Skip to content

Commit

Permalink
fixes #1581
Browse files Browse the repository at this point in the history
  • Loading branch information
wumpz committed Jul 25, 2022
1 parent 2f4916d commit 732e840
Show file tree
Hide file tree
Showing 8 changed files with 270 additions and 122 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ Any requests for examples or any particular documentation will be most welcome.

## Extensions in the latest SNAPSHOT version 4.6

* support for named windows in window expressions: `SELECT sum(c) OVER winName FROM mytable WINDOW winName AS (PARTITION BY pcol)`

Additionally, we have fixed many errors and improved the code quality and the test coverage.

## Extensions of JSqlParser releases
Expand Down
66 changes: 37 additions & 29 deletions src/main/java/net/sf/jsqlparser/expression/AnalyticExpression.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,14 @@
import net.sf.jsqlparser.statement.select.OrderByElement;

/**
* Analytic function. The name of the function is variable but the parameters following the special
* analytic function path. e.g. row_number() over (order by test). Additional there can be an
* expression for an analytical aggregate like sum(col) or the "all collumns" wildcard like
* count(*).
* Analytic function. The name of the function is variable but the parameters following the special analytic function
* path. e.g. row_number() over (order by test). Additional there can be an expression for an analytical aggregate like
* sum(col) or the "all collumns" wildcard like count(*).
*
* @author tw
*/
public class AnalyticExpression extends ASTNodeAccessImpl implements Expression {

private final OrderByClause orderBy = new OrderByClause();
private final PartitionByClause partitionBy = new PartitionByClause();
private String name;
private Expression expression;
private Expression offset;
Expand All @@ -39,8 +36,9 @@ public class AnalyticExpression extends ASTNodeAccessImpl implements Expression
private boolean ignoreNulls = false; //IGNORE NULLS inside function parameters
private boolean ignoreNullsOutside = false; //IGNORE NULLS outside function parameters
private Expression filterExpression = null;
private WindowElement windowElement = null;
private List<OrderByElement> funcOrderBy = null;
private String windowName = null; // refers to an external window definition (paritionBy, orderBy, windowElement)
private WindowDefinition windowDef = new WindowDefinition();

public AnalyticExpression() {
}
Expand Down Expand Up @@ -76,11 +74,11 @@ public void accept(ExpressionVisitor expressionVisitor) {
}

public List<OrderByElement> getOrderByElements() {
return orderBy.getOrderByElements();
return windowDef.orderBy.getOrderByElements();
}

public void setOrderByElements(List<OrderByElement> orderByElements) {
orderBy.setOrderByElements(orderByElements);
windowDef.orderBy.setOrderByElements(orderByElements);
}

public KeepExpression getKeep() {
Expand All @@ -92,19 +90,19 @@ public void setKeep(KeepExpression keep) {
}

public ExpressionList getPartitionExpressionList() {
return partitionBy.getPartitionExpressionList();
return windowDef.partitionBy.getPartitionExpressionList();
}

public void setPartitionExpressionList(ExpressionList partitionExpressionList) {
setPartitionExpressionList(partitionExpressionList, false);
}

public void setPartitionExpressionList(ExpressionList partitionExpressionList, boolean brackets) {
partitionBy.setPartitionExpressionList(partitionExpressionList, brackets);
windowDef.partitionBy.setPartitionExpressionList(partitionExpressionList, brackets);
}

public boolean isPartitionByBrackets() {
return partitionBy.isBrackets();
return windowDef.partitionBy.isBrackets();
}

public String getName() {
Expand Down Expand Up @@ -140,11 +138,11 @@ public void setDefaultValue(Expression defaultValue) {
}

public WindowElement getWindowElement() {
return windowElement;
return windowDef.windowElement;
}

public void setWindowElement(WindowElement windowElement) {
this.windowElement = windowElement;
windowDef.windowElement = windowElement;
}

public AnalyticType getType() {
Expand Down Expand Up @@ -187,6 +185,22 @@ public void setIgnoreNullsOutside(boolean ignoreNullsOutside) {
this.ignoreNullsOutside = ignoreNullsOutside;
}

public String getWindowName() {
return windowName;
}

public void setWindowName(String windowName) {
this.windowName = windowName;
}

public WindowDefinition getWindowDefinition() {
return windowDef;
}

public void setWindowDefinition(WindowDefinition windowDef) {
this.windowDef = windowDef;
}

@Override
@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity", "PMD.MissingBreakInSwitch"})
public String toString() {
Expand All @@ -210,11 +224,11 @@ public String toString() {
if (isIgnoreNulls()) {
b.append(" IGNORE NULLS");
}
if (funcOrderBy!=null) {
if (funcOrderBy != null) {
b.append(" ORDER BY ");
b.append( funcOrderBy.stream().map(OrderByElement::toString).collect(joining(", ")));
b.append(funcOrderBy.stream().map(OrderByElement::toString).collect(joining(", ")));
}

b.append(") ");
if (keep != null) {
b.append(keep.toString()).append(" ");
Expand All @@ -232,7 +246,7 @@ public String toString() {
if (isIgnoreNullsOutside()) {
b.append("IGNORE NULLS ");
}

switch (type) {
case FILTER_ONLY:
return b.toString();
Expand All @@ -242,20 +256,14 @@ public String toString() {
default:
b.append("OVER");
}
b.append(" (");

partitionBy.toStringPartitionBy(b);
orderBy.toStringOrderByElements(b);

if (windowElement != null) {
if (orderBy.getOrderByElements() != null) {
b.append(' ');
}
b.append(windowElement);
if (windowName != null) {
b.append(" ").append(windowName);
} else {
b.append(" ");
b.append(windowDef.toString());
}

b.append(")");

return b.toString();
}

Expand Down
83 changes: 83 additions & 0 deletions src/main/java/net/sf/jsqlparser/expression/WindowDefinition.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*-
* #%L
* JSQLParser library
* %%
* Copyright (C) 2004 - 2022 JSQLParser
* %%
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
* #L%
*/
package net.sf.jsqlparser.expression;

import java.util.List;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.statement.select.OrderByElement;

public class WindowDefinition {

final OrderByClause orderBy = new OrderByClause();
final PartitionByClause partitionBy = new PartitionByClause();
WindowElement windowElement = null;
private String windowName;

public WindowElement getWindowElement() {
return windowElement;
}

public void setWindowElement(WindowElement windowElement) {
this.windowElement = windowElement;
}

public List<OrderByElement> getOrderByElements() {
return orderBy.getOrderByElements();
}

public void setOrderByElements(List<OrderByElement> orderByElements) {
orderBy.setOrderByElements(orderByElements);
}

public ExpressionList getPartitionExpressionList() {
return partitionBy.getPartitionExpressionList();
}

public void setPartitionExpressionList(ExpressionList partitionExpressionList) {
setPartitionExpressionList(partitionExpressionList, false);
}

public void setPartitionExpressionList(ExpressionList partitionExpressionList, boolean brackets) {
partitionBy.setPartitionExpressionList(partitionExpressionList, brackets);
}

public String getWindowName() {
return windowName;
}

public void setWindowName(String windowName) {
this.windowName = windowName;
}

public WindowDefinition withWindowName(String windowName) {
setWindowName(windowName);
return this;
}

@Override
public String toString() {
StringBuilder b = new StringBuilder();
if (windowName != null) {
b.append(windowName).append(" AS ");
}
b.append("(");
partitionBy.toStringPartitionBy(b);
orderBy.toStringOrderByElements(b);

if (windowElement != null) {
if (orderBy.getOrderByElements() != null) {
b.append(' ');
}
b.append(windowElement);
}
b.append(")");
return b.toString();
}
}
51 changes: 33 additions & 18 deletions src/main/java/net/sf/jsqlparser/statement/select/PlainSelect.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import static java.util.stream.Collectors.joining;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.OracleHierarchicalExpression;
import net.sf.jsqlparser.expression.OracleHint;
import net.sf.jsqlparser.expression.WindowDefinition;
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
import net.sf.jsqlparser.schema.Table;

Expand Down Expand Up @@ -55,6 +57,7 @@ public class PlainSelect extends ASTNodeAccessImpl implements SelectBody {
private boolean noWait = false;
private boolean emitChanges = false;
private WithIsolation withIsolation;
private List<WindowDefinition> windowDefinitions;

public boolean isUseBrackets() {
return useBrackets;
Expand Down Expand Up @@ -230,8 +233,7 @@ public void setHaving(Expression expression) {
}

/**
* A list of {@link Expression}s of the GROUP BY clause. It is null in case
* there is no GROUP BY clause
* A list of {@link Expression}s of the GROUP BY clause. It is null in case there is no GROUP BY clause
*
* @return a list of {@link Expression}s
*/
Expand Down Expand Up @@ -331,7 +333,6 @@ public boolean isEmitChanges() {
return emitChanges;
}


public WithIsolation getWithIsolation() {
return withIsolation;
}
Expand All @@ -340,8 +341,16 @@ public void setWithIsolation(WithIsolation withIsolation) {
this.withIsolation = withIsolation;
}

public List<WindowDefinition> getWindowDefinitions() {
return windowDefinitions;
}

public void setWindowDefinitions(List<WindowDefinition> windowDefinitions) {
this.windowDefinitions = windowDefinitions;
}

@Override
@SuppressWarnings({"PMD.CyclomaticComplexity" , "PMD.ExcessiveMethodLength", "PMD.NPathComplexity"})
@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.ExcessiveMethodLength", "PMD.NPathComplexity"})
public String toString() {
StringBuilder sql = new StringBuilder();
if (useBrackets) {
Expand Down Expand Up @@ -418,8 +427,14 @@ public String toString() {
if (having != null) {
sql.append(" HAVING ").append(having);
}

if (windowDefinitions != null) {
sql.append(" WINDOW ");
sql.append(windowDefinitions.stream().map(WindowDefinition::toString).collect(joining(", ")));
}

sql.append(orderByToString(oracleSiblings, orderByElements));
if (emitChanges){
if (emitChanges) {
sql.append(" EMIT CHANGES");
}
if (limit != null) {
Expand Down Expand Up @@ -471,7 +486,7 @@ public String toString() {
}
if (withIsolation != null) {
sql.append(withIsolation);
}
}
}
if (forXmlPath != null) {
sql.append(" FOR XML PATH(").append(forXmlPath).append(")");
Expand Down Expand Up @@ -509,8 +524,8 @@ public static String getFormatedList(List<?> list, String expression, boolean us
}

/**
* List the toString out put of the objects in the List comma separated. If the
* List is null or empty an empty string is returned.
* List the toString out put of the objects in the List comma separated. If the List is null or empty an empty
* string is returned.
*
* The same as getStringList(list, true, false)
*
Expand All @@ -523,11 +538,11 @@ public static String getStringList(List<?> list) {
}

/**
* List the toString out put of the objects in the List that can be comma
* separated. If the List is null or empty an empty string is returned.
* List the toString out put of the objects in the List that can be comma separated. If the List is null or empty an
* empty string is returned.
*
* @param list list of objects with toString methods
* @param useComma true if the list has to be comma separated
* @param list list of objects with toString methods
* @param useComma true if the list has to be comma separated
* @param useBrackets true if the list has to be enclosed in brackets
* @return comma separated list of the elements in the list
*/
Expand All @@ -536,11 +551,11 @@ public static String getStringList(List<?> list, boolean useComma, boolean useBr
}

/**
* Append the toString out put of the objects in the List (that can be comma
* separated). If the List is null or empty an empty string is returned.
* Append the toString out put of the objects in the List (that can be comma separated). If the List is null or
* empty an empty string is returned.
*
* @param list list of objects with toString methods
* @param useComma true if the list has to be comma separated
* @param list list of objects with toString methods
* @param useComma true if the list has to be comma separated
* @param useBrackets true if the list has to be enclosed in brackets
* @return comma separated list of the elements in the list
*/
Expand All @@ -554,9 +569,9 @@ public static StringBuilder appendStringListTo(StringBuilder builder, List<?> li

int size = list.size();
for (int i = 0; i < size; i++) {
builder.append(list.get(i)).append( i < size - 1
builder.append(list.get(i)).append(i < size - 1
? comma + " "
: "" );
: "");
}

if (useBrackets) {
Expand Down

0 comments on commit 732e840

Please sign in to comment.