[PostgreSQL] Over clause support

This commit is contained in:
aboyko
2024-10-09 22:27:35 -04:00
parent d2608475f6
commit ec8b9ea019
5 changed files with 9606 additions and 8609 deletions

View File

@@ -1384,15 +1384,29 @@ frame_clause
: (RANGE | ROWS) frame_start
| (RANGE | ROWS) BETWEEN frame_start AND frame_end
;
window_definition_list
: window_definition (COMMA window_definition)*
;
window_definition
: window_name
| PARTITION BY expr (COMMA expr)*
| order_by_clause
: window_name AS window_specification
;
window_clause
: WINDOW window_name AS OPEN_PAREN window_definition CLOSE_PAREN
: WINDOW window_definition_list
;
window_specification
: OPEN_PAREN window_name? partition_clause? order_by_clause? frame_clause? CLOSE_PAREN
;
partition_clause
: PARTITION BY expr (COMMA expr)*
;
over_clause
: OVER (window_specification | window_name)
;
combine_clause
@@ -1482,7 +1496,7 @@ expr
| expr op=IS (bool_expr | NULL | NOT NULL)
| expr IS NOT? DISTINCT FROM expr
| op=(NOT | ALL ) expr
| func_call
| func_call over_clause?
| identifier
| CAST OPEN_PAREN expr AS data_type CLOSE_PAREN
| correlation_name DOT column_name

View File

@@ -2460,6 +2460,18 @@ public class PostgreSqlParserBaseListener implements PostgreSqlParserListener {
* <p>The default implementation does nothing.</p>
*/
@Override public void exitFrame_clause(PostgreSqlParser.Frame_clauseContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterWindow_definition_list(PostgreSqlParser.Window_definition_listContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitWindow_definition_list(PostgreSqlParser.Window_definition_listContext ctx) { }
/**
* {@inheritDoc}
*
@@ -2484,6 +2496,42 @@ public class PostgreSqlParserBaseListener implements PostgreSqlParserListener {
* <p>The default implementation does nothing.</p>
*/
@Override public void exitWindow_clause(PostgreSqlParser.Window_clauseContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterWindow_specification(PostgreSqlParser.Window_specificationContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitWindow_specification(PostgreSqlParser.Window_specificationContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterPartition_clause(PostgreSqlParser.Partition_clauseContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitPartition_clause(PostgreSqlParser.Partition_clauseContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterOver_clause(PostgreSqlParser.Over_clauseContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitOver_clause(PostgreSqlParser.Over_clauseContext ctx) { }
/**
* {@inheritDoc}
*

View File

@@ -2047,6 +2047,16 @@ public interface PostgreSqlParserListener extends ParseTreeListener {
* @param ctx the parse tree
*/
void exitFrame_clause(PostgreSqlParser.Frame_clauseContext ctx);
/**
* Enter a parse tree produced by {@link PostgreSqlParser#window_definition_list}.
* @param ctx the parse tree
*/
void enterWindow_definition_list(PostgreSqlParser.Window_definition_listContext ctx);
/**
* Exit a parse tree produced by {@link PostgreSqlParser#window_definition_list}.
* @param ctx the parse tree
*/
void exitWindow_definition_list(PostgreSqlParser.Window_definition_listContext ctx);
/**
* Enter a parse tree produced by {@link PostgreSqlParser#window_definition}.
* @param ctx the parse tree
@@ -2067,6 +2077,36 @@ public interface PostgreSqlParserListener extends ParseTreeListener {
* @param ctx the parse tree
*/
void exitWindow_clause(PostgreSqlParser.Window_clauseContext ctx);
/**
* Enter a parse tree produced by {@link PostgreSqlParser#window_specification}.
* @param ctx the parse tree
*/
void enterWindow_specification(PostgreSqlParser.Window_specificationContext ctx);
/**
* Exit a parse tree produced by {@link PostgreSqlParser#window_specification}.
* @param ctx the parse tree
*/
void exitWindow_specification(PostgreSqlParser.Window_specificationContext ctx);
/**
* Enter a parse tree produced by {@link PostgreSqlParser#partition_clause}.
* @param ctx the parse tree
*/
void enterPartition_clause(PostgreSqlParser.Partition_clauseContext ctx);
/**
* Exit a parse tree produced by {@link PostgreSqlParser#partition_clause}.
* @param ctx the parse tree
*/
void exitPartition_clause(PostgreSqlParser.Partition_clauseContext ctx);
/**
* Enter a parse tree produced by {@link PostgreSqlParser#over_clause}.
* @param ctx the parse tree
*/
void enterOver_clause(PostgreSqlParser.Over_clauseContext ctx);
/**
* Exit a parse tree produced by {@link PostgreSqlParser#over_clause}.
* @param ctx the parse tree
*/
void exitOver_clause(PostgreSqlParser.Over_clauseContext ctx);
/**
* Enter a parse tree produced by {@link PostgreSqlParser#combine_clause}.
* @param ctx the parse tree

View File

@@ -208,4 +208,81 @@ public class PostgreSqlSemanticTokensTest {
assertThat(tokens.get(9)).isEqualTo(new SemanticTokenData(53, 54, "operator", new String[0]));
assertThat(tokens.get(10)).isEqualTo(new SemanticTokenData(54, 55, "parameter", new String[0]));
}
@Test
void over_clause_1() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM empsalary;\n"
+ "", 0);
assertThat(tokens.size()).isEqualTo(20);
}
@Test
void over_clause_2() {
List<SemanticTokenData> tokens = provider.computeTokens("""
SELECT depname, empno, salary,
rank() OVER (PARTITION BY depname ORDER BY salary DESC)
FROM empsalary;
""", 0);
assertThat(tokens.size()).isEqualTo(23);
}
@Test
void over_clause_3() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT salary, sum(salary) OVER () FROM empsalary;"
+ "", 0);
assertThat(tokens.size()).isEqualTo(13);
}
@Test
void over_clause_4() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT salary, sum(salary) OVER (ORDER BY salary) FROM empsalary;"
+ "", 0);
assertThat(tokens.size()).isEqualTo(16);
}
@Test
void over_clause_5() {
List<SemanticTokenData> tokens = provider.computeTokens("""
SELECT depname, empno, salary, enroll_date
FROM
(SELECT depname, empno, salary, enroll_date,
rank() OVER (PARTITION BY depname ORDER BY salary DESC, empno) AS pos
FROM empsalary
) AS ss
WHERE pos < 3;
""", 0);
assertThat(tokens.size()).isEqualTo(46);
}
@Test
void over_clause_6() {
List<SemanticTokenData> tokens = provider.computeTokens("""
SELECT sum(salary) OVER w, avg(salary) OVER w
FROM empsalary
WINDOW w AS (PARTITION BY depname ORDER BY salary DESC);
""", 0);
assertThat(tokens.size()).isEqualTo(29);
}
@Test
void over_clause_7() {
List<SemanticTokenData> tokens = provider.computeTokens("""
WITH cte AS (
SELECT
q.*,
ROW_NUMBER() OVER (PARTITION BY q.database_id ORDER BY q.order_id) AS rn
FROM
SAMPLE_TABLE AS q
WHERE
q.status IN (0, 1, 5, 10)
)
SELECT *
FROM cte
WHERE
(rn = 1 OR status = 10)
AND (scenario = 11 OR scenario = 8)
ORDER BY status DESC
""", 0);
assertThat(tokens.size()).isEqualTo(74);
}
}