Search in sources :

Example 1 with QueryPart

use of org.hibernate.sql.ast.tree.select.QueryPart 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 QueryPart

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

the class AbstractSqlAstTranslator method emulateSubQueryRelationalRestrictionPredicate.

protected <X extends Expression> void emulateSubQueryRelationalRestrictionPredicate(Predicate predicate, boolean negated, QueryPart queryPart, X lhsTuple, SubQueryRelationalRestrictionEmulationRenderer<X> renderer, ComparisonOperator tupleComparisonOperator) {
    final QuerySpec subQuery;
    if (queryPart instanceof QuerySpec && queryPart.getFetchClauseExpression() == null && queryPart.getOffsetClauseExpression() == null) {
        subQuery = (QuerySpec) queryPart;
        // We can only emulate the tuple sub query predicate as exists predicate when there are no limit/offsets
        if (negated) {
            appendSql("not ");
        }
        final QueryPart queryPartForRowNumbering = this.queryPartForRowNumbering;
        final int queryPartForRowNumberingClauseDepth = this.queryPartForRowNumberingClauseDepth;
        final boolean needsSelectAliases = this.needsSelectAliases;
        try {
            this.queryPartForRowNumbering = null;
            this.queryPartForRowNumberingClauseDepth = -1;
            this.needsSelectAliases = false;
            queryPartStack.push(subQuery);
            appendSql("exists (select 1");
            visitFromClause(subQuery.getFromClause());
            if (!subQuery.getGroupByClauseExpressions().isEmpty() || subQuery.getHavingClauseRestrictions() != null) {
                // If we have a group by or having clause, we have to move the tuple comparison emulation to the HAVING clause
                visitWhereClause(subQuery.getWhereClauseRestrictions());
                visitGroupByClause(subQuery, SelectItemReferenceStrategy.EXPRESSION);
                appendSql(" having ");
                clauseStack.push(Clause.HAVING);
                try {
                    renderer.renderComparison(subQuery.getSelectClause().getSqlSelections(), lhsTuple, tupleComparisonOperator);
                    final Predicate havingClauseRestrictions = subQuery.getHavingClauseRestrictions();
                    if (havingClauseRestrictions != null) {
                        appendSql(" and (");
                        havingClauseRestrictions.accept(this);
                        appendSql(CLOSE_PARENTHESIS);
                    }
                } finally {
                    clauseStack.pop();
                }
            } else {
                // If we have no group by or having clause, we can move the tuple comparison emulation to the WHERE clause
                appendSql(" where ");
                clauseStack.push(Clause.WHERE);
                try {
                    renderer.renderComparison(subQuery.getSelectClause().getSqlSelections(), lhsTuple, tupleComparisonOperator);
                    final Predicate whereClauseRestrictions = subQuery.getWhereClauseRestrictions();
                    if (whereClauseRestrictions != null) {
                        appendSql(" and (");
                        whereClauseRestrictions.accept(this);
                        appendSql(CLOSE_PARENTHESIS);
                    }
                } finally {
                    clauseStack.pop();
                }
            }
            appendSql(CLOSE_PARENTHESIS);
        } finally {
            queryPartStack.pop();
            this.queryPartForRowNumbering = queryPartForRowNumbering;
            this.queryPartForRowNumberingClauseDepth = queryPartForRowNumberingClauseDepth;
            this.needsSelectAliases = needsSelectAliases;
        }
    } else {
        // TODO: We could use nested queries and use row numbers to emulate this
        throw new IllegalArgumentException("Can't emulate in predicate with tuples and limit/offset or set operations: " + predicate);
    }
}
Also used : QueryPart(org.hibernate.sql.ast.tree.select.QueryPart) QuerySpec(org.hibernate.sql.ast.tree.select.QuerySpec) 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 3 with QueryPart

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

the class AbstractSqlAstTranslator method withRowNumbering.

protected final void withRowNumbering(QueryPart queryPart, boolean needsSelectAliases, Runnable r) {
    final QueryPart queryPartForRowNumbering = this.queryPartForRowNumbering;
    final int queryPartForRowNumberingClauseDepth = this.queryPartForRowNumberingClauseDepth;
    final boolean originalNeedsSelectAliases = this.needsSelectAliases;
    try {
        this.queryPartForRowNumbering = queryPart;
        this.queryPartForRowNumberingClauseDepth = clauseStack.depth();
        this.needsSelectAliases = needsSelectAliases;
        r.run();
    } finally {
        this.queryPartForRowNumbering = queryPartForRowNumbering;
        this.queryPartForRowNumberingClauseDepth = queryPartForRowNumberingClauseDepth;
        this.needsSelectAliases = originalNeedsSelectAliases;
    }
}
Also used : QueryPart(org.hibernate.sql.ast.tree.select.QueryPart)

Example 4 with QueryPart

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

the class AbstractSqlAstTranslator method getEffectiveLockMode.

protected LockMode getEffectiveLockMode(String alias) {
    if (getLockOptions() == null) {
        return LockMode.NONE;
    }
    final QueryPart currentQueryPart = getQueryPartStack().getCurrent();
    LockMode lockMode = getLockOptions().getAliasSpecificLockMode(alias);
    if (currentQueryPart.isRoot() && lockMode == null) {
        lockMode = getLockOptions().getLockMode();
    }
    return lockMode == null ? LockMode.NONE : lockMode;
}
Also used : QueryPart(org.hibernate.sql.ast.tree.select.QueryPart) LockMode(org.hibernate.LockMode)

Example 5 with QueryPart

use of org.hibernate.sql.ast.tree.select.QueryPart 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)

Aggregations

QueryPart (org.hibernate.sql.ast.tree.select.QueryPart)19 QueryGroup (org.hibernate.sql.ast.tree.select.QueryGroup)7 QuerySpec (org.hibernate.sql.ast.tree.select.QuerySpec)7 ComparisonPredicate (org.hibernate.sql.ast.tree.predicate.ComparisonPredicate)6 ArrayList (java.util.ArrayList)5 Expression (org.hibernate.sql.ast.tree.expression.Expression)5 NamedTableReference (org.hibernate.sql.ast.tree.from.NamedTableReference)5 ExistsPredicate (org.hibernate.sql.ast.tree.predicate.ExistsPredicate)5 InSubQueryPredicate (org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate)5 SqmInsertSelectStatement (org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement)4 BinaryArithmeticExpression (org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression)4 ColumnReference (org.hibernate.sql.ast.tree.expression.ColumnReference)4 SelectClause (org.hibernate.sql.ast.tree.select.SelectClause)4 SqlSelectionImpl (org.hibernate.sql.results.internal.SqlSelectionImpl)4 Collections (java.util.Collections)3 IdentityHashMap (java.util.IdentityHashMap)3 LinkedHashMap (java.util.LinkedHashMap)3 List (java.util.List)3 Map (java.util.Map)3 BiConsumer (java.util.function.BiConsumer)3