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;
}
}
}
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);
}
}
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;
}
}
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;
}
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());
}
}
Aggregations