hibernate/hibernate-orm · error · IllegalQueryOperationException

Insert conflict 'do update' clause with constraint name is n

Error message

Insert conflict 'do update' clause with constraint name is not supported

What it means

Hibernate 6.6+ supports INSERT ... ON CONFLICT ... DO UPDATE where the conflict target is either column names or a named constraint (`on conflict on constraint <name>`). The Sybase legacy translator emulates do-update as a merge-style statement keyed on conflict column names; a constraint-name target provides no column list to match on, so visitConflictClause throws IllegalQueryOperationException for exactly the do-update + constraint-name combination.

Source

Thrown at hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseLegacySqlAstTranslator.java:89

			clauseStack.push( Clause.DELETE );
			renderDmlTargetTableExpression( statement.getTargetTable() );
		}
		finally {
			clauseStack.pop();
		}
		visitFromClause( statement.getFromClause() );
	}

	@Override
	protected void renderFromClauseAfterUpdateSet(UpdateStatement statement) {
		visitFromClause( statement.getFromClause() );
	}

	@Override
	protected void visitConflictClause(ConflictClause conflictClause) {
		if ( conflictClause != null ) {
			if ( conflictClause.isDoUpdate() && conflictClause.getConstraintName() != null ) {
				throw new IllegalQueryOperationException( "Insert conflict 'do update' clause with constraint name is not supported" );
			}
		}
	}

	// Sybase does not allow CASE expressions where all result arms contain plain parameters.
	// At least one result arm must provide some type context for inference,
	// so we cast the first result arm if we encounter this condition

	@Override
	protected void visitAnsiCaseSearchedExpression(
			CaseSearchedExpression caseSearchedExpression,
			Consumer<Expression> resultRenderer) {
		if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSearchedExpression ) ) {
			final List<CaseSearchedExpression.WhenFragment> whenFragments = caseSearchedExpression.getWhenFragments();
			final Expression firstResult = whenFragments.get( 0 ).getResult();
			super.visitAnsiCaseSearchedExpression(
					caseSearchedExpression,
					e -> {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Replace the constraint-name target with the conflict column list: `on conflict (email) do update set ...`
  2. Use `on conflict do nothing` when update-on-conflict is not required
  3. Execute the upsert as a native SQL statement
  4. Deduplicate in application code and issue a plain insert

Example fix

// before
insert into Customer(id, email) select :id, :email
 on conflict on constraint uk_customer_email do update set email = :email

// after
insert into Customer(id, email) select :id, :email
 on conflict (email) do update set id = :id
Defensive patterns

Strategy: validation

Validate before calling

// Emit only column-targeted conflict clauses on Sybase
static String conflictClause(Dialect d) {
    if (d instanceof SybaseLegacyDialect) {
        return "on conflict (email) do update set id = :id"; // columns only
    }
    return "on conflict on constraint uk_customer_email do update set id = :id";
}

Try / catch

try {
    return em.createQuery(upsertHql).executeUpdate();
} catch (IllegalQueryOperationException e) {
    if (e.getMessage() != null && e.getMessage().contains("constraint name")) {
        // rebuild HQL with a column-list conflict target and retry
    }
    throw e;
}

Prevention

When it happens

Trigger: HQL `insert into Customer(id, email) select ... on conflict on constraint uk_customer_email do update set ...` executed with SybaseLegacyDialect (Sybase ASE). Column-list targets (`on conflict (email) do update`) and `do nothing` variants do not trigger this throw.

Common situations: Generic upsert code shared across databases that assumes the constraint-name syntax works everywhere; HQL upserts written against PostgreSQL semantics then run on Sybase ASE.

Related errors


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