Search in sources :

Example 1 with QueryGroup

use of org.hibernate.sql.ast.tree.select.QueryGroup in project hibernate-orm by hibernate.

the class AbstractSqlAstTranslator method visitQuerySpec.

@Override
public void visitQuerySpec(QuerySpec querySpec) {
    final QueryPart queryPartForRowNumbering = this.queryPartForRowNumbering;
    final int queryPartForRowNumberingClauseDepth = this.queryPartForRowNumberingClauseDepth;
    final boolean needsSelectAliases = this.needsSelectAliases;
    final Predicate additionalWherePredicate = this.additionalWherePredicate;
    final ForUpdateClause forUpdate = this.forUpdate;
    try {
        this.additionalWherePredicate = null;
        this.forUpdate = null;
        // See the field documentation of queryPartForRowNumbering etc. for an explanation about this
        // In addition, we also reset the row numbering if the currently row numbered query part is a query group
        // which means this query spec is a part of that query group.
        // We want the row numbering to happen on the query group level, not on the query spec level, so we reset
        final QueryPart currentQueryPart = queryPartStack.getCurrent();
        if (currentQueryPart != null && (queryPartForRowNumbering instanceof QueryGroup || queryPartForRowNumberingClauseDepth != clauseStack.depth())) {
            this.queryPartForRowNumbering = null;
            this.queryPartForRowNumberingClauseDepth = -1;
        }
        String queryGroupAlias = "";
        final boolean needsParenthesis;
        if (currentQueryPart instanceof QueryGroup) {
            // We always need query wrapping if we are in a query group and this query spec has a fetch clause
            // because of order by precedence in SQL
            needsParenthesis = querySpec.hasOffsetOrFetchClause();
            if (needsParenthesis) {
                // or if the database does not support simple query grouping, we must use a select wrapper
                if (!supportsSimpleQueryGrouping() || currentQueryPart.hasOffsetOrFetchClause()) {
                    queryGroupAlias = " grp_" + queryGroupAliasCounter + '_';
                    queryGroupAliasCounter++;
                    appendSql("select");
                    appendSql(queryGroupAlias);
                    appendSql(".* from ");
                }
            }
        } else {
            needsParenthesis = !querySpec.isRoot();
        }
        queryPartStack.push(querySpec);
        if (needsParenthesis) {
            appendSql(OPEN_PARENTHESIS);
        }
        visitSelectClause(querySpec.getSelectClause());
        visitFromClause(querySpec.getFromClause());
        visitWhereClause(querySpec.getWhereClauseRestrictions());
        visitGroupByClause(querySpec, getDialect().getGroupBySelectItemReferenceStrategy());
        visitHavingClause(querySpec);
        visitOrderBy(querySpec.getSortSpecifications());
        visitOffsetFetchClause(querySpec);
        // We render the FOR UPDATE clause in the parent query
        if (queryPartForRowNumbering == null) {
            visitForUpdateClause(querySpec);
        }
        if (needsParenthesis) {
            appendSql(CLOSE_PARENTHESIS);
            appendSql(queryGroupAlias);
        }
    } finally {
        this.queryPartStack.pop();
        this.queryPartForRowNumbering = queryPartForRowNumbering;
        this.queryPartForRowNumberingClauseDepth = queryPartForRowNumberingClauseDepth;
        this.needsSelectAliases = needsSelectAliases;
        this.additionalWherePredicate = additionalWherePredicate;
        if (queryPartForRowNumbering == null) {
            this.forUpdate = forUpdate;
        }
    }
}
Also used : QueryPart(org.hibernate.sql.ast.tree.select.QueryPart) QueryGroup(org.hibernate.sql.ast.tree.select.QueryGroup) SqlFragmentPredicate(org.hibernate.persister.internal.SqlFragmentPredicate) InSubQueryPredicate(org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate) SelfRenderingPredicate(org.hibernate.sql.ast.tree.predicate.SelfRenderingPredicate) FilterPredicate(org.hibernate.sql.ast.tree.predicate.FilterPredicate) NegatedPredicate(org.hibernate.sql.ast.tree.predicate.NegatedPredicate) LikePredicate(org.hibernate.sql.ast.tree.predicate.LikePredicate) ComparisonPredicate(org.hibernate.sql.ast.tree.predicate.ComparisonPredicate) BetweenPredicate(org.hibernate.sql.ast.tree.predicate.BetweenPredicate) NullnessPredicate(org.hibernate.sql.ast.tree.predicate.NullnessPredicate) GroupedPredicate(org.hibernate.sql.ast.tree.predicate.GroupedPredicate) BooleanExpressionPredicate(org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate) ExistsPredicate(org.hibernate.sql.ast.tree.predicate.ExistsPredicate) InListPredicate(org.hibernate.sql.ast.tree.predicate.InListPredicate) Predicate(org.hibernate.sql.ast.tree.predicate.Predicate)

Example 2 with QueryGroup

use of org.hibernate.sql.ast.tree.select.QueryGroup in project hibernate-orm by hibernate.

the class AbstractSqlAstTranslator method visitRelationalPredicate.

@Override
public void visitRelationalPredicate(ComparisonPredicate comparisonPredicate) {
    // todo (6.0) : do we want to allow multi-valued parameters in a relational predicate?
    // yes means we'd have to support dynamically converting this predicate into
    // an IN predicate or an OR predicate
    // 
    // NOTE: JPA does not define support for multi-valued parameters here.
    // 
    // If we decide to support that ^^  we should validate that *both* sides of the
    // predicate are multi-valued parameters.  because...
    // well... its stupid :)
    final SqlTuple lhsTuple;
    final SqlTuple rhsTuple;
    if ((lhsTuple = SqlTupleContainer.getSqlTuple(comparisonPredicate.getLeftHandExpression())) != null) {
        final Expression rhsExpression = comparisonPredicate.getRightHandExpression();
        final boolean all;
        final QueryPart subquery;
        // Handle emulation of quantified comparison
        if (rhsExpression instanceof QueryPart) {
            subquery = (QueryPart) rhsExpression;
            all = true;
        } else if (rhsExpression instanceof Every) {
            subquery = ((Every) rhsExpression).getSubquery();
            all = true;
        } else if (rhsExpression instanceof Any) {
            subquery = ((Any) rhsExpression).getSubquery();
            all = false;
        } else {
            subquery = null;
            all = false;
        }
        final ComparisonOperator operator = comparisonPredicate.getOperator();
        if (lhsTuple.getExpressions().size() == 1) {
            // Special case for tuples with arity 1 as any DBMS supports scalar IN predicates
            if (subquery == null) {
                renderComparison(lhsTuple.getExpressions().get(0), operator, SqlTupleContainer.getSqlTuple(comparisonPredicate.getRightHandExpression()).getExpressions().get(0));
            } else {
                renderComparison(lhsTuple.getExpressions().get(0), operator, rhsExpression);
            }
        } else if (subquery != null && !supportsRowValueConstructorSyntaxInQuantifiedPredicates()) {
            // For quantified relational comparisons, we can do an optimized emulation
            if (supportsRowValueConstructorSyntax() && all) {
                switch(operator) {
                    case LESS_THAN:
                    case LESS_THAN_OR_EQUAL:
                    case GREATER_THAN:
                    case GREATER_THAN_OR_EQUAL:
                        {
                            emulateQuantifiedTupleSubQueryPredicate(comparisonPredicate, subquery, lhsTuple, operator);
                            return;
                        }
                }
            }
            emulateSubQueryRelationalRestrictionPredicate(comparisonPredicate, all, subquery, lhsTuple, this::renderSelectTupleComparison, all ? operator.negated() : operator);
        } else if (!supportsRowValueConstructorSyntax()) {
            rhsTuple = SqlTupleContainer.getSqlTuple(rhsExpression);
            assert rhsTuple != null;
            // Some DBs like Oracle support tuples only for the IN subquery predicate
            if ((operator == ComparisonOperator.EQUAL || operator == ComparisonOperator.NOT_EQUAL) && supportsRowValueConstructorSyntaxInInSubQuery()) {
                comparisonPredicate.getLeftHandExpression().accept(this);
                if (operator == ComparisonOperator.NOT_EQUAL) {
                    appendSql(" not");
                }
                appendSql(" in(");
                renderExpressionsAsSubquery(rhsTuple.getExpressions());
                appendSql(CLOSE_PARENTHESIS);
            } else {
                emulateTupleComparison(lhsTuple.getExpressions(), rhsTuple.getExpressions(), operator, true);
            }
        } else {
            renderComparison(comparisonPredicate.getLeftHandExpression(), operator, rhsExpression);
        }
    } else if ((rhsTuple = SqlTupleContainer.getSqlTuple(comparisonPredicate.getRightHandExpression())) != null) {
        final Expression lhsExpression = comparisonPredicate.getLeftHandExpression();
        if (lhsExpression instanceof QueryGroup) {
            if (rhsTuple.getExpressions().size() == 1) {
                // Special case for tuples with arity 1 as any DBMS supports scalar IN predicates
                renderComparison(lhsExpression, comparisonPredicate.getOperator(), rhsTuple.getExpressions().get(0));
            } else if (supportsRowValueConstructorSyntax()) {
                renderComparison(lhsExpression, comparisonPredicate.getOperator(), comparisonPredicate.getRightHandExpression());
            } else {
                emulateSubQueryRelationalRestrictionPredicate(comparisonPredicate, false, (QueryGroup) lhsExpression, rhsTuple, this::renderSelectTupleComparison, // Since we switch the order of operands, we have to invert the operator
                comparisonPredicate.getOperator().invert());
            }
        } else {
            throw new IllegalStateException("Unsupported tuple comparison combination. LHS is neither a tuple nor a tuple subquery but RHS is a tuple: " + comparisonPredicate);
        }
    } else {
        renderComparison(comparisonPredicate.getLeftHandExpression(), comparisonPredicate.getOperator(), comparisonPredicate.getRightHandExpression());
    }
}
Also used : ComparisonOperator(org.hibernate.query.sqm.ComparisonOperator) Expression(org.hibernate.sql.ast.tree.expression.Expression) BinaryArithmeticExpression(org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression) SelfRenderingExpression(org.hibernate.sql.ast.tree.expression.SelfRenderingExpression) OrderedSetAggregateFunctionExpression(org.hibernate.sql.ast.tree.expression.OrderedSetAggregateFunctionExpression) CaseSimpleExpression(org.hibernate.sql.ast.tree.expression.CaseSimpleExpression) SqlSelectionExpression(org.hibernate.sql.ast.tree.expression.SqlSelectionExpression) CaseSearchedExpression(org.hibernate.sql.ast.tree.expression.CaseSearchedExpression) ModifiedSubQueryExpression(org.hibernate.sql.ast.tree.expression.ModifiedSubQueryExpression) QueryPart(org.hibernate.sql.ast.tree.select.QueryPart) Every(org.hibernate.sql.ast.tree.expression.Every) SqlTuple(org.hibernate.sql.ast.tree.expression.SqlTuple) Any(org.hibernate.sql.ast.tree.expression.Any) QueryGroup(org.hibernate.sql.ast.tree.select.QueryGroup)

Example 3 with QueryGroup

use of org.hibernate.sql.ast.tree.select.QueryGroup in project hibernate-orm by hibernate.

the class BaseSqmToSqlAstConverter method visitQueryGroup.

@Override
public QueryGroup visitQueryGroup(SqmQueryGroup<?> queryGroup) {
    final List<? extends SqmQueryPart<?>> queryParts = queryGroup.getQueryParts();
    final int size = queryParts.size();
    final List<QueryPart> newQueryParts = new ArrayList<>(size);
    final QueryGroup group = new QueryGroup(getProcessingStateStack().isEmpty(), queryGroup.getSetOperator(), newQueryParts);
    if (queryGroup.getOrderByClause() != null && queryGroup.getOrderByClause().hasPositionalSortItem()) {
        trackSelectionsForGroup = true;
    }
    final SqlAstQueryPartProcessingStateImpl processingState = new SqlAstQueryPartProcessingStateImpl(group, getCurrentProcessingState(), this, DelegatingSqmAliasedNodeCollector::new, currentClauseStack::getCurrent, deduplicateSelectionItems);
    final DelegatingSqmAliasedNodeCollector collector = (DelegatingSqmAliasedNodeCollector) processingState.getSqlExpressionResolver();
    final SqmQueryPart<?> sqmQueryPart = currentSqmQueryPart;
    currentSqmQueryPart = queryGroup;
    pushProcessingState(processingState);
    try {
        newQueryParts.add(visitQueryPart(queryParts.get(0)));
        collector.setSqmAliasedNodeCollector((SqmAliasedNodeCollector) lastPoppedProcessingState.getSqlExpressionResolver());
        visitOrderByOffsetAndFetch(queryGroup, group);
        trackSelectionsForGroup = false;
        for (int i = 1; i < size; i++) {
            newQueryParts.add(visitQueryPart(queryParts.get(i)));
        }
        return group;
    } finally {
        popProcessingStateStack();
        currentSqmQueryPart = sqmQueryPart;
    }
}
Also used : SqlAstQueryPartProcessingStateImpl(org.hibernate.query.sqm.sql.internal.SqlAstQueryPartProcessingStateImpl) SqmQueryPart(org.hibernate.query.sqm.tree.select.SqmQueryPart) QueryPart(org.hibernate.sql.ast.tree.select.QueryPart) ArrayList(java.util.ArrayList) QueryGroup(org.hibernate.sql.ast.tree.select.QueryGroup) SqmQueryGroup(org.hibernate.query.sqm.tree.select.SqmQueryGroup)

Example 4 with QueryGroup

use of org.hibernate.sql.ast.tree.select.QueryGroup in project hibernate-orm by hibernate.

the class OracleSqlAstTranslator method emulateFetchOffsetWithWindowFunctions.

@Override
protected void emulateFetchOffsetWithWindowFunctions(QueryPart queryPart, Expression offsetExpression, Expression fetchExpression, FetchClauseType fetchClauseType, boolean emulateFetchClause) {
    if (queryPart instanceof QuerySpec && offsetExpression == null && fetchClauseType == FetchClauseType.ROWS_ONLY) {
        // Special case for Oracle to support locking along with simple max results paging
        final QuerySpec querySpec = (QuerySpec) queryPart;
        withRowNumbering(querySpec, // we need select aliases to avoid ORA-00918: column ambiguously defined
        true, () -> {
            final QueryPart currentQueryPart = getQueryPartStack().getCurrent();
            final boolean needsParenthesis;
            final boolean needsWrapper;
            if (currentQueryPart instanceof QueryGroup) {
                needsParenthesis = false;
                // visitQuerySpec will add the select wrapper
                needsWrapper = !currentQueryPart.hasOffsetOrFetchClause();
            } else {
                needsParenthesis = !querySpec.isRoot();
                needsWrapper = true;
            }
            if (needsWrapper) {
                if (needsParenthesis) {
                    appendSql('(');
                }
                appendSql("select * from ");
                if (!needsParenthesis) {
                    appendSql('(');
                }
            }
            super.visitQuerySpec(querySpec);
            if (needsWrapper) {
                if (!needsParenthesis) {
                    appendSql(')');
                }
            }
            appendSql(" where rownum<=");
            final Stack<Clause> clauseStack = getClauseStack();
            clauseStack.push(Clause.WHERE);
            try {
                fetchExpression.accept(this);
                // We render the FOR UPDATE clause in the outer query
                clauseStack.pop();
                clauseStack.push(Clause.FOR_UPDATE);
                visitForUpdateClause(querySpec);
            } finally {
                clauseStack.pop();
            }
            if (needsWrapper) {
                if (needsParenthesis) {
                    appendSql(')');
                }
            }
        });
    } else {
        super.emulateFetchOffsetWithWindowFunctions(queryPart, offsetExpression, fetchExpression, fetchClauseType, emulateFetchClause);
    }
}
Also used : QueryPart(org.hibernate.sql.ast.tree.select.QueryPart) Clause(org.hibernate.sql.ast.Clause) SelectClause(org.hibernate.sql.ast.tree.select.SelectClause) QuerySpec(org.hibernate.sql.ast.tree.select.QuerySpec) QueryGroup(org.hibernate.sql.ast.tree.select.QueryGroup)

Example 5 with QueryGroup

use of org.hibernate.sql.ast.tree.select.QueryGroup in project hibernate-orm by hibernate.

the class AbstractSqlAstTranslator method determineLateralEmulationPredicate.

protected Predicate determineLateralEmulationPredicate(TableGroup tableGroup) {
    if (tableGroup.getPrimaryTableReference() instanceof QueryPartTableReference) {
        final QueryPartTableReference tableReference = (QueryPartTableReference) tableGroup.getPrimaryTableReference();
        final List<String> columnNames = tableReference.getColumnNames();
        final List<ColumnReference> columnReferences = new ArrayList<>(columnNames.size());
        final List<ColumnReference> subColumnReferences = new ArrayList<>(columnNames.size());
        final QueryPart queryPart = tableReference.getQueryPart();
        for (String columnName : columnNames) {
            columnReferences.add(new ColumnReference(tableReference, columnName, false, null, null, null, sessionFactory));
        }
        // The following optimization only makes sense if the necessary features are supported natively
        if ((columnReferences.size() == 1 || supportsRowValueConstructorSyntax()) && supportsDistinctFromPredicate()) {
            // ... x(c) on x.c is not distinct from (... fetch first 1 rows only)
            if (queryPart.getFetchClauseType() == FetchClauseType.ROWS_ONLY && queryPart.getFetchClauseExpression() instanceof QueryLiteral<?> && Integer.valueOf(1).equals(((QueryLiteral<?>) queryPart.getFetchClauseExpression()).getLiteralValue())) {
                return new ComparisonPredicate(new SqlTuple(columnReferences, tableGroup.getModelPart()), ComparisonOperator.NOT_DISTINCT_FROM, queryPart);
            }
        }
        // ... x(c) on exists(select x.c intersect ...)
        if (supportsIntersect()) {
            final QuerySpec lhsReferencesQuery = new QuerySpec(false);
            for (ColumnReference columnReference : columnReferences) {
                lhsReferencesQuery.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, columnReference));
            }
            final List<QueryPart> queryParts = new ArrayList<>(2);
            queryParts.add(lhsReferencesQuery);
            queryParts.add(queryPart);
            return new ExistsPredicate(new QueryGroup(false, SetOperator.INTERSECT, queryParts), false, getBooleanType());
        }
        // Double nested sub-query rendering if nothing else works
        // We try to avoid this as much as possible as it is not very efficient and some DBs don't like it
        // when a correlation happens in a sub-query that is not a direct child
        // ... x(c) on exists(select 1 from (...) synth_(c) where x.c = synth_.c)
        final QueryPartTableGroup subTableGroup = new QueryPartTableGroup(tableGroup.getNavigablePath(), (TableGroupProducer) tableGroup.getModelPart(), queryPart, "synth_", columnNames, false, true, sessionFactory);
        for (String columnName : columnNames) {
            subColumnReferences.add(new ColumnReference(subTableGroup.getPrimaryTableReference(), columnName, false, null, null, null, sessionFactory));
        }
        final QuerySpec existsQuery = new QuerySpec(false, 1);
        existsQuery.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, new QueryLiteral<>(1, getIntegerType())));
        existsQuery.getFromClause().addRoot(subTableGroup);
        existsQuery.applyPredicate(new ComparisonPredicate(new SqlTuple(columnReferences, tableGroup.getModelPart()), ComparisonOperator.NOT_DISTINCT_FROM, new SqlTuple(subColumnReferences, tableGroup.getModelPart())));
        return new ExistsPredicate(existsQuery, false, getBooleanType());
    }
    return null;
}
Also used : QueryPart(org.hibernate.sql.ast.tree.select.QueryPart) ExistsPredicate(org.hibernate.sql.ast.tree.predicate.ExistsPredicate) ArrayList(java.util.ArrayList) QueryPartTableGroup(org.hibernate.sql.ast.tree.from.QueryPartTableGroup) ComparisonPredicate(org.hibernate.sql.ast.tree.predicate.ComparisonPredicate) QueryGroup(org.hibernate.sql.ast.tree.select.QueryGroup) ConvertedQueryLiteral(org.hibernate.sql.ast.tree.expression.ConvertedQueryLiteral) QueryLiteral(org.hibernate.sql.ast.tree.expression.QueryLiteral) SqlTuple(org.hibernate.sql.ast.tree.expression.SqlTuple) SqlSelectionImpl(org.hibernate.sql.results.internal.SqlSelectionImpl) QuerySpec(org.hibernate.sql.ast.tree.select.QuerySpec) QueryPartTableReference(org.hibernate.sql.ast.tree.from.QueryPartTableReference) ColumnReference(org.hibernate.sql.ast.tree.expression.ColumnReference)

Aggregations

QueryGroup (org.hibernate.sql.ast.tree.select.QueryGroup)8 QueryPart (org.hibernate.sql.ast.tree.select.QueryPart)7 ArrayList (java.util.ArrayList)4 ComparisonPredicate (org.hibernate.sql.ast.tree.predicate.ComparisonPredicate)4 ExistsPredicate (org.hibernate.sql.ast.tree.predicate.ExistsPredicate)4 QuerySpec (org.hibernate.sql.ast.tree.select.QuerySpec)4 Clause (org.hibernate.sql.ast.Clause)3 BinaryArithmeticExpression (org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression)3 CaseSearchedExpression (org.hibernate.sql.ast.tree.expression.CaseSearchedExpression)3 CaseSimpleExpression (org.hibernate.sql.ast.tree.expression.CaseSimpleExpression)3 ConvertedQueryLiteral (org.hibernate.sql.ast.tree.expression.ConvertedQueryLiteral)3 Expression (org.hibernate.sql.ast.tree.expression.Expression)3 ModifiedSubQueryExpression (org.hibernate.sql.ast.tree.expression.ModifiedSubQueryExpression)3 QueryLiteral (org.hibernate.sql.ast.tree.expression.QueryLiteral)3 SelfRenderingExpression (org.hibernate.sql.ast.tree.expression.SelfRenderingExpression)3 SqlSelectionExpression (org.hibernate.sql.ast.tree.expression.SqlSelectionExpression)3 SqlTuple (org.hibernate.sql.ast.tree.expression.SqlTuple)3 BetweenPredicate (org.hibernate.sql.ast.tree.predicate.BetweenPredicate)3 BooleanExpressionPredicate (org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate)3 GroupedPredicate (org.hibernate.sql.ast.tree.predicate.GroupedPredicate)3