Skip to content

Commit

Permalink
feat: RedShift specific Window function IGNORE | RESPECT NULLS
Browse files Browse the repository at this point in the history
Signed-off-by: Andreas Reichel <andreas@manticore-projects.com>
  • Loading branch information
manticore-projects committed Apr 20, 2024
1 parent 13e61a7 commit 321c880
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 9 deletions.
14 changes: 11 additions & 3 deletions src/main/java/net/sf/jsqlparser/expression/AnalyticExpression.java
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ public String toString() {
havingClause.appendTo(b);
}

if (nullHandling != null) {
if (nullHandling != null && !ignoreNullsOutside) {
switch (nullHandling) {
case IGNORE_NULLS:
b.append(" IGNORE NULLS");
Expand All @@ -287,6 +287,7 @@ public String toString() {
break;
}
}

if (funcOrderBy != null) {
b.append(" ORDER BY ");
b.append(funcOrderBy.stream().map(OrderByElement::toString).collect(joining(", ")));
Expand All @@ -310,8 +311,15 @@ public String toString() {
}
}

if (isIgnoreNullsOutside()) {
b.append("IGNORE NULLS ");
if (nullHandling != null && ignoreNullsOutside) {
switch (nullHandling) {
case IGNORE_NULLS:
b.append(" IGNORE NULLS ");
break;
case RESPECT_NULLS:
b.append(" RESPECT NULLS ");
break;
}
}

switch (type) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -823,7 +823,7 @@ public void visit(AnalyticExpression aexpr) {
havingClause.getExpression().accept(this);
}

if (aexpr.getNullHandling() != null) {
if (aexpr.getNullHandling() != null && !aexpr.isIgnoreNullsOutside()) {
switch (aexpr.getNullHandling()) {
case IGNORE_NULLS:
buffer.append(" IGNORE NULLS");
Expand Down Expand Up @@ -858,8 +858,15 @@ public void visit(AnalyticExpression aexpr) {
}
}

if (aexpr.isIgnoreNullsOutside()) {
buffer.append("IGNORE NULLS ");
if (aexpr.getNullHandling() != null && aexpr.isIgnoreNullsOutside()) {
switch (aexpr.getNullHandling()) {
case IGNORE_NULLS:
buffer.append(" IGNORE NULLS ");
break;
case RESPECT_NULLS:
buffer.append(" RESPECT NULLS ");
break;
}
}

switch (aexpr.getType()) {
Expand Down
15 changes: 14 additions & 1 deletion src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,14 @@ import net.sf.jsqlparser.statement.grant.*;
import java.util.*;
import java.util.AbstractMap.SimpleEntry;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
* The parser generated by JavaCC
*/
public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
public final static Logger LOGGER = Logger.getLogger(CCJSqlParser.class.getName());
public int bracketsCounter = 0;
public int caseCounter = 0;
public boolean interrupted = false;
Expand Down Expand Up @@ -5050,7 +5054,16 @@ void windowFun(AnalyticExpression retval):{
WindowDefinition winDef;
} {
(
[<K_IGNORE> <K_NULLS> { retval.setIgnoreNullsOutside(true); } ]
[
(
<K_IGNORE> <K_NULLS> { retval.setNullHandling(Function.NullHandling.IGNORE_NULLS); retval.setIgnoreNullsOutside(true); }
)
|
(
<K_RESPECT> <K_NULLS> { retval.setNullHandling(Function.NullHandling.RESPECT_NULLS); retval.setIgnoreNullsOutside(true); }
)
]

<K_OVER> {retval.setType(AnalyticType.OVER);}
|
<K_WITHIN> <K_GROUP> {retval.setType(AnalyticType.WITHIN_GROUP);}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,23 @@ public class WindowFunctionTest {
public void testListAggOverIssue1652() throws JSQLParserException {
String sqlString =
"SELECT\n" +
" LISTAGG (d.COL_TO_AGG, ' / ') WITHIN GROUP (ORDER BY d.COL_TO_AGG) OVER (PARTITION BY d.PART_COL) AS MY_LISTAGG\n" +
"FROM cte_dummy_data d";
" LISTAGG (d.COL_TO_AGG, ' / ') WITHIN GROUP (ORDER BY d.COL_TO_AGG) OVER (PARTITION BY d.PART_COL) AS MY_LISTAGG\n"
+
"FROM cte_dummy_data d";

TestUtils.assertSqlCanBeParsedAndDeparsed(sqlString, true);
}

@Test
public void RedshiftRespectIgnoreNulls() throws JSQLParserException {
String sqlString =
"select venuestate, venueseats, venuename,\n"
+ "first_value(venuename) ignore nulls\n"
+ "over(partition by venuestate\n"
+ "order by venueseats desc\n"
+ "rows between unbounded preceding and unbounded following) AS first\n"
+ "from (select * from venue where venuestate='CA')\n"
+ "order by venuestate;";

TestUtils.assertSqlCanBeParsedAndDeparsed(sqlString, true);
}
Expand Down

0 comments on commit 321c880

Please sign in to comment.