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
SybaseASELegacySqlAstTranslator.visitConflictClause() throws IllegalQueryOperationException when an HQL insert statement carries an ON CONFLICT 'do update' clause that names a constraint ('on conflict for constraint <name> do update'). Sybase ASE has no native upsert, and while the translator can pass through a plain key-based conflict clause, the constraint-name variant is explicitly rejected during query translation. The check only fires when isDoUpdate() and getConstraintName() are both set - 'do nothing' with a constraint name and 'do update' keyed by columns are not rejected here.
Source
Thrown at hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacySqlAstTranslator.java:123
}
@Override
protected void renderFromClauseAfterUpdateSet(UpdateStatement statement) {
if ( statement.getFromClause().getRoots().isEmpty() ) {
appendSql( " from " );
renderDmlTargetTableExpression( statement.getTargetTable() );
renderTableReferenceIdentificationVariable( statement.getTargetTable() );
}
else {
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 ASE 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
- Drop the 'for constraint <name>' phrase and key the conflict by columns: 'on conflict (id) do update set ...'
- Use 'on conflict do nothing' (optionally with the constraint name) if skipping duplicates is acceptable
- On ASE, implement the upsert manually: try an UPDATE, then INSERT the rows that updated zero rows, inside a transaction
- Catch IllegalQueryOperationException at query creation and fall back to the manual update-then-insert path
Example fix
// before insert into Person(id, name) values(:id, :name) on conflict for constraint pk_person do update set name = excluded.name // after insert into Person(id, name) values(:id, :name) on conflict (id) do update set name = excluded.name
Defensive patterns
Strategy: try-catch
Validate before calling
static String stripConflictConstraintName(String hql) {
return hql.replaceAll('for constraint \\w+', '');
}
// use stripConflictConstraintName(hql) before createMutationQuery on Sybase ASE Try / catch
try {
factory.createMutationQuery(upsertHql).execute();
}
catch (IllegalQueryOperationException e) {
if (String.valueOf(e.getMessage()).contains('do update')) {
// fallback: manual upsert on ASE
int updated = em.createQuery('update Person p set p.name = :n where p.id = :id')
.setParameter('n', name).setParameter('id', id).executeUpdate();
if (updated == 0) {
em.persist(new Person(id, name));
}
} else {
throw e;
}
} Prevention
- Key ON CONFLICT clauses by columns, never by constraint name, for portable HQL
- Keep database-specific upsert statements in per-dialect repositories
- Test upsert queries against every target database in CI
When it happens
Trigger: Building a MutationQuery with HQL like 'insert into Person(id, name) values(:id,:name) on conflict for constraint pk_person do update set name = excluded.name' against a Sybase ASE (legacy dialect) connection; Jakarta Persistence 3.2 style upsert statements reused across databases.
Common situations: An upsert statement written and tested on PostgreSQL (where naming the constraint is common) executed against Sybase ASE in another environment; shared repository code covering multiple databases; migration of batch import jobs to ASE.
Related errors
- Insert conflict 'do update' clause with constraint name is n
- Insert conflict 'do update' clause with constraint name is n
- Insert conflict 'do update' clause with constraint name is n
- Insert conflict 'do update' clause with constraint name is n
- Insert conflict 'do update' clause with constraint name is n
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/1bafb36f9e7fa0c3.
Report an issue: GitHub.