hibernate/hibernate-orm · error · IllegalQueryOperationException

Dialect does not support constraint name in conflict clause

Error message

Dialect does not support constraint name in conflict clause

What it means

visitInsertStatementEmulateMerge rewrites an HQL insert-with-conflict-clause as a database MERGE statement; used by translators for DB2, SQL Server, Oracle, Sybase/ASE, HANA, H2, and HSQLDB when the dialect has no native upsert. A MERGE statement matches rows by predicate and cannot target a named constraint, so if the SQM conflict clause has a non-null constraint name the translation aborts with IllegalQueryOperationException before any SQL is emitted.

Source

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

		return expression.getExpressionType().getSingleJdbcMapping().getJdbcType();
	}

	protected void visitInsertSource(InsertSelectStatement statement) {
		if ( statement.getSourceSelectStatement() != null ) {
			statement.getSourceSelectStatement().accept( this );
		}
		else {
			visitValuesList( statement.getValuesList() );
		}
	}

	protected void visitInsertStatementEmulateMerge(InsertSelectStatement statement) {
		assert statement.getConflictClause() != null;

		final ConflictClause conflictClause = statement.getConflictClause();
		final String constraintName = conflictClause.getConstraintName();
		if ( constraintName != null ) {
			throw new IllegalQueryOperationException( "Dialect does not support constraint name in conflict clause" );
		}

		appendSql( "merge into " );
		clauseStack.push( Clause.MERGE );
		renderNamedTableReference( statement.getTargetTable(), LockMode.NONE );
		clauseStack.pop();
		appendSql(" using " );

		final List<ColumnReference> targetColumnReferences = statement.getTargetColumns();
		final List<String> columnNames = new ArrayList<>( targetColumnReferences.size() );
		for ( ColumnReference targetColumnReference : targetColumnReferences ) {
			columnNames.add( targetColumnReference.getColumnExpression() );
		}

		final DerivedTableReference derivedTableReference;
		if ( statement.getSourceSelectStatement() != null ) {
			derivedTableReference = new QueryPartTableReference(
					new SelectStatement( statement.getSourceSelectStatement() ),

View on GitHub (pinned to fad1729dce)

Solutions

  1. Drop the constraint name from the conflict clause — 'on conflict do nothing' or 'on conflict (col1, col2) ...' works through the MERGE emulation.
  2. If you must target a specific constraint, run a native MERGE/upsert statement for that dialect.
  3. For SQL Server/Oracle newer versions, ensure the dialect version is detected correctly so native upsert/MERGE paths with conflict-column support are used.

Example fix

// before — named constraint cannot be represented in the MERGE emulation
session.createQuery(
    "insert into Customer (id,email) values (:i,:e) on conflict on constraint uk_email do nothing")
    .executeUpdate();

// after — use conflict column names instead of the constraint name
session.createQuery(
    "insert into Customer (id,email) values (:i,:e) on conflict (email) do nothing")
    .executeUpdate();
Defensive patterns

Strategy: validation

Validate before calling

org.hibernate.dialect.Dialect d = sessionFactory.getJdbcServices().getDialect();
boolean mergeEmulatedUpsert = d instanceof org.hibernate.dialect.DB2Dialect
        || d instanceof org.hibernate.dialect.SQLServerDialect
        || d instanceof org.hibernate.dialect.SybaseASEDialect
        || d instanceof org.hibernate.dialect.HANADialect;
if (mergeEmulatedUpsert && constraintName != null) {
    // MERGE emulation cannot target a named constraint
    constraintName = null; // or switch to conflict column names
}

Try / catch

try { session.createQuery(insertHql).executeUpdate(); }
catch (org.hibernate.query.IllegalQueryOperationException e) {
    if (e.getMessage().equals("Dialect does not support constraint name in conflict clause")) {
        session.createQuery(insertHql.replace(" on constraint " + name, "")).executeUpdate();
    } else { throw e; }
}

Prevention

When it happens

Trigger: HQL 'insert ... on conflict on constraint <name> [do nothing | do update ...]' executed on a dialect whose translator routes upserts through visitInsertStatementEmulateMerge (DB2, SQL Server, Oracle pre-native-upsert, Sybase ASE, HANA, H2, HSQLDB).

Common situations: Writing database-agnostic upsert HQL and testing it on H2 while targeting SQL Server/Oracle; copying PostgreSQL ON CONFLICT ON CONSTRAINT syntax to DB2; Hibernate 6.5+ HQL insert conflict feature enabled in multi-dialect apps.

Related errors


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