{"record":{"id":"cdc5cc9576e8d318","repo":"hibernate/hibernate-orm","slug":"insert-conflict-do-update-clause-is-not-supported","errorCode":null,"errorMessage":"Insert conflict do update clause is not supported","messagePattern":"Insert conflict do update clause is not supported","errorType":"exception","errorClass":"IllegalQueryOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java","lineNumber":1994,"sourceCode":"\t\t\t\tthrow new IllegalQueryOperationException( \"Locking with aggregate functions is not supported\" );\n\t\t\t}\n\t\t\telse if ( followOnStrategy == Locking.FollowOn.IGNORE ) {\n\t\t\t\treturn LockStrategy.NONE;\n\t\t\t}\n\t\t\tstrategy = LockStrategy.FOLLOW_ON;\n\t\t}\n\n\t\treturn strategy;\n\t}\n\n\tprotected void visitConflictClause(ConflictClause conflictClause) {\n\t\tif ( conflictClause != null ) {\n\t\t\t// By default, we only support do nothing with an optional constraint name\n\t\t\tif ( !conflictClause.getConstraintColumnNames().isEmpty() ) {\n\t\t\t\tthrow new IllegalQueryOperationException( \"Insert conflict clause with constraint column names is not supported\" );\n\t\t\t}\n\t\t\tif ( conflictClause.isDoUpdate() ) {\n\t\t\t\tthrow new IllegalQueryOperationException( \"Insert conflict do update clause is not supported\" );\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected void visitStandardConflictClause(ConflictClause conflictClause) {\n\t\tif ( conflictClause == null ) {\n\t\t\treturn;\n\t\t}\n\n\t\tclauseStack.push( Clause.CONFLICT );\n\t\tappendSql( \" on conflict\" );\n\t\tfinal String constraintName = conflictClause.getConstraintName();\n\t\tif ( constraintName != null ) {\n\t\t\tappendSql( \" on constraint \" );\n\t\t\tappendSql( constraintName );\n\t\t}\n\t\telse if ( !conflictClause.getConstraintColumnNames().isEmpty() ) {\n\t\t\tchar separator = '(';","sourceCodeStart":1976,"sourceCodeEnd":2012,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java#L1976-L2012","documentation":"The second guard of the base visitConflictClause: the default implementation supports only DO NOTHING, so an HQL insert with a 'do update' conflict clause (upsert-update) on a dialect whose translator did not override conflict handling throws IllegalQueryOperationException during translation.","triggerScenarios":"HQL 'insert ... on conflict [constraint] do update set col = ...' on a dialect using the base translator — databases without native upsert-update and without a MERGE/duplicate-key override in their SqlAstTranslator.","commonSituations":"Writing portable upsert HQL for PostgreSQL/MySQL and running it on a lesser-supported database; Hibernate 6.5+/6.6 upsert features enabled broadly; community dialects lagging on conflict-clause support.","solutions":["Run the upsert-update as a native statement (MERGE, INSERT ... ON CONFLICT DO UPDATE, ON DUPLICATE KEY UPDATE) for that database.","Implement the upsert in application code inside a transaction: attempt insert, catch the unique violation, then update.","Restrict the HQL conflict syntax to dialects that support it (profile per-dialect HQL) and use 'do nothing' where only that is supported."],"exampleFix":"// before — do-update conflict clause on an unsupported dialect\nsession.createQuery(\n    \"insert into Counter (id,hits) values (:i,:h) on conflict (id) do update set hits = excluded.hits\")\n    .executeUpdate();\n\n// after — dialect-native upsert\nem.createNativeQuery(\"insert into counter (id,hits) values (?,?) \" +\n    \"on duplicate key update hits = hits + values(hits)\")\n  .setParameter(1, id).setParameter(2, hits).executeUpdate();","handlingStrategy":"validation","validationCode":"if (conflictClauseHasDoUpdate(hql) && !dialectSupportsUpsertUpdate(sessionFactory)) {\n    // route to native upsert or application-level insert-or-update instead of HQL\n    useNativeUpsert = true;\n}","typeGuard":null,"tryCatchPattern":"try { session.createQuery(insertHql).executeUpdate(); }\ncatch (org.hibernate.query.IllegalQueryOperationException e) {\n    if (e.getMessage().equals(\"Insert conflict do update clause is not supported\")) {\n        runNativeUpsertOrUpdate(insertHql);\n    } else { throw e; }\n}","preventionTips":["Use HQL 'do update' only on dialects with native/emulated upsert-update; otherwise use native SQL.","Wrap upsert logic behind a dialect-aware repository method so callers cannot pick the wrong syntax."],"tags":["hibernate","orm","upsert","do-update","on-conflict","dialect-capability"],"backgroundTag":"upsert-conflict-clause-unsupported","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}