use of org.hibernate.sql.ast.tree.select.QueryGroup in project hibernate-orm by hibernate.
the class AbstractSqlAstTranslator method emulateFetchOffsetWithWindowFunctions.
protected void emulateFetchOffsetWithWindowFunctions(QueryPart queryPart, Expression offsetExpression, Expression fetchExpression, FetchClauseType fetchClauseType, boolean emulateFetchClause) {
final QueryPart queryPartForRowNumbering = this.queryPartForRowNumbering;
final int queryPartForRowNumberingClauseDepth = this.queryPartForRowNumberingClauseDepth;
final boolean needsSelectAliases = this.needsSelectAliases;
try {
this.queryPartForRowNumbering = queryPart;
this.queryPartForRowNumberingClauseDepth = clauseStack.depth();
this.needsSelectAliases = true;
final String alias = "r_" + queryPartForRowNumberingAliasCounter + '_';
queryPartForRowNumberingAliasCounter++;
final boolean needsParenthesis;
if (queryPart instanceof QueryGroup) {
// We always need query wrapping if we are in a query group and the query part has a fetch clause
needsParenthesis = queryPart.hasOffsetOrFetchClause();
} else {
needsParenthesis = !queryPart.isRoot();
}
if (needsParenthesis && !queryPart.isRoot()) {
appendSql(OPEN_PARENTHESIS);
}
appendSql("select ");
if (getClauseStack().isEmpty()) {
appendSql('*');
} else {
final int size = queryPart.getFirstQuerySpec().getSelectClause().getSqlSelections().size();
String separator = "";
for (int i = 0; i < size; i++) {
appendSql(separator);
appendSql(alias);
appendSql(".c");
appendSql(i);
separator = COMA_SEPARATOR;
}
}
appendSql(" from ");
if (!needsParenthesis || queryPart.isRoot()) {
appendSql(OPEN_PARENTHESIS);
}
queryPart.accept(this);
if (!needsParenthesis || queryPart.isRoot()) {
appendSql(CLOSE_PARENTHESIS);
}
appendSql(WHITESPACE);
appendSql(alias);
appendSql(" where ");
final Stack<Clause> clauseStack = getClauseStack();
clauseStack.push(Clause.WHERE);
try {
if (emulateFetchClause && fetchExpression != null) {
switch(fetchClauseType) {
case PERCENT_ONLY:
appendSql(alias);
appendSql(".rn<=");
if (offsetExpression != null) {
offsetExpression.accept(this);
appendSql('+');
}
appendSql("ceil(");
appendSql(alias);
appendSql(".cnt*");
fetchExpression.accept(this);
appendSql("/100)");
break;
case ROWS_ONLY:
appendSql(alias);
appendSql(".rn<=");
if (offsetExpression != null) {
offsetExpression.accept(this);
appendSql('+');
}
fetchExpression.accept(this);
break;
case PERCENT_WITH_TIES:
appendSql(alias);
appendSql(".rnk<=");
if (offsetExpression != null) {
offsetExpression.accept(this);
appendSql('+');
}
appendSql("ceil(");
appendSql(alias);
appendSql(".cnt*");
fetchExpression.accept(this);
appendSql("/100)");
break;
case ROWS_WITH_TIES:
appendSql(alias);
appendSql(".rnk<=");
if (offsetExpression != null) {
offsetExpression.accept(this);
appendSql('+');
}
fetchExpression.accept(this);
break;
}
}
// todo: not sure if databases handle order by row number or the original ordering better..
if (offsetExpression == null) {
final Predicate additionalWherePredicate = this.additionalWherePredicate;
if (additionalWherePredicate != null && !additionalWherePredicate.isEmpty()) {
this.additionalWherePredicate = null;
appendSql(" and ");
additionalWherePredicate.accept(this);
}
if (queryPart.isRoot()) {
switch(fetchClauseType) {
case PERCENT_ONLY:
case ROWS_ONLY:
appendSql(" order by ");
appendSql(alias);
appendSql(".rn");
break;
case PERCENT_WITH_TIES:
case ROWS_WITH_TIES:
appendSql(" order by ");
appendSql(alias);
appendSql(".rnk");
break;
}
}
} else {
if (emulateFetchClause && fetchExpression != null) {
appendSql(" and ");
}
appendSql(alias);
appendSql(".rn>");
offsetExpression.accept(this);
final Predicate additionalWherePredicate = this.additionalWherePredicate;
if (additionalWherePredicate != null && !additionalWherePredicate.isEmpty()) {
this.additionalWherePredicate = null;
appendSql(" and ");
additionalWherePredicate.accept(this);
}
if (queryPart.isRoot()) {
appendSql(" order by ");
appendSql(alias);
appendSql(".rn");
}
}
// We render the FOR UPDATE clause in the outer query
if (queryPart instanceof QuerySpec) {
clauseStack.pop();
clauseStack.push(Clause.FOR_UPDATE);
visitForUpdateClause((QuerySpec) queryPart);
}
} finally {
clauseStack.pop();
}
if (needsParenthesis && !queryPart.isRoot()) {
appendSql(CLOSE_PARENTHESIS);
}
} finally {
this.queryPartForRowNumbering = queryPartForRowNumbering;
this.queryPartForRowNumberingClauseDepth = queryPartForRowNumberingClauseDepth;
this.needsSelectAliases = needsSelectAliases;
}
}
use of org.hibernate.sql.ast.tree.select.QueryGroup in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method visitSelection.
@Override
public Void visitSelection(SqmSelection<?> sqmSelection) {
final List<Map.Entry<String, DomainResultProducer<?>>> resultProducers;
final SqmSelectableNode<?> selectionNode = sqmSelection.getSelectableNode();
if (selectionNode instanceof SqmJpaCompoundSelection<?>) {
final SqmJpaCompoundSelection<?> selectableNode = (SqmJpaCompoundSelection<?>) selectionNode;
resultProducers = new ArrayList<>(selectableNode.getSelectionItems().size());
for (SqmSelectableNode<?> selectionItem : selectableNode.getSelectionItems()) {
if (selectionItem instanceof SqmPath<?>) {
prepareForSelection((SqmPath<?>) selectionItem);
}
resultProducers.add(new AbstractMap.SimpleEntry<>(selectionItem.getAlias(), (DomainResultProducer<?>) selectionItem.accept(this)));
}
} else {
if (selectionNode instanceof SqmPath<?>) {
prepareForSelection((SqmPath<?>) selectionNode);
}
resultProducers = Collections.singletonList(new AbstractMap.SimpleEntry<>(sqmSelection.getAlias(), (DomainResultProducer<?>) selectionNode.accept(this)));
}
final Stack<SqlAstProcessingState> processingStateStack = getProcessingStateStack();
final boolean needsDomainResults = domainResults != null && currentClauseContributesToTopLevelSelectClause();
final boolean collectDomainResults;
if (processingStateStack.depth() == 1) {
collectDomainResults = needsDomainResults;
} else {
final SqlAstProcessingState current = processingStateStack.getCurrent();
// Since we only want to create domain results for the first/left-most query spec within query groups,
// we have to check if the current query spec is the left-most.
// This is the case when all upper level in-flight query groups are still empty
collectDomainResults = needsDomainResults && processingStateStack.findCurrentFirst(processingState -> {
if (!(processingState instanceof SqlAstQueryPartProcessingState)) {
return Boolean.FALSE;
}
if (processingState == current) {
return null;
}
final QueryPart part = ((SqlAstQueryPartProcessingState) processingState).getInflightQueryPart();
if (part instanceof QueryGroup) {
if (((QueryGroup) part).getQueryParts().isEmpty()) {
return null;
}
}
return Boolean.FALSE;
}) == null;
}
// arguments
if (collectDomainResults) {
resultProducers.forEach(entry -> {
if (!(entry.getValue() instanceof DynamicInstantiation<?>)) {
currentSqlSelectionCollector().next();
}
domainResults.add(entry.getValue().createDomainResult(entry.getKey(), this));
});
} else if (needsDomainResults) {
// We just create domain results for the purpose of creating selections
// This is necessary for top-level query specs within query groups to avoid cycles
resultProducers.forEach(entry -> {
if (!(entry.getValue() instanceof DynamicInstantiation<?>)) {
currentSqlSelectionCollector().next();
}
entry.getValue().createDomainResult(entry.getKey(), this);
});
} else {
resultProducers.forEach(entry -> {
if (!(entry.getValue() instanceof DynamicInstantiation<?>)) {
currentSqlSelectionCollector().next();
}
entry.getValue().applySqlSelections(this);
});
}
return null;
}
use of org.hibernate.sql.ast.tree.select.QueryGroup in project hibernate-orm by hibernate.
the class AbstractSqlAstTranslator method getSortSpecificationsRowNumbering.
protected List<SortSpecification> getSortSpecificationsRowNumbering(SelectClause selectClause, QueryPart queryPart) {
final List<SortSpecification> sortSpecifications;
if (queryPart.hasSortSpecifications()) {
sortSpecifications = queryPart.getSortSpecifications();
} else {
sortSpecifications = Collections.emptyList();
}
if (selectClause.isDistinct()) {
// When select distinct is used, we need to add all select items to the order by clause
final List<SqlSelection> sqlSelections = new ArrayList<>(selectClause.getSqlSelections());
final int specificationsSize = sortSpecifications.size();
for (int i = sqlSelections.size() - 1; i != 0; i--) {
final Expression selectionExpression = sqlSelections.get(i).getExpression();
for (int j = 0; j < specificationsSize; j++) {
final Expression expression = resolveAliasedExpression(sqlSelections, sortSpecifications.get(j).getSortExpression());
if (expression.equals(selectionExpression)) {
sqlSelections.remove(i);
break;
}
}
}
final int sqlSelectionsSize = sqlSelections.size();
if (sqlSelectionsSize == 0) {
return sortSpecifications;
} else {
final List<SortSpecification> sortSpecificationsRowNumbering = new ArrayList<>(sqlSelectionsSize + specificationsSize);
sortSpecificationsRowNumbering.addAll(sortSpecifications);
for (int i = 0; i < sqlSelectionsSize; i++) {
sortSpecificationsRowNumbering.add(new SortSpecification(new SqlSelectionExpression(sqlSelections.get(i)), SortOrder.ASCENDING, NullPrecedence.NONE));
}
return sortSpecificationsRowNumbering;
}
} else if (queryPart instanceof QueryGroup) {
// When the sort specifications come from a query group which uses positional references
// we have to resolve to the actual selection expressions
final int specificationsSize = sortSpecifications.size();
final List<SortSpecification> sortSpecificationsRowNumbering = new ArrayList<>(specificationsSize);
final List<SqlSelection> sqlSelections = selectClause.getSqlSelections();
for (int i = 0; i < specificationsSize; i++) {
final SortSpecification sortSpecification = sortSpecifications.get(i);
final int position;
if (sortSpecification.getSortExpression() instanceof SqlSelectionExpression) {
position = ((SqlSelectionExpression) sortSpecification.getSortExpression()).getSelection().getValuesArrayPosition();
} else {
assert sortSpecification.getSortExpression() instanceof QueryLiteral;
final QueryLiteral<?> queryLiteral = (QueryLiteral<?>) sortSpecification.getSortExpression();
assert queryLiteral.getLiteralValue() instanceof Integer;
position = (Integer) queryLiteral.getLiteralValue();
}
sortSpecificationsRowNumbering.add(new SortSpecification(new SqlSelectionExpression(sqlSelections.get(position)), sortSpecification.getSortOrder(), sortSpecification.getNullPrecedence()));
}
return sortSpecificationsRowNumbering;
} else {
return sortSpecifications;
}
}
Aggregations