use of org.hibernate.query.sqm.tree.select.SqmSortSpecification in project hibernate-orm by hibernate.
the class SemanticQueryBuilder method applyOverClause.
private SqmExpression<?> applyOverClause(HqlParser.OverClauseContext ctx, SqmFunction<?> function) {
final List<SqmExpression<?>> partitions;
final List<SqmSortSpecification> orderList;
final FrameMode mode;
final FrameKind startKind;
final SqmExpression<?> startExpression;
final FrameKind endKind;
final SqmExpression<?> endExpression;
final FrameExclusion exclusion;
int index = 2;
if (ctx.getChild(index) instanceof HqlParser.PartitionClauseContext) {
final ParseTree subCtx = ctx.getChild(index);
partitions = new ArrayList<>((subCtx.getChildCount() >> 1) - 1);
for (int i = 2; i < subCtx.getChildCount(); i += 2) {
partitions.add((SqmExpression<?>) subCtx.getChild(i).accept(this));
}
index++;
} else {
partitions = Collections.emptyList();
}
if (index < ctx.getChildCount() && ctx.getChild(index) instanceof HqlParser.OrderByClauseContext) {
orderList = visitOrderByClause((HqlParser.OrderByClauseContext) ctx.getChild(index)).getSortSpecifications();
index++;
} else {
orderList = Collections.emptyList();
}
if (index < ctx.getChildCount() && ctx.getChild(index) instanceof HqlParser.FrameClauseContext) {
final ParseTree frameCtx = ctx.getChild(index);
switch(((TerminalNode) frameCtx.getChild(0)).getSymbol().getType()) {
case HqlParser.RANGE:
mode = FrameMode.RANGE;
break;
case HqlParser.ROWS:
mode = FrameMode.ROWS;
break;
case HqlParser.GROUPS:
mode = FrameMode.GROUPS;
break;
default:
throw new IllegalArgumentException("Unexpected frame mode: " + frameCtx.getChild(0));
}
final int frameStartIndex;
if (frameCtx.getChild(1) instanceof TerminalNode) {
frameStartIndex = 2;
endKind = getFrameKind(frameCtx.getChild(4));
endExpression = endKind == FrameKind.OFFSET_FOLLOWING || endKind == FrameKind.OFFSET_PRECEDING ? (SqmExpression<?>) frameCtx.getChild(4).getChild(0).accept(this) : null;
} else {
frameStartIndex = 1;
endKind = FrameKind.CURRENT_ROW;
endExpression = null;
}
startKind = getFrameKind(frameCtx.getChild(frameStartIndex));
startExpression = startKind == FrameKind.OFFSET_FOLLOWING || startKind == FrameKind.OFFSET_PRECEDING ? (SqmExpression<?>) frameCtx.getChild(frameStartIndex).getChild(0).accept(this) : null;
final ParseTree lastChild = frameCtx.getChild(frameCtx.getChildCount() - 1);
if (lastChild instanceof HqlParser.FrameExclusionContext) {
switch(((TerminalNode) lastChild.getChild(1)).getSymbol().getType()) {
case HqlParser.CURRENT:
exclusion = FrameExclusion.CURRENT_ROW;
break;
case HqlParser.GROUP:
exclusion = FrameExclusion.GROUP;
break;
case HqlParser.TIES:
exclusion = FrameExclusion.TIES;
break;
case HqlParser.NO:
exclusion = FrameExclusion.NO_OTHERS;
break;
default:
throw new IllegalArgumentException("Unexpected frame exclusion: " + lastChild);
}
} else {
exclusion = FrameExclusion.NO_OTHERS;
}
} else {
mode = FrameMode.ROWS;
startKind = FrameKind.UNBOUNDED_PRECEDING;
startExpression = null;
endKind = FrameKind.CURRENT_ROW;
endExpression = null;
exclusion = FrameExclusion.NO_OTHERS;
}
return new SqmOver<>(function, partitions, orderList, mode, startKind, startExpression, endKind, endExpression, exclusion);
}
use of org.hibernate.query.sqm.tree.select.SqmSortSpecification 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.SqmSortSpecification in project hibernate-orm by hibernate.
the class SqmOver method copy.
@Override
public SqmOver<T> copy(SqmCopyContext context) {
final SqmOver<T> existing = context.getCopy(this);
if (existing != null) {
return existing;
}
final List<SqmExpression<?>> partitions = new ArrayList<>(this.partitions.size());
for (SqmExpression<?> partition : this.partitions) {
partitions.add(partition.copy(context));
}
final List<SqmSortSpecification> orderList = new ArrayList<>(this.orderList.size());
for (SqmSortSpecification sortSpecification : this.orderList) {
orderList.add(sortSpecification.copy(context));
}
final SqmOver<T> over = context.registerCopy(this, new SqmOver<>(expression.copy(context), partitions, orderList, mode, startKind, startExpression == null ? null : startExpression.copy(context), endKind, endExpression == null ? null : endExpression.copy(context), exclusion));
copyTo(over, context);
return over;
}
use of org.hibernate.query.sqm.tree.select.SqmSortSpecification in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method visitOrderByOffsetAndFetch.
protected void visitOrderByOffsetAndFetch(SqmQueryPart<?> sqmQueryPart, QueryPart sqlQueryPart) {
if (sqmQueryPart.getOrderByClause() != null) {
currentClauseStack.push(Clause.ORDER);
inferrableTypeAccessStack.push(() -> null);
try {
for (SqmSortSpecification sortSpecification : sqmQueryPart.getOrderByClause().getSortSpecifications()) {
final SortSpecification specification = visitSortSpecification(sortSpecification);
if (specification != null) {
sqlQueryPart.addSortSpecification(specification);
}
}
} finally {
inferrableTypeAccessStack.pop();
currentClauseStack.pop();
}
}
if (!containsCollectionFetches || !currentClauseStack.isEmpty()) {
// Strip off the root offset and limit expressions in case the query contains collection fetches to retain
// the proper cardinality. We could implement pagination for single select statements differently in this
// case by using a subquery e.g. `... where alias in (select subAlias from ... limit ...)`
// or use window functions e.g. `select ... from (select ..., dense_rank() over(order by ..., id) rn from ...) tmp where tmp.rn between ...`
// but these transformations/translations are non-trivial and can be done later
inferrableTypeAccessStack.push(() -> getTypeConfiguration().getBasicTypeForJavaType(Integer.class));
sqlQueryPart.setOffsetClauseExpression(visitOffsetExpression(sqmQueryPart.getOffsetExpression()));
if (sqmQueryPart.getFetchClauseType() == FetchClauseType.PERCENT_ONLY || sqmQueryPart.getFetchClauseType() == FetchClauseType.PERCENT_WITH_TIES) {
inferrableTypeAccessStack.pop();
inferrableTypeAccessStack.push(() -> getTypeConfiguration().getBasicTypeForJavaType(Double.class));
}
sqlQueryPart.setFetchClauseExpression(visitFetchExpression(sqmQueryPart.getFetchExpression()), sqmQueryPart.getFetchClauseType());
inferrableTypeAccessStack.pop();
}
}
use of org.hibernate.query.sqm.tree.select.SqmSortSpecification in project hibernate-orm by hibernate.
the class HHH13884Test method testDefaultReversedOrderImpl.
@Test
public void testDefaultReversedOrderImpl() {
SqmExpression<?> expression = mock(SqmExpression.class);
SqmSortSpecification order = new SqmSortSpecification(expression);
assertEquals(expression, order.getExpression());
assertTrue("Order should be ascending by default", order.isAscending());
Order reversed = order.reverse();
assertEquals(expression, reversed.getExpression());
assertFalse("Reversed Order should be descending", reversed.isAscending());
assertNotSame("Order.reverse() should create new instance by the contract", order, reversed);
}
Aggregations