use of io.trino.sql.tree.Window in project trino by trinodb.
the class AstBuilder method visitListagg.
/**
* Returns the corresponding {@link FunctionCall} for the `LISTAGG` primary expression.
* <p>
* Although the syntax tree should represent the structure of the original parsed query
* as closely as possible and any semantic interpretation should be part of the
* analysis/planning phase, in case of `LISTAGG` aggregation function it is more pragmatic
* now to create a synthetic {@link FunctionCall} expression during the parsing of the syntax tree.
*
* @param context `LISTAGG` expression context
*/
@Override
public Node visitListagg(SqlBaseParser.ListaggContext context) {
Optional<Window> window = Optional.empty();
OrderBy orderBy = new OrderBy(visit(context.sortItem(), SortItem.class));
boolean distinct = isDistinct(context.setQuantifier());
Expression expression = (Expression) visit(context.expression());
StringLiteral separator = context.string() == null ? new StringLiteral(getLocation(context), "") : (StringLiteral) (visit(context.string()));
BooleanLiteral overflowError = new BooleanLiteral(getLocation(context), "true");
StringLiteral overflowFiller = new StringLiteral(getLocation(context), "...");
BooleanLiteral showOverflowEntryCount = new BooleanLiteral(getLocation(context), "false");
SqlBaseParser.ListAggOverflowBehaviorContext overflowBehavior = context.listAggOverflowBehavior();
if (overflowBehavior != null) {
if (overflowBehavior.ERROR() != null) {
overflowError = new BooleanLiteral(getLocation(context), "true");
} else if (overflowBehavior.TRUNCATE() != null) {
overflowError = new BooleanLiteral(getLocation(context), "false");
if (overflowBehavior.string() != null) {
overflowFiller = (StringLiteral) (visit(overflowBehavior.string()));
}
SqlBaseParser.ListaggCountIndicationContext listaggCountIndicationContext = overflowBehavior.listaggCountIndication();
if (listaggCountIndicationContext.WITH() != null) {
showOverflowEntryCount = new BooleanLiteral(getLocation(context), "true");
} else if (listaggCountIndicationContext.WITHOUT() != null) {
showOverflowEntryCount = new BooleanLiteral(getLocation(context), "false");
}
}
}
List<Expression> arguments = ImmutableList.of(expression, separator, overflowError, overflowFiller, showOverflowEntryCount);
// TODO model this as a ListAgg node in the AST
return new FunctionCall(Optional.of(getLocation(context)), QualifiedName.of("LISTAGG"), window, Optional.empty(), Optional.of(orderBy), distinct, Optional.empty(), Optional.empty(), arguments);
}
use of io.trino.sql.tree.Window in project trino by trinodb.
the class AstBuilder method visitFunctionCall.
@Override
public Node visitFunctionCall(SqlBaseParser.FunctionCallContext context) {
Optional<Expression> filter = visitIfPresent(context.filter(), Expression.class);
Optional<Window> window = visitIfPresent(context.over(), Window.class);
Optional<OrderBy> orderBy = Optional.empty();
if (context.ORDER() != null) {
orderBy = Optional.of(new OrderBy(visit(context.sortItem(), SortItem.class)));
}
QualifiedName name = getQualifiedName(context.qualifiedName());
boolean distinct = isDistinct(context.setQuantifier());
SqlBaseParser.NullTreatmentContext nullTreatment = context.nullTreatment();
SqlBaseParser.ProcessingModeContext processingMode = context.processingMode();
if (name.toString().equalsIgnoreCase("if")) {
check(context.expression().size() == 2 || context.expression().size() == 3, "Invalid number of arguments for 'if' function", context);
check(!window.isPresent(), "OVER clause not valid for 'if' function", context);
check(!distinct, "DISTINCT not valid for 'if' function", context);
check(nullTreatment == null, "Null treatment clause not valid for 'if' function", context);
check(processingMode == null, "Running or final semantics not valid for 'if' function", context);
check(!filter.isPresent(), "FILTER not valid for 'if' function", context);
Expression elseExpression = null;
if (context.expression().size() == 3) {
elseExpression = (Expression) visit(context.expression(2));
}
return new IfExpression(getLocation(context), (Expression) visit(context.expression(0)), (Expression) visit(context.expression(1)), elseExpression);
}
if (name.toString().equalsIgnoreCase("nullif")) {
check(context.expression().size() == 2, "Invalid number of arguments for 'nullif' function", context);
check(!window.isPresent(), "OVER clause not valid for 'nullif' function", context);
check(!distinct, "DISTINCT not valid for 'nullif' function", context);
check(nullTreatment == null, "Null treatment clause not valid for 'nullif' function", context);
check(processingMode == null, "Running or final semantics not valid for 'nullif' function", context);
check(!filter.isPresent(), "FILTER not valid for 'nullif' function", context);
return new NullIfExpression(getLocation(context), (Expression) visit(context.expression(0)), (Expression) visit(context.expression(1)));
}
if (name.toString().equalsIgnoreCase("coalesce")) {
check(context.expression().size() >= 2, "The 'coalesce' function must have at least two arguments", context);
check(!window.isPresent(), "OVER clause not valid for 'coalesce' function", context);
check(!distinct, "DISTINCT not valid for 'coalesce' function", context);
check(nullTreatment == null, "Null treatment clause not valid for 'coalesce' function", context);
check(processingMode == null, "Running or final semantics not valid for 'coalesce' function", context);
check(!filter.isPresent(), "FILTER not valid for 'coalesce' function", context);
return new CoalesceExpression(getLocation(context), visit(context.expression(), Expression.class));
}
if (name.toString().equalsIgnoreCase("try")) {
check(context.expression().size() == 1, "The 'try' function must have exactly one argument", context);
check(!window.isPresent(), "OVER clause not valid for 'try' function", context);
check(!distinct, "DISTINCT not valid for 'try' function", context);
check(nullTreatment == null, "Null treatment clause not valid for 'try' function", context);
check(processingMode == null, "Running or final semantics not valid for 'try' function", context);
check(!filter.isPresent(), "FILTER not valid for 'try' function", context);
return new TryExpression(getLocation(context), (Expression) visit(getOnlyElement(context.expression())));
}
if (name.toString().equalsIgnoreCase("format")) {
check(context.expression().size() >= 2, "The 'format' function must have at least two arguments", context);
check(!window.isPresent(), "OVER clause not valid for 'format' function", context);
check(!distinct, "DISTINCT not valid for 'format' function", context);
check(nullTreatment == null, "Null treatment clause not valid for 'format' function", context);
check(processingMode == null, "Running or final semantics not valid for 'format' function", context);
check(!filter.isPresent(), "FILTER not valid for 'format' function", context);
return new Format(getLocation(context), visit(context.expression(), Expression.class));
}
if (name.toString().equalsIgnoreCase("$internal$bind")) {
check(context.expression().size() >= 1, "The '$internal$bind' function must have at least one arguments", context);
check(!window.isPresent(), "OVER clause not valid for '$internal$bind' function", context);
check(!distinct, "DISTINCT not valid for '$internal$bind' function", context);
check(nullTreatment == null, "Null treatment clause not valid for '$internal$bind' function", context);
check(processingMode == null, "Running or final semantics not valid for '$internal$bind' function", context);
check(!filter.isPresent(), "FILTER not valid for '$internal$bind' function", context);
int numValues = context.expression().size() - 1;
List<Expression> arguments = context.expression().stream().map(this::visit).map(Expression.class::cast).collect(toImmutableList());
return new BindExpression(getLocation(context), arguments.subList(0, numValues), arguments.get(numValues));
}
Optional<NullTreatment> nulls = Optional.empty();
if (nullTreatment != null) {
if (nullTreatment.IGNORE() != null) {
nulls = Optional.of(NullTreatment.IGNORE);
} else if (nullTreatment.RESPECT() != null) {
nulls = Optional.of(NullTreatment.RESPECT);
}
}
Optional<ProcessingMode> mode = Optional.empty();
if (processingMode != null) {
if (processingMode.RUNNING() != null) {
mode = Optional.of(new ProcessingMode(getLocation(processingMode), RUNNING));
} else if (processingMode.FINAL() != null) {
mode = Optional.of(new ProcessingMode(getLocation(processingMode), FINAL));
}
}
List<Expression> arguments = visit(context.expression(), Expression.class);
if (context.label != null) {
arguments = ImmutableList.of(new DereferenceExpression(getLocation(context.label), (Identifier) visit(context.label)));
}
return new FunctionCall(Optional.of(getLocation(context)), name, window, filter, orderBy, distinct, nulls, mode, arguments);
}
Aggregations