mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
Oracle支持GroupingSets Clause
git-svn-id: http://code.alibabatech.com/svn/druid/trunk@155 b9813039-fb51-4c41-a8b9-e21c2acb5095
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
package com.alibaba.druid.sql.ast.expr;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.SQLExprImpl;
|
||||
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
|
||||
|
||||
public class SQLListExpr extends SQLExprImpl {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final List<SQLExpr> items = new ArrayList<SQLExpr>();
|
||||
|
||||
public List<SQLExpr> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void accept0(SQLASTVisitor visitor) {
|
||||
if (visitor.visit(this)) {
|
||||
acceptChild(visitor, items);
|
||||
}
|
||||
visitor.endVisit(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.alibaba.druid.sql.dialect.oracle.ast.clause;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.SQLExprImpl;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.visitor.OracleASTVisitor;
|
||||
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
|
||||
|
||||
public class GroupingSetExpr extends SQLExprImpl {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final List<SQLExpr> parameters = new ArrayList<SQLExpr>();
|
||||
|
||||
public List<SQLExpr> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void accept0(SQLASTVisitor visitor) {
|
||||
accept0((OracleASTVisitor) visitor);
|
||||
}
|
||||
|
||||
protected void accept0(OracleASTVisitor visitor) {
|
||||
if (visitor.visit(this)) {
|
||||
acceptChild(visitor, parameters);
|
||||
}
|
||||
visitor.endVisit(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import com.alibaba.druid.sql.dialect.oracle.ast.OracleHint;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.OracleOrderBy;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.clause.FlashbackQueryClause.AsOfFlashbackQueryClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.clause.FlashbackQueryClause.VersionsFlashbackQueryClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.clause.GroupingSetExpr;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.clause.PartitionExtensionClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.clause.SampleClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleAggregateExpr;
|
||||
@@ -328,4 +329,8 @@ public interface OracleASTVisitor extends SQLASTVisitor {
|
||||
boolean visit(AsOfFlashbackQueryClause x);
|
||||
|
||||
void endVisit(AsOfFlashbackQueryClause x);
|
||||
|
||||
boolean visit(GroupingSetExpr x);
|
||||
|
||||
void endVisit(GroupingSetExpr x);
|
||||
}
|
||||
|
||||
+15
@@ -33,6 +33,7 @@ import com.alibaba.druid.sql.dialect.oracle.ast.OracleHint;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.OracleOrderBy;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.clause.FlashbackQueryClause.AsOfFlashbackQueryClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.clause.FlashbackQueryClause.VersionsFlashbackQueryClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.clause.GroupingSetExpr;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.clause.PartitionExtensionClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.clause.SampleClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleAggregateExpr;
|
||||
@@ -1560,5 +1561,19 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS
|
||||
public void endVisit(AsOfFlashbackQueryClause x) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(GroupingSetExpr x) {
|
||||
print("GROUPING SETS");
|
||||
print(" (");
|
||||
printAndAccept(x.getParameters(), ", ");
|
||||
print(")");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(GroupingSetExpr x) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.alibaba.druid.sql.ast.statement.SQLUnionQuery;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.OracleHint;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.clause.FlashbackQueryClause.AsOfFlashbackQueryClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.clause.FlashbackQueryClause.VersionsFlashbackQueryClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.clause.GroupingSetExpr;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.clause.PartitionExtensionClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.clause.SampleClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleAggregateExpr;
|
||||
@@ -56,7 +57,7 @@ public class OracleSelectParser extends SQLSelectParser {
|
||||
public OracleSelectParser(Lexer lexer){
|
||||
super(lexer);
|
||||
}
|
||||
|
||||
|
||||
protected SQLExprParser createExprParser() {
|
||||
return new OracleExprParser(lexer);
|
||||
}
|
||||
@@ -199,9 +200,23 @@ public class OracleSelectParser extends SQLSelectParser {
|
||||
accept(Token.BY);
|
||||
|
||||
SQLSelectGroupByClause groupBy = new SQLSelectGroupByClause();
|
||||
while (true) {
|
||||
groupBy.getItems().add(this.createExprParser().expr());
|
||||
if (!(lexer.token() == (Token.COMMA))) break;
|
||||
for (;;) {
|
||||
if (identifierEquals("GROUPING")) {
|
||||
GroupingSetExpr groupingSet = new GroupingSetExpr();
|
||||
lexer.nextToken();
|
||||
acceptIdentifier("SETS");
|
||||
accept(Token.LPAREN);
|
||||
createExprParser().exprList(groupingSet.getParameters());
|
||||
accept(Token.RPAREN);
|
||||
groupBy.getItems().add(groupingSet);
|
||||
} else {
|
||||
groupBy.getItems().add(this.createExprParser().expr());
|
||||
}
|
||||
|
||||
if (!(lexer.token() == (Token.COMMA))) {
|
||||
break;
|
||||
}
|
||||
|
||||
lexer.nextToken();
|
||||
}
|
||||
|
||||
@@ -246,8 +261,7 @@ public class OracleSelectParser extends SQLSelectParser {
|
||||
|
||||
lexer.nextToken();
|
||||
accept(Token.BY);
|
||||
|
||||
|
||||
|
||||
if (lexer.token() == Token.PRIOR) {
|
||||
lexer.nextToken();
|
||||
hierachical.setPrior(true);
|
||||
@@ -301,40 +315,40 @@ public class OracleSelectParser extends SQLSelectParser {
|
||||
|
||||
private void parseTableSourceQueryTableExpr(OracleSelectTableReference tableReference) {
|
||||
tableReference.setExpr(this.createExprParser().expr());
|
||||
|
||||
|
||||
if (identifierEquals("SAMPLE")) {
|
||||
lexer.nextToken();
|
||||
|
||||
|
||||
SampleClause sample = new SampleClause();
|
||||
|
||||
|
||||
if (identifierEquals("BLOCK")) {
|
||||
sample.setBlock(true);
|
||||
}
|
||||
|
||||
|
||||
accept(Token.LPAREN);
|
||||
|
||||
|
||||
if (lexer.token() != Token.LITERAL_INT) {
|
||||
throw new ParserException("syntax error : " + lexer.token());
|
||||
}
|
||||
sample.setPercent(lexer.integerValue().intValue());
|
||||
lexer.nextToken();
|
||||
|
||||
|
||||
accept(Token.RPAREN);
|
||||
|
||||
|
||||
if (identifierEquals("SEED")) {
|
||||
lexer.nextToken();
|
||||
accept(Token.LPAREN);
|
||||
sample.setSeedValue(expr());
|
||||
accept(Token.RPAREN);
|
||||
}
|
||||
|
||||
|
||||
tableReference.setSampleClause(sample);
|
||||
}
|
||||
|
||||
if (identifierEquals("PARTITION")) {
|
||||
lexer.nextToken();
|
||||
PartitionExtensionClause partition = new PartitionExtensionClause();
|
||||
|
||||
|
||||
if (lexer.token() == Token.LPAREN) {
|
||||
lexer.nextToken();
|
||||
partition.setPartition(createExprParser().name());
|
||||
@@ -345,15 +359,15 @@ public class OracleSelectParser extends SQLSelectParser {
|
||||
createExprParser().names(partition.getFor());
|
||||
accept(Token.RPAREN);
|
||||
}
|
||||
|
||||
|
||||
tableReference.setPartition(partition);
|
||||
}
|
||||
|
||||
|
||||
if (identifierEquals("SUBPARTITION")) {
|
||||
lexer.nextToken();
|
||||
PartitionExtensionClause partition = new PartitionExtensionClause();
|
||||
partition.setSubPartition(true);
|
||||
|
||||
|
||||
if (lexer.token() == Token.LPAREN) {
|
||||
lexer.nextToken();
|
||||
partition.setPartition(createExprParser().name());
|
||||
@@ -364,16 +378,16 @@ public class OracleSelectParser extends SQLSelectParser {
|
||||
createExprParser().names(partition.getFor());
|
||||
accept(Token.RPAREN);
|
||||
}
|
||||
|
||||
|
||||
tableReference.setPartition(partition);
|
||||
}
|
||||
|
||||
|
||||
if (lexer.token() == Token.AS) {
|
||||
lexer.nextToken();
|
||||
|
||||
|
||||
if (identifierEquals("OF")) {
|
||||
lexer.nextToken();
|
||||
|
||||
|
||||
AsOfFlashbackQueryClause clause = new AsOfFlashbackQueryClause();
|
||||
if (identifierEquals("SCN")) {
|
||||
clause.setType(AsOfFlashbackQueryClause.Type.SCN);
|
||||
@@ -383,17 +397,17 @@ public class OracleSelectParser extends SQLSelectParser {
|
||||
clause.setType(AsOfFlashbackQueryClause.Type.TIMESTAMP);
|
||||
}
|
||||
clause.setExpr(createExprParser().primary());
|
||||
|
||||
|
||||
tableReference.setFlashback(clause);
|
||||
} else {
|
||||
throw new SQLParseException("TODO");
|
||||
}
|
||||
} else if (identifierEquals("VERSIONS")) {
|
||||
lexer.nextToken();
|
||||
|
||||
|
||||
if (lexer.token() == Token.BETWEEN) {
|
||||
lexer.nextToken();
|
||||
|
||||
|
||||
VersionsFlashbackQueryClause clause = new VersionsFlashbackQueryClause();
|
||||
if (identifierEquals("SCN")) {
|
||||
clause.setType(AsOfFlashbackQueryClause.Type.SCN);
|
||||
@@ -402,21 +416,21 @@ public class OracleSelectParser extends SQLSelectParser {
|
||||
acceptIdentifier("TIMESTAMP");
|
||||
clause.setType(AsOfFlashbackQueryClause.Type.TIMESTAMP);
|
||||
}
|
||||
|
||||
|
||||
SQLBinaryOpExpr binaryExpr = (SQLBinaryOpExpr) createExprParser().expr();
|
||||
if (binaryExpr.getOperator() != SQLBinaryOperator.BooleanAnd) {
|
||||
throw new SQLParseException("syntax error : " + binaryExpr.getOperator());
|
||||
}
|
||||
|
||||
|
||||
clause.setBegin(binaryExpr.getLeft());
|
||||
clause.setEnd(binaryExpr.getRight());
|
||||
|
||||
|
||||
tableReference.setFlashback(clause);
|
||||
} else {
|
||||
throw new SQLParseException("TODO");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected SQLTableSource parseTableSourceRest(SQLTableSource tableSource) {
|
||||
@@ -465,7 +479,7 @@ public class OracleSelectParser extends SQLSelectParser {
|
||||
lexer.nextToken();
|
||||
joinType = OracleSelectJoin.JoinType.JOIN;
|
||||
}
|
||||
|
||||
|
||||
if (lexer.token() == (Token.COMMA)) {
|
||||
lexer.nextToken();
|
||||
joinType = OracleSelectJoin.JoinType.COMMA;
|
||||
@@ -489,7 +503,7 @@ public class OracleSelectParser extends SQLSelectParser {
|
||||
|
||||
return join;
|
||||
}
|
||||
|
||||
|
||||
return tableSource;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLInListExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLInSubQueryExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLListExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLNCharExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLNotExpr;
|
||||
@@ -148,6 +149,16 @@ public class SQLExprParser extends SQLParser {
|
||||
case LPAREN:
|
||||
lexer.nextToken();
|
||||
sqlExpr = expr();
|
||||
if (lexer.token() == Token.COMMA) {
|
||||
SQLListExpr listExpr = new SQLListExpr();
|
||||
listExpr.getItems().add(sqlExpr);
|
||||
do {
|
||||
lexer.nextToken();
|
||||
listExpr.getItems().add(expr());
|
||||
} while (lexer.token() == Token.COMMA);
|
||||
|
||||
sqlExpr = listExpr;
|
||||
}
|
||||
accept(Token.RPAREN);
|
||||
break;
|
||||
case INSERT:
|
||||
|
||||
@@ -40,6 +40,7 @@ import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLInListExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLInSubQueryExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLListExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLNCharExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLNotExpr;
|
||||
@@ -808,4 +809,13 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(SQLListExpr x) {
|
||||
print("(");
|
||||
printAndAccept(x.getItems(), ", ");
|
||||
print(")");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.alibaba.druid.sql.ast.expr.SQLInListExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLInSubQueryExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLIntervalLiteralExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLListExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLNCharExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLNotExpr;
|
||||
@@ -319,4 +320,8 @@ public interface SQLASTVisitor {
|
||||
void endVisit(SQLInSubQueryExpr x);
|
||||
|
||||
boolean visit(SQLInSubQueryExpr x);
|
||||
|
||||
void endVisit(SQLListExpr x);
|
||||
|
||||
boolean visit(SQLListExpr x);
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.alibaba.druid.sql.ast.expr.SQLInListExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLInSubQueryExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLIntervalLiteralExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLListExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLNCharExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLNotExpr;
|
||||
@@ -541,4 +542,14 @@ public class SQLASTVisitorAdapter implements SQLASTVisitor {
|
||||
public boolean visit(SQLInSubQueryExpr x) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(SQLListExpr x) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(SQLListExpr x) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,10 @@ public class OracleSQLParserResourceTest extends TestCase {
|
||||
// exec_test("bvt/parser/oracle-8.txt");
|
||||
// exec_test("bvt/parser/oracle-9.txt");
|
||||
// exec_test("bvt/parser/oracle-10.txt");
|
||||
exec_test("bvt/parser/oracle-11.txt");
|
||||
// exec_test("bvt/parser/oracle-11.txt");
|
||||
// exec_test("bvt/parser/oracle-12.txt");
|
||||
// exec_test("bvt/parser/oracle-13.txt");
|
||||
exec_test("bvt/parser/oracle-14.txt");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
SELECT department_id, MIN(salary), MAX (salary)
|
||||
FROM employees
|
||||
GROUP BY department_id
|
||||
ORDER BY department_id;
|
||||
---------------------------
|
||||
SELECT department_id, MIN(salary), MAX(salary)
|
||||
FROM employees
|
||||
GROUP BY department_id
|
||||
ORDER BY department_id;
|
||||
@@ -0,0 +1,15 @@
|
||||
SELECT DECODE(GROUPING(department_name), 1, 'All Departments',
|
||||
department_name) AS department_name,
|
||||
DECODE(GROUPING(job_id), 1, 'All Jobs', job_id) AS job_id,
|
||||
COUNT(*) "Total Empl", AVG(salary) * 12 "Average Sal"
|
||||
FROM employees e, departments d
|
||||
WHERE d.department_id = e.department_id
|
||||
GROUP BY CUBE (department_name, job_id)
|
||||
ORDER BY department_name, job_id;
|
||||
---------------------------
|
||||
SELECT DECODE(GROUPING(department_name), 1, 'All Departments', department_name) AS department_name, DECODE(GROUPING(job_id), 1, 'All Jobs', job_id) AS job_id, COUNT(*) AS COUNT, AVG(salary) * 12 AS salary
|
||||
FROM employees e , departments d
|
||||
WHERE d.department_id = e.department_id
|
||||
GROUP BY CUBE(department_name, job_id)
|
||||
ORDER BY department_name, job_id;
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
SELECT channel_desc, calendar_month_desc, co.country_id,
|
||||
TO_CHAR(sum(amount_sold) , '9,999,999,999') SALES$
|
||||
FROM sales, customers, times, channels, countries co
|
||||
WHERE sales.time_id=times.time_id
|
||||
AND sales.cust_id=customers.cust_id
|
||||
AND sales.channel_id= channels.channel_id
|
||||
AND customers.country_id = co.country_id
|
||||
AND channels.channel_desc IN ('Direct Sales', 'Internet')
|
||||
AND times.calendar_month_desc IN ('2000-09', '2000-10')
|
||||
AND co.country_iso_code IN ('UK', 'US')
|
||||
GROUP BY GROUPING SETS(
|
||||
(channel_desc, calendar_month_desc, co.country_id),
|
||||
(channel_desc, co.country_id),
|
||||
(calendar_month_desc, co.country_id) );
|
||||
---------------------------
|
||||
SELECT channel_desc, calendar_month_desc, co.country_id, TO_CHAR(sum(amount_sold), '9,999,999,999') AS SALES$
|
||||
FROM sales , customers , times , channels , countries co
|
||||
WHERE sales.time_id = times.time_id AND (sales.cust_id = customers.cust_id AND (sales.channel_id = channels.channel_id AND (customers.country_id = co.country_id AND (channels.channel_desc IN ('Direct Sales', 'Internet') AND (times.calendar_month_desc IN ('2000-09', '2000-10') AND co.country_iso_code IN ('UK', 'US'))))))
|
||||
GROUP BY GROUPING SETS ((channel_desc, calendar_month_desc, co.country_id), (channel_desc, co.country_id), (calendar_month_desc, co.country_id));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user