use of org.hibernate.query.sqm.tree.select.SqmOrderByClause in project hibernate-orm by hibernate.
the class SemanticQueryBuilder method visitQueryOrder.
protected void visitQueryOrder(SqmQueryPart<?> sqmQueryPart, HqlParser.QueryOrderContext ctx) {
if (ctx == null) {
return;
}
final SqmOrderByClause orderByClause;
final HqlParser.OrderByClauseContext orderByClauseContext = (HqlParser.OrderByClauseContext) ctx.getChild(0);
if (orderByClauseContext != null) {
if (creationOptions.useStrictJpaCompliance() && processingStateStack.depth() > 1) {
throw new StrictJpaComplianceViolation(StrictJpaComplianceViolation.Type.SUBQUERY_ORDER_BY);
}
orderByClause = visitOrderByClause(orderByClauseContext);
sqmQueryPart.setOrderByClause(orderByClause);
} else {
orderByClause = null;
}
int currentIndex = 1;
final HqlParser.LimitClauseContext limitClauseContext;
if (currentIndex < ctx.getChildCount() && ctx.getChild(currentIndex) instanceof HqlParser.LimitClauseContext) {
limitClauseContext = (HqlParser.LimitClauseContext) ctx.getChild(currentIndex++);
} else {
limitClauseContext = null;
}
final HqlParser.OffsetClauseContext offsetClauseContext;
if (currentIndex < ctx.getChildCount() && ctx.getChild(currentIndex) instanceof HqlParser.OffsetClauseContext) {
offsetClauseContext = (HqlParser.OffsetClauseContext) ctx.getChild(currentIndex++);
} else {
offsetClauseContext = null;
}
final HqlParser.FetchClauseContext fetchClauseContext;
if (currentIndex < ctx.getChildCount() && ctx.getChild(currentIndex) instanceof HqlParser.FetchClauseContext) {
fetchClauseContext = (HqlParser.FetchClauseContext) ctx.getChild(currentIndex++);
} else {
fetchClauseContext = null;
}
if (currentIndex != 1) {
if (getCreationOptions().useStrictJpaCompliance()) {
throw new StrictJpaComplianceViolation(StrictJpaComplianceViolation.Type.LIMIT_OFFSET_CLAUSE);
}
if (processingStateStack.depth() > 1 && orderByClause == null) {
throw new SemanticException("limit, offset and fetch clause require an order-by clause when used in sub-query");
}
sqmQueryPart.setOffsetExpression(visitOffsetClause(offsetClauseContext));
if (limitClauseContext == null) {
sqmQueryPart.setFetchExpression(visitFetchClause(fetchClauseContext), visitFetchClauseType(fetchClauseContext));
} else if (fetchClauseContext == null) {
sqmQueryPart.setFetchExpression(visitLimitClause(limitClauseContext));
} else {
throw new SemanticException("Can't use both limit and fetch clause");
}
}
}
use of org.hibernate.query.sqm.tree.select.SqmOrderByClause in project hibernate-orm by hibernate.
the class InverseDistributionWindowEmulation method generateSqmOrderedSetAggregateFunctionExpression.
@Override
public <T> SelfRenderingSqmOrderedSetAggregateFunction<T> generateSqmOrderedSetAggregateFunctionExpression(List<? extends SqmTypedNode<?>> arguments, SqmPredicate filter, SqmOrderByClause withinGroupClause, ReturnableType<T> impliedResultType, QueryEngine queryEngine, TypeConfiguration typeConfiguration) {
return new SelfRenderingInverseDistributionFunction<>(arguments, filter, withinGroupClause, impliedResultType, queryEngine) {
@Override
public Expression convertToSqlAst(SqmToSqlAstConverter walker) {
final Clause currentClause = walker.getCurrentClauseStack().getCurrent();
if (currentClause == Clause.OVER) {
return super.convertToSqlAst(walker);
} else if (currentClause != Clause.SELECT) {
throw new IllegalArgumentException("Can't emulate [" + getName() + "] in clause " + currentClause + ". Only the SELECT clause is supported!");
}
final ReturnableType<?> resultType = resolveResultType(walker.getCreationContext().getMappingMetamodel().getTypeConfiguration());
List<SqlAstNode> arguments = resolveSqlAstArguments(getArguments(), walker);
ArgumentsValidator argumentsValidator = getArgumentsValidator();
if (argumentsValidator != null) {
argumentsValidator.validateSqlTypes(arguments, getFunctionName());
}
List<SortSpecification> withinGroup;
if (this.getWithinGroup() == null) {
withinGroup = Collections.emptyList();
} else {
walker.getCurrentClauseStack().push(Clause.ORDER);
try {
final List<SqmSortSpecification> sortSpecifications = this.getWithinGroup().getSortSpecifications();
withinGroup = new ArrayList<>(sortSpecifications.size());
for (SqmSortSpecification sortSpecification : sortSpecifications) {
final SortSpecification specification = (SortSpecification) walker.visitSortSpecification(sortSpecification);
if (specification != null) {
withinGroup.add(specification);
}
}
} finally {
walker.getCurrentClauseStack().pop();
}
}
final SelfRenderingFunctionSqlAstExpression function = new SelfRenderingOrderedSetAggregateFunctionSqlAstExpression(getFunctionName(), getRenderingSupport(), arguments, getFilter() == null ? null : (Predicate) getFilter().accept(walker), withinGroup, resultType, getMappingModelExpressible(walker, resultType));
final Over<Object> windowFunction = new Over<>(function, new ArrayList<>(), Collections.emptyList());
walker.registerQueryTransformer(new AggregateWindowEmulationQueryTransformer(windowFunction, withinGroup, null));
return windowFunction;
}
};
}
use of org.hibernate.query.sqm.tree.select.SqmOrderByClause in project hibernate-orm by hibernate.
the class HypotheticalSetWindowEmulation method generateSqmOrderedSetAggregateFunctionExpression.
@Override
public <T> SelfRenderingSqmOrderedSetAggregateFunction<T> generateSqmOrderedSetAggregateFunctionExpression(List<? extends SqmTypedNode<?>> arguments, SqmPredicate filter, SqmOrderByClause withinGroupClause, ReturnableType<T> impliedResultType, QueryEngine queryEngine, TypeConfiguration typeConfiguration) {
return new SelfRenderingSqmOrderedSetAggregateFunction<>(this, this, arguments, filter, withinGroupClause, impliedResultType, getArgumentsValidator(), getReturnTypeResolver(), queryEngine.getCriteriaBuilder(), getName()) {
@Override
public Expression convertToSqlAst(SqmToSqlAstConverter walker) {
final Clause currentClause = walker.getCurrentClauseStack().getCurrent();
if (currentClause == Clause.OVER) {
return super.convertToSqlAst(walker);
} else if (currentClause != Clause.SELECT) {
throw new IllegalArgumentException("Can't emulate [" + getName() + "] in clause " + currentClause + ". Only the SELECT clause is supported!");
}
final ReturnableType<?> resultType = resolveResultType(walker.getCreationContext().getMappingMetamodel().getTypeConfiguration());
List<SqlAstNode> arguments = resolveSqlAstArguments(getArguments(), walker);
ArgumentsValidator argumentsValidator = getArgumentsValidator();
if (argumentsValidator != null) {
argumentsValidator.validateSqlTypes(arguments, getFunctionName());
}
List<SortSpecification> withinGroup;
if (this.getWithinGroup() == null) {
withinGroup = Collections.emptyList();
} else {
walker.getCurrentClauseStack().push(Clause.ORDER);
try {
final List<SqmSortSpecification> sortSpecifications = this.getWithinGroup().getSortSpecifications();
withinGroup = new ArrayList<>(sortSpecifications.size());
for (SqmSortSpecification sortSpecification : sortSpecifications) {
final SortSpecification specification = (SortSpecification) walker.visitSortSpecification(sortSpecification);
if (specification != null) {
withinGroup.add(specification);
}
}
} finally {
walker.getCurrentClauseStack().pop();
}
}
final SelfRenderingFunctionSqlAstExpression function = new SelfRenderingOrderedSetAggregateFunctionSqlAstExpression(getFunctionName(), getRenderingSupport(), Collections.emptyList(), getFilter() == null ? null : (Predicate) getFilter().accept(walker), Collections.emptyList(), resultType, getMappingModelExpressible(walker, resultType));
final Over<Object> windowFunction = new Over<>(function, new ArrayList<>(), withinGroup);
walker.registerQueryTransformer(new AggregateWindowEmulationQueryTransformer(windowFunction, withinGroup, arguments));
return windowFunction;
}
};
}
use of org.hibernate.query.sqm.tree.select.SqmOrderByClause in project hibernate-orm by hibernate.
the class SemanticQueryBuilder method visitGenericFunction.
@Override
public Object visitGenericFunction(HqlParser.GenericFunctionContext ctx) {
final String originalFunctionName = visitGenericFunctionName(ctx.genericFunctionName());
final String functionName = originalFunctionName.toLowerCase();
if (creationOptions.useStrictJpaCompliance() && !JPA_STANDARD_FUNCTIONS.contains(functionName)) {
throw new StrictJpaComplianceViolation("Encountered non-compliant non-standard function call [" + originalFunctionName + "], but strict JPA " + "compliance was requested; use JPA's FUNCTION(functionName[,...]) " + "syntax name instead", StrictJpaComplianceViolation.Type.FUNCTION_CALL);
}
final ParseTree argumentChild = ctx.getChild(2);
final List<SqmTypedNode<?>> functionArguments;
if (argumentChild instanceof HqlParser.GenericFunctionArgumentsContext) {
functionArguments = (List<SqmTypedNode<?>>) argumentChild.accept(this);
} else if ("*".equals(argumentChild.getText())) {
functionArguments = Collections.singletonList(new SqmStar(getCreationContext().getNodeBuilder()));
} else {
functionArguments = emptyList();
}
final Boolean fromFirst = getFromFirst(ctx);
final Boolean respectNulls = getRespectNullsClause(ctx);
final SqmOrderByClause withinGroup = getWithinGroup(ctx);
final SqmPredicate filterExpression = getFilterExpression(ctx);
final boolean hasOverClause = ctx.getChild(ctx.getChildCount() - 1) instanceof HqlParser.OverClauseContext;
SqmFunctionDescriptor functionTemplate = getFunctionDescriptor(functionName);
if (functionTemplate == null) {
FunctionKind functionKind = FunctionKind.NORMAL;
if (withinGroup != null) {
functionKind = FunctionKind.ORDERED_SET_AGGREGATE;
} else if (hasOverClause) {
functionKind = FunctionKind.WINDOW;
} else if (filterExpression != null) {
functionKind = FunctionKind.AGGREGATE;
}
functionTemplate = new NamedSqmFunctionDescriptor(functionName, true, null, StandardFunctionReturnTypeResolvers.invariant(resolveExpressibleTypeBasic(Object.class)), null, functionName, functionKind, null, SqlAstNodeRenderingMode.DEFAULT);
} else {
if (hasOverClause && functionTemplate.getFunctionKind() == FunctionKind.NORMAL) {
throw new SemanticException("OVER clause is illegal for normal function: " + functionName);
} else if (!hasOverClause && functionTemplate.getFunctionKind() == FunctionKind.WINDOW) {
throw new SemanticException("OVER clause is mandatory for window-only function: " + functionName);
}
if (respectNulls != null) {
switch(functionName) {
case "lag":
case "lead":
case "first_value":
case "last_value":
case "nth_value":
break;
default:
throw new SemanticException("RESPECT/IGNORE NULLS is illegal for function: " + functionName);
}
}
if (fromFirst != null && !"nth_value".equals(functionName)) {
throw new SemanticException("FROM FIRST/LAST is illegal for function: " + functionName);
}
}
final SqmFunction<?> function;
switch(functionTemplate.getFunctionKind()) {
case ORDERED_SET_AGGREGATE:
function = functionTemplate.generateOrderedSetAggregateSqmExpression(functionArguments, filterExpression, withinGroup, null, creationContext.getQueryEngine(), creationContext.getJpaMetamodel().getTypeConfiguration());
break;
case AGGREGATE:
function = functionTemplate.generateAggregateSqmExpression(functionArguments, filterExpression, null, creationContext.getQueryEngine(), creationContext.getJpaMetamodel().getTypeConfiguration());
break;
case WINDOW:
function = functionTemplate.generateWindowSqmExpression(functionArguments, filterExpression, null, null, null, creationContext.getQueryEngine(), creationContext.getJpaMetamodel().getTypeConfiguration());
break;
default:
if (filterExpression != null) {
throw new ParsingException("Illegal use of a FILTER clause for non-aggregate function: " + originalFunctionName);
}
function = functionTemplate.generateSqmExpression(functionArguments, null, creationContext.getQueryEngine(), creationContext.getJpaMetamodel().getTypeConfiguration());
break;
}
return applyOverClause(ctx, function);
}
use of org.hibernate.query.sqm.tree.select.SqmOrderByClause in project hibernate-orm by hibernate.
the class SemanticQueryBuilder method visitListaggFunction.
@Override
public Object visitListaggFunction(ListaggFunctionContext ctx) {
if (creationOptions.useStrictJpaCompliance()) {
throw new StrictJpaComplianceViolation("Encountered non-compliant non-standard function call [listagg], but strict JPA " + "compliance was requested; use JPA's FUNCTION(functionName[,...]) " + "syntax name instead", StrictJpaComplianceViolation.Type.FUNCTION_CALL);
}
final SqmFunctionDescriptor functionTemplate = getFunctionDescriptor("listagg");
if (functionTemplate == null) {
throw new SemanticException("The listagg function was not registered for the dialect!");
}
final int argumentStartIndex;
final ParseTree thirdChild = ctx.getChild(2);
final boolean distinct;
if (thirdChild instanceof TerminalNode) {
distinct = true;
argumentStartIndex = 3;
} else {
distinct = false;
argumentStartIndex = 2;
}
final SqmExpression<?> firstArgument = (SqmExpression<?>) ctx.getChild(argumentStartIndex).accept(this);
final SqmExpression<?> secondArgument = (SqmExpression<?>) ctx.getChild(argumentStartIndex + 2).accept(this);
final ParseTree overflowCtx = ctx.getChild(argumentStartIndex + 3);
final List<SqmTypedNode<?>> functionArguments = new ArrayList<>(3);
if (distinct) {
functionArguments.add(new SqmDistinct<>(firstArgument, creationContext.getNodeBuilder()));
} else {
functionArguments.add(firstArgument);
}
if (overflowCtx instanceof OnOverflowClauseContext) {
if (overflowCtx.getChildCount() > 3) {
// ON OVERFLOW TRUNCATE
final TerminalNode countNode = (TerminalNode) overflowCtx.getChild(overflowCtx.getChildCount() - 2);
final boolean withCount = countNode.getSymbol().getType() == HqlParser.WITH;
final SqmExpression<?> fillerExpression;
if (overflowCtx.getChildCount() == 6) {
fillerExpression = (SqmExpression<?>) overflowCtx.getChild(3).accept(this);
} else {
// The SQL standard says the default is three periods `...`
fillerExpression = new SqmLiteral<>("...", secondArgument.getNodeType(), secondArgument.nodeBuilder());
}
// noinspection unchecked,rawtypes
functionArguments.add(new SqmOverflow(secondArgument, fillerExpression, withCount));
} else {
// ON OVERFLOW ERROR
functionArguments.add(new SqmOverflow<>(secondArgument, null, false));
}
} else {
functionArguments.add(secondArgument);
}
final SqmOrderByClause withinGroup = getWithinGroup(ctx);
final SqmPredicate filterExpression = getFilterExpression(ctx);
return applyOverClause(ctx, functionTemplate.generateOrderedSetAggregateSqmExpression(functionArguments, filterExpression, withinGroup, null, creationContext.getQueryEngine(), creationContext.getJpaMetamodel().getTypeConfiguration()));
}
Aggregations