[plsql] Support WithinClause for LISTAGG function (and similar)

This commit is contained in:
Andreas Dangel
2019-02-13 19:53:31 +01:00
parent d56bdc1c84
commit 892b53dc6f
4 changed files with 41 additions and 5 deletions

View File

@ -1561,6 +1561,19 @@ ASTWindowingClause WindowingClause() :
{ return jjtThis; }
}
/**
* Within Clause is used for the following analytic functions: CUME_DIST, DENSE_RANK, LISTAGG, PERCENT_RANK, PERCENTILE_CONT,
* PERCENTILE_DISC, RANK.
*
* See e.g. https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/LISTAGG.html
*/
ASTWithinClause WithinClause() :
{}
{
"WITHIN" <GROUP> "(" OrderByClause() ")" [ LOOKAHEAD(2) "OVER" "(" QueryPartitionClause() ")" ]
{ return jjtThis; }
}
ASTColumn Column() :
{ ASTID id; }
{
@ -2950,8 +2963,8 @@ ASTPrimaryPrefix PrimaryPrefix() :
}
{
(
// Note: AnalyticClause is only allowed for specific functions, but this grammar allows it for all functions.
LOOKAHEAD(FunctionName() "(") simpleNode = FunctionCall() [ AnalyticClause() ]
// Note: AnalyticClause and WithinClause are only allowed for specific functions, but this grammar allows it for all functions.
LOOKAHEAD(FunctionName() "(") simpleNode = FunctionCall() [ AnalyticClause() ] [ WithinClause() ]
| LOOKAHEAD(Literal()) simpleNode = Literal() { sb.append(simpleNode.getImage()) ; }
| LOOKAHEAD(MultiSetCondition()) simpleNode = MultiSetCondition()
| LOOKAHEAD(TrimExpression()) simpleNode = TrimExpression() //SRT 20110613.3
@ -4810,7 +4823,7 @@ ASTKEYWORD_UNRESERVED KEYWORD_UNRESERVED (): {}
{
// PL/SQL UNRESERVED KEYWORDS - V$RESERVED.RESERVED='N'
(
"FIRST" | "REPLACE" | "REF" | "LAST" | "TRIM" | "OVER" | "UNBOUNDED" | "PRECEDING" | "FOLLOWING" |
"FIRST" | "REPLACE" | "REF" | "LAST" | "TRIM" | "OVER" | "UNBOUNDED" | "PRECEDING" | "FOLLOWING" | "WITHIN" |
<FALSE>
| <TRUE>
| <A>
@ -5974,7 +5987,6 @@ ASTID ID(): {}
// <COMMIT> | <FUNCTION> | // this causes bug 643043 Procedure w/o params appears as variable
| <GOTO> //SYNTAX
//| <GROUP> //RESERVED WORD
| <HAVING> //RESERVED WORD
//20120501 | <HEAP>
| <IF> //SYNTAX
@ -6221,7 +6233,6 @@ ASTQualifiedID QualifiedID(): {}
//<FROM>
//| <FUNCTION>
//<GOTO>
//<GROUP>
//<HAVING>
//20120501 | <HEAP>
//<IF>

View File

@ -1036,4 +1036,9 @@ public class PLSQLParserVisitorAdapter implements PLSQLParserVisitor {
public Object visit(ASTWindowingClause node, Object data) {
return visit((PLSQLNode) node, data);
}
@Override
public Object visit(ASTWithinClause node, Object data) {
return visit((PLSQLNode) node, data);
}
}

View File

@ -1130,6 +1130,11 @@ public abstract class AbstractPLSQLRule extends AbstractRule implements PLSQLPar
return visit((PLSQLNode) node, data);
}
@Override
public Object visit(ASTWithinClause node, Object data) {
return visit((PLSQLNode) node, data);
}
/*
* Treat all Executable Code
*/

View File

@ -25,5 +25,20 @@ SELECT manager_id, last_name, hire_date, salary,
FROM employees
ORDER BY manager_id, hire_date, salary;
-- Example from: https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/LISTAGG.html
SELECT LISTAGG(last_name, '; ')
WITHIN GROUP (ORDER BY hire_date, last_name) "Emp_list",
MIN(hire_date) "Earliest"
INTO some_record
FROM employees
WHERE department_id = 30;
SELECT department_id "Dept.",
LISTAGG(last_name, '; ') WITHIN GROUP (ORDER BY hire_date) "Employees"
INTO some_record
FROM employees
GROUP BY department_id
ORDER BY department_id;
END;
/