sql parser improved window function support, fix #4059

This commit is contained in:
高铁
2020-12-12 20:09:33 +08:00
parent ae675fec72
commit 031fede035
7 changed files with 72 additions and 8 deletions
@@ -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)) {
@@ -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