mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
sql parser improved window function support, fix #4059
This commit is contained in:
@@ -3886,4 +3886,8 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
|
||||
public void setCheckExecuteTime(boolean checkExecuteTime) {
|
||||
this.checkExecuteTime = checkExecuteTime;
|
||||
}
|
||||
|
||||
public void forEach(Connection conn) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
+19
-1
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<SQLStatement> 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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user