Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ public <S> T visit(Function function, S context) {
if (function.getParameters() != null) {
subExpressions.addAll(function.getParameters());
}
if (function.getChainedParameters() != null) {
subExpressions.addAll(function.getChainedParameters());
}
if (function.getKeep() != null) {
subExpressions.add(function.getKeep());
}
Expand Down
24 changes: 24 additions & 0 deletions src/main/java/net/sf/jsqlparser/expression/Function.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
public class Function extends ASTNodeAccessImpl implements Expression {
private List<String> nameparts;
private ExpressionList<?> parameters;
private ExpressionList<?> chainedParameters;
private NamedExpressionList<?> namedParameters;
private boolean allColumns = false;
private boolean distinct = false;
Expand Down Expand Up @@ -192,6 +193,20 @@ public void setParameters(ExpressionList<?> list) {
parameters = list;
}

/**
* Additional function-call parameters for dialects that support chained function calls, e.g.
* quantile(0.95)(cost) in ClickHouse.
*
* @return the chained parameters of the function (if any, else null)
*/
public ExpressionList<?> getChainedParameters() {
return chainedParameters;
}

public void setChainedParameters(ExpressionList<?> chainedParameters) {
this.chainedParameters = chainedParameters;
}

/**
* the parameters might be named parameters, e.g. substring('foobar' from 2 for 3)
*
Expand Down Expand Up @@ -335,6 +350,10 @@ public String toString() {

String ans = getName() + params;

if (chainedParameters != null) {
ans += "(" + chainedParameters + ")";
}

if (nullHandling != null && isIgnoreNullsOutside()) {
switch (nullHandling) {
case IGNORE_NULLS:
Expand Down Expand Up @@ -393,6 +412,11 @@ public Function withParameters(Expression... parameters) {
return withParameters(new ExpressionList<>(parameters));
}

public Function withChainedParameters(ExpressionList<?> chainedParameters) {
this.setChainedParameters(chainedParameters);
return this;
}

public Function withNamedParameters(NamedExpressionList<?> namedParameters) {
this.setNamedParameters(namedParameters);
return this;
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,10 @@ public <S> Void visit(Function function, S context) {
if (exprList != null) {
visit(exprList, context);
}
exprList = function.getChainedParameters();
if (exprList != null) {
visit(exprList, context);
}
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -920,6 +920,12 @@ public <S> StringBuilder visit(Function function, S context) {
builder.append(")");
}

if (function.getChainedParameters() != null) {
builder.append("(");
function.getChainedParameters().accept(this, context);
builder.append(")");
}

if (function.getNullHandling() != null && function.isIgnoreNullsOutside()) {
switch (function.getNullHandling()) {
case IGNORE_NULLS:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,7 @@ public <S> Void visit(Function function, S context) {

validateOptionalExpressionList(function.getNamedParameters());
validateOptionalExpressionList(function.getParameters());
validateOptionalExpressionList(function.getChainedParameters());

Object attribute = function.getAttribute();
if (attribute instanceof Expression) {
Expand Down
6 changes: 6 additions & 0 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -8308,6 +8308,7 @@ Function InternalFunction(boolean escaped):
Function retval = new Function();
ObjectNames funcName;
ExpressionList expressionList = null;
ExpressionList chainedExpressionList = null;
KeepExpression keep = null;
Expression expr = null;
Expression attributeExpression = null;
Expand Down Expand Up @@ -8374,6 +8375,10 @@ Function InternalFunction(boolean escaped):

")"

[
LOOKAHEAD(2) "(" chainedExpressionList = ExpressionList() ")"
]


[ LOOKAHEAD(2) "." (
// tricky lookahead since we do need to support the following constructs
Expand Down Expand Up @@ -8409,6 +8414,7 @@ Function InternalFunction(boolean escaped):
{
retval.setEscaped(escaped);
retval.setParameters(expressionList);
retval.setChainedParameters(chainedExpressionList);
retval.setName(funcName.getNames());
retval.setKeep(keep);
return retval;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
package net.sf.jsqlparser.statement.select;

import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Function;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -116,4 +117,19 @@ public void testPreWhereWithWhereClause() throws JSQLParserException {
Assertions.assertNotNull(select.getPreWhere());
Assertions.assertNotNull(select.getWhere());
}

@Test
public void testParameterizedAggregateFunctionIssue2125() throws JSQLParserException {
String sql =
"SELECT toStartOfDay(timestamp) AS date, count(1) AS count, quantile(0.95)(cost) AS cost95 FROM apm_log_event";
Select select = (Select) assertSqlCanBeParsedAndDeparsed(sql, true);

Function function = ((PlainSelect) select.getSelectBody())
.getSelectItem(2)
.getExpression(Function.class);
Assertions.assertNotNull(function.getParameters());
Assertions.assertNotNull(function.getChainedParameters());
Assertions.assertEquals(1, function.getParameters().size());
Assertions.assertEquals(1, function.getChainedParameters().size());
}
}