use of org.hibernate.query.sqm.tree.expression.SqmAliasedNodeRef in project hibernate-orm by hibernate.
the class SemanticQueryBuilder method resolveOrderByOrGroupByExpression.
private SqmExpression<?> resolveOrderByOrGroupByExpression(ParseTree child, boolean definedCollate) {
if (child instanceof TerminalNode) {
if (definedCollate) {
// This is syntactically disallowed
throw new ParsingException("COLLATE is not allowed for position based order-by or group-by items");
}
final int position = Integer.parseInt(child.getText());
// make sure this selection exists
final SqmAliasedNode<?> nodeByPosition = getCurrentProcessingState().getPathRegistry().findAliasedNodeByPosition(position);
if (nodeByPosition == null) {
throw new ParsingException("Numeric literal '" + position + "' used in group-by does not match a registered select-item");
}
return new SqmAliasedNodeRef(position, integerDomainType, creationContext.getNodeBuilder());
} else if (child instanceof HqlParser.IdentifierContext) {
final String identifierText = visitIdentifier((HqlParser.IdentifierContext) child);
final Integer correspondingPosition = getCurrentProcessingState().getPathRegistry().findAliasedNodePosition(identifierText);
if (correspondingPosition != null) {
if (definedCollate) {
// This is syntactically disallowed
throw new ParsingException("COLLATE is not allowed for alias based order-by or group-by items");
}
return new SqmAliasedNodeRef(correspondingPosition, integerDomainType, creationContext.getNodeBuilder());
}
final SqmFrom<?, ?> sqmFrom = getCurrentProcessingState().getPathRegistry().findFromByAlias(identifierText, true);
if (sqmFrom != null) {
if (definedCollate) {
// This is syntactically disallowed
throw new ParsingException("COLLATE is not allowed for alias based order-by or group-by items");
}
// this will group-by all of the sub-parts in the from-element's model part
return sqmFrom;
}
final DotIdentifierConsumer dotIdentifierConsumer = dotIdentifierConsumerStack.getCurrent();
dotIdentifierConsumer.consumeIdentifier(identifierText, true, true);
return (SqmExpression<?>) dotIdentifierConsumer.getConsumedPart();
}
return (SqmExpression<?>) child.accept(this);
}
use of org.hibernate.query.sqm.tree.expression.SqmAliasedNodeRef in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method resolveGroupOrOrderByExpression.
protected Expression resolveGroupOrOrderByExpression(SqmExpression<?> groupByClauseExpression) {
final int sqmPosition;
if (groupByClauseExpression instanceof SqmAliasedNodeRef) {
final int aliasedNodeOrdinal = ((SqmAliasedNodeRef) groupByClauseExpression).getPosition();
sqmPosition = aliasedNodeOrdinal - 1;
} else if (statement.getQuerySource() == SqmQuerySource.CRITERIA) {
// In JPA Criteria we could be using the same expression object for the group/order by and select item
// We try to find the select item position for this expression here which is not necessarily just an optimization.
// This is vital to enable the support for parameters in these expressions.
// Databases usually don't know if a parameter marker will have the same value as another parameter marker
// and due to that, a database usually complains when seeing something like
// `select ?, count(*) from dual group by ?` saying that there is a missing group by for the first `?`
// To avoid this issue, we determine the position and let the SqlAstTranslator handle the rest.
// Usually it will render `select ?, count(*) from dual group by 1` if supported
// or force rendering the parameter as literal instead so that the database can see the grouping is fine
final SqmQuerySpec<?> querySpec = currentSqmQueryPart.getFirstQuerySpec();
sqmPosition = indexOfExpression(querySpec.getSelectClause().getSelections(), groupByClauseExpression);
} else {
sqmPosition = -1;
}
if (sqmPosition != -1) {
final List<SqlSelection> selections = currentSqlSelectionCollector().getSelections(sqmPosition);
assert selections != null : String.format(Locale.ROOT, "No SqlSelections for SQM position `%s`", sqmPosition);
final List<Expression> expressions = new ArrayList<>(selections.size());
OUTER: for (int i = 0; i < selections.size(); i++) {
final SqlSelection selection = selections.get(i);
// which is, just like the identifier itself, also registered as selection
for (int j = 0; j < i; j++) {
if (selections.get(j) == selection) {
continue OUTER;
}
}
if (currentSqmQueryPart instanceof SqmQueryGroup<?>) {
// Reusing the SqlSelection for query groups would be wrong because the aliases do no exist
// So we have to use a literal expression in a new SqlSelection instance to refer to the position
expressions.add(new SqlSelectionExpression(new SqlSelectionImpl(selection.getJdbcResultSetIndex(), selection.getValuesArrayPosition(), new QueryLiteral<>(selection.getValuesArrayPosition(), basicType(Integer.class)))));
} else {
expressions.add(new SqlSelectionExpression(selection));
}
}
if (expressions.size() == 1) {
return expressions.get(0);
}
return new SqlTuple(expressions, null);
}
return (Expression) groupByClauseExpression.accept(this);
}
Aggregations