diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index 53658c3e58..c1546e3b46 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -3886,4 +3886,8 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat public void setCheckExecuteTime(boolean checkExecuteTime) { this.checkExecuteTime = checkExecuteTime; } + + public void forEach(Connection conn) { + + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/expr/OracleAnalytic.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/expr/OracleAnalytic.java index 288a66e49a..32b9d2623d 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/expr/OracleAnalytic.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/expr/OracleAnalytic.java @@ -77,8 +77,11 @@ public class OracleAnalytic extends SQLOver implements SQLReplaceable, OracleExp return x; } - public void setWindowing(OracleAnalyticWindowing windowing) { - this.windowing = windowing; + public void setWindowing(OracleAnalyticWindowing x) { + if (x != null) { + x.setParent(this); + } + this.windowing = x; } public SQLDataType computeDataType() { diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleExprParser.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleExprParser.java index 7593fb0a4e..26eef11bb9 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleExprParser.java @@ -899,6 +899,11 @@ public class OracleExprParser extends SQLExprParser { beginExpr = relational(); } + final SQLOver.WindowingBound beginBound = parseWindowingBound(); + if (beginBound != null) { + over.setWindowingBetweenBeginBound(beginBound); + } + accept(Token.AND); SQLExpr endExpr; if (lexer.identifierEquals(FnvHash.Constants.CURRENT)) { diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java index 2310b78b34..b0f68e271e 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java @@ -109,7 +109,25 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS public boolean visit(OracleAnalyticWindowing x) { print0(x.getType().name().toUpperCase()); print(' '); - x.getExpr().accept(this); + + SQLExpr expr = x.getExpr(); + + if (expr instanceof SQLBetweenExpr && x.getParent() instanceof SQLOver) { + SQLOver over = (SQLOver) x.getParent(); + SQLBetweenExpr betweenExpr = (SQLBetweenExpr) expr; + SQLOver.WindowingBound beginBound = over.getWindowingBetweenBeginBound(); + if (beginBound != null) { + betweenExpr.getBeginExpr().accept(this); + print(' '); + print0(ucase ? beginBound.name : beginBound.name_lower); + print0(ucase ? " AND " : " and "); + betweenExpr.getEndExpr().accept(this); + return false; + } + } + + expr.accept(this); + return false; } diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java index 7a141d21b2..7e39babb44 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -2299,7 +2299,7 @@ public class SQLExprParser extends SQLParser { accept(Token.RPAREN); } - private SQLOver.WindowingBound parseWindowingBound() { + protected SQLOver.WindowingBound parseWindowingBound() { if (lexer.identifierEquals(FnvHash.Constants.PRECEDING)) { lexer.nextToken(); return SQLOver.WindowingBound.PRECEDING; diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleSQLParserResourceTest.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleSQLParserResourceTest.java index 5df03108a6..07daf162bc 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleSQLParserResourceTest.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleSQLParserResourceTest.java @@ -39,6 +39,10 @@ public class OracleSQLParserResourceTest extends TestCase { exec_test("bvt/parser/oracle-55.txt"); } + public void test_59() throws Exception { + exec_test("bvt/parser/oracle-59.txt"); + } + public void exec_test(String resource) throws Exception { System.out.println(resource); InputStream is = null; @@ -49,17 +53,26 @@ public class OracleSQLParserResourceTest extends TestCase { JdbcUtils.close(reader); String[] items = input.split("---------------------------"); String sql = items[0].trim(); - String expect = items[1].trim(); + String expect = null; + if (items.length > 1) { + expect = items[1]; + if (expect != null) { + expect = expect.trim(); + expect = expect.replaceAll("\\r\\n", "\n"); + } + } OracleStatementParser parser = new OracleStatementParser(sql); List statementList = parser.parseStatementList(); - Assert.assertEquals(1, statementList.size()); + assertEquals(1, statementList.size()); String text = TestUtils.outputOracle(statementList); - expect = expect.replaceAll("\\r\\n", "\n"); + System.out.println(text); - Assert.assertEquals(expect, text.trim()); + if (expect != null && !expect.isEmpty()) { + Assert.assertEquals(expect, text.trim()); + } } } diff --git a/src/test/resources/bvt/parser/oracle-59.txt b/src/test/resources/bvt/parser/oracle-59.txt new file mode 100644 index 0000000000..a8d083214e --- /dev/null +++ b/src/test/resources/bvt/parser/oracle-59.txt @@ -0,0 +1,21 @@ +SELECT B.CUSTOMER_ID customerId,B.CN_NAME NAME + , OPENING_DATE,CLOSING_DATE + , count(A.OPENING_DATE) + over (partition BY B.CUSTOMER_ID + ORDER BY trunc(A.OPENING_DATE,'mm') + RANGE BETWEEN interval '3' month (4) preceding AND CURRENT ROW + ) AS createCount + , count(A.CLOSING_DATE) + over (partition BY B.CUSTOMER_ID + ORDER BY trunc(NVL(A.CLOSING_DATE,SYSDATE),'mm') + RANGE BETWEEN interval '3' month (4) preceding AND CURRENT ROW) AS cancelCount + ,row_number () + over (partition BY B.CUSTOMER_ID ORDER BY trunc(A.OPENING_DATE) DESC) AS row_flg +FROM account_info A,CUSTOMER_INFO B WHERE A.CUSTOMER_ID=B.CUSTOMER_ID +--------------------------- +SELECT B.CUSTOMER_ID AS customerId, B.CN_NAME AS NAME, OPENING_DATE, CLOSING_DATE + , count(A.OPENING_DATE) OVER (PARTITION BY B.CUSTOMER_ID ORDER BY trunc(A.OPENING_DATE, 'mm') RANGE INTERVAL '3' MONTH(4) PRECEDING AND CURRENT ROW) AS createCount + , count(A.CLOSING_DATE) OVER (PARTITION BY B.CUSTOMER_ID ORDER BY trunc(NVL(A.CLOSING_DATE, SYSDATE), 'mm') RANGE INTERVAL '3' MONTH(4) PRECEDING AND CURRENT ROW) AS cancelCount + , row_number() OVER (PARTITION BY B.CUSTOMER_ID ORDER BY trunc(A.OPENING_DATE) DESC) AS row_flg +FROM account_info A, CUSTOMER_INFO B +WHERE A.CUSTOMER_ID = B.CUSTOMER_ID \ No newline at end of file