hibernate/hibernate-orm · error · UnsupportedOperationException

Can't emulate lateral join for query spec with having clause

Error message

Can't emulate lateral join for query spec with having clause

What it means

Same stripToSelectClause lateral emulation as the group-by case: a HAVING clause in the lateral query spec cannot be preserved when the query is stripped to its select clause and inlined into the outer query, so Hibernate throws this UnsupportedOperationException instead of silently changing query semantics.

Source

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

		}
	}

	private QueryGroup stripToSelectClause(QueryGroup queryGroup) {
		final List<QueryPart> parts = new ArrayList<>( queryGroup.getQueryParts().size() );
		for ( QueryPart queryPart : queryGroup.getQueryParts() ) {
			parts.add( stripToSelectClause( queryPart ) );
		}
		return new QueryGroup( queryGroup.isRoot(), queryGroup.getSetOperator(), parts );
	}

	private QuerySpec stripToSelectClause(QuerySpec querySpec) {
		final var groupByExpressions = querySpec.getGroupByClauseExpressions();
		if ( groupByExpressions != null && !groupByExpressions.isEmpty() ) {
			throw new UnsupportedOperationException( "Can't emulate lateral join for query spec with group by clause" );
		}
		final Predicate havingRestrictions = querySpec.getHavingClauseRestrictions();
		if ( havingRestrictions != null && !havingRestrictions.isEmpty() ) {
			throw new UnsupportedOperationException( "Can't emulate lateral join for query spec with having clause" );
		}
		final var roots = querySpec.getFromClause().getRoots();
		final QuerySpec newQuerySpec = new QuerySpec( querySpec.isRoot(), roots.size() );
		for ( TableGroup root : roots ) {
			newQuerySpec.getFromClause().addRoot( root );
		}
		final SelectClause selectClause = querySpec.getSelectClause();
		for ( SqlSelection selection : selectClause.getSqlSelections() ) {
			if ( AggregateFunctionChecker.hasAggregateFunctions( selection.getExpression() ) ) {
				throw new UnsupportedOperationException( "Can't emulate lateral join for query spec with aggregate function" );
			}
			newQuerySpec.getSelectClause().addSqlSelection( selection );
		}
		return newQuerySpec;
	}

	private boolean needsLateralSortExpressionVirtualSelections(QuerySpec querySpec) {
		return !( ( querySpec.getSelectClause().getSqlSelections().size() == 1

View on GitHub (pinned to fad1729dce)

Solutions

  1. Move the having restriction into a where on a subselect or into the outer query
  2. Remove the aggregate/having logic from the lateral part
  3. Use a dialect with native LATERAL support
  4. Write the query as native SQL

Example fix

// before
... join lateral (select o.customer c, count(o) n from Ord o where o.customer=cust group by o.customer having count(o) > 5) s ...

// after
... where (select count(o) from Ord o where o.customer=cust) > 5 ...
Defensive patterns

Strategy: fallback

Validate before calling

if (!dialect.supportsLateral() && lateralPartHasHaving(sq)) {
    // convert having to a where predicate on a scalar subquery first
}

Try / catch

try {
    query.list();
} catch (UnsupportedOperationException e) {
    if (String.valueOf(e.getMessage()).contains("lateral join for query spec with having clause")) {
        // push the filter into a correlated scalar subquery and retry
    } else throw e;
}

Prevention

When it happens

Trigger: A lateral join emulation (dialect without LATERAL) where the lateral query spec carries a non-empty HAVING restriction, e.g. 'join lateral (select ... group by ... having count(*) > 1)' or any HQL that yields having inside the lateral part.

Common situations: Aggregating inside collection/lateral joins on MySQL 5.x or other non-lateral databases; migrating PostgreSQL queries with lateral + having; Hibernate 6.x implicit lateral collection joins.

Related errors


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