hibernate/hibernate-orm · error · IllegalArgumentException

Can't emulate quantified tuple subquery predicate with limit

Error message

Can't emulate quantified tuple subquery predicate with limit/offset or set operations: 

What it means

Quantified variant of the tuple subquery emulation: (a,b) = any (select x,y ...) or < all (select ...) on dialects without row constructor syntax is emulated by comparing against the subquery's top row after row-number wrapping (renderQuantifiedEmulationSubQuery). The comment above the throw records the constraint: this only works without limit/offset in the subquery part; otherwise IllegalArgumentException is thrown.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java:8176

			Predicate predicate,
			SelectStatement selectStatement,
			SqlTuple lhsTuple,
			ComparisonOperator tupleComparisonOperator) {
		final QueryPart queryPart = selectStatement.getQueryPart();
		if ( queryPart instanceof QuerySpec querySpec
				&& queryPart.getFetchClauseExpression() == null
				&& queryPart.getOffsetClauseExpression() == null ) {
			// We can only emulate the tuple subquery predicate comparing against the top element when there are no limit/offsets
			lhsTuple.accept( this );
			appendSql( tupleComparisonOperator.sqlText() );
			renderQuantifiedEmulationSubQuery(
					querySpec,
					tupleComparisonOperator
			);
		}
		else {
			// TODO: We could use nested queries and use row numbers to emulate this
			throw new IllegalArgumentException(
					"Can't emulate quantified tuple subquery predicate with limit/offset or set operations: " + predicate );
		}
	}

	protected void renderQuantifiedEmulationSubQuery(
			QuerySpec subQuery,
			ComparisonOperator tupleComparisonOperator) {
		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( OPEN_PARENTHESIS );
			visitSelectClause( subQuery.getSelectClause() );
			visitFromClause( subQuery.getFromClause() );

View on GitHub (pinned to fad1729dce)

Solutions

  1. Remove limit/offset and set operations from the quantified subquery
  2. Use a single-column comparison or component-wise comparisons
  3. Use a database with native row value constructor support
  4. Use a native query

Example fix

// before
... where (o.custId, o.seq) = any (select v.custId, v.seq from Vip v fetch first 10 rows only)

// after
... where o.custId in (select v.custId from Vip v fetch first 10 rows only) and o.seq in (select v.seq from Vip v fetch first 10 rows only)
Defensive patterns

Strategy: fallback

Validate before calling

if (!dialect.supportsRowValueConstructorSyntax()
        && quantifiedSubqueryHasLimitOrSetOperation(predicate)) {
    // rewrite = any/(tuple) as per-column in()/scalar comparisons
}

Try / catch

try {
    query.list();
} catch (IllegalArgumentException e) {
    if (String.valueOf(e.getMessage()).startsWith("Can't emulate quantified tuple subquery predicate")) {
        // rewrite as component-wise in()/scalar predicates and retry
    } else throw e;
}

Prevention

When it happens

Trigger: HQL where a tuple is compared with = any/all/some against a subquery containing limit/fetch/offset or set operations, on a dialect lacking native row value constructor + quantified comparison support (e.g. SQL Server, MySQL < 8.0.19).

Common situations: any()/all() queries with composite keys on SQL Server; subqueries with union or pagination reused in quantified comparisons; porting PostgreSQL/standard SQL to MySQL.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/d6e24826ae5130e8. Report an issue: GitHub.