{"record":{"id":"f6aadb5d2d35be9e","repo":"hibernate/hibernate-orm","slug":"insert-conflict-do-update-clause-with-constraint-f6aadb","errorCode":null,"errorMessage":"Insert conflict 'do update' clause with constraint name is not supported","messagePattern":"Insert conflict 'do update' clause with constraint name is not supported","errorType":"exception","errorClass":"IllegalQueryOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HANALegacySqlAstTranslator.java","lineNumber":145,"sourceCode":"\t\t\telse {\n\t\t\t\tvisitFromClause( statement.getFromClause() );\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tprotected void renderDmlTargetTableExpression(NamedTableReference tableReference) {\n\t\tsuper.renderDmlTargetTableExpression( tableReference );\n\t\tif ( getClauseStack().getCurrent() != Clause.INSERT ) {\n\t\t\trenderTableReferenceIdentificationVariable( tableReference );\n\t\t}\n\t}\n\n\t@Override\n\tprotected void visitConflictClause(ConflictClause conflictClause) {\n\t\tif ( conflictClause != null ) {\n\t\t\tif ( conflictClause.isDoUpdate() && conflictClause.getConstraintName() != null ) {\n\t\t\t\tthrow new IllegalQueryOperationException( \"Insert conflict 'do update' clause with constraint name is not supported\" );\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected boolean shouldEmulateFetchClause(QueryPart queryPart) {\n\t\t// HANA only supports the LIMIT + OFFSET syntax but also window functions\n\t\t// Check if current query part is already row numbering to avoid infinite recursion\n\t\treturn useOffsetFetchClause( queryPart ) && getQueryPartForRowNumbering() != queryPart\n\t\t\t\t&& !isRowsOnlyFetchClauseType( queryPart );\n\t}\n\n\t@Override\n\tprotected boolean isCorrelated(CteStatement cteStatement) {\n\t\t// Report false here, because apparently HANA does not need the \"lateral\" keyword to correlate a from clause subquery in a subquery\n\t\treturn false;\n\t}\n\n\t@Override","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HANALegacySqlAstTranslator.java#L127-L163","documentation":"HQL upserts ('insert ... on conflict do update') may name a conflict target constraint ('on conflict on constraint <name>'). HANALegacySqlAstTranslator.visitConflictClause throws IllegalQueryOperationException for that form: the legacy HANA translator's conflict rendering (HANA UPSERT emulation) cannot bind to a constraint by name.","triggerScenarios":"Executing an HQL insert whose conflict clause names a constraint, e.g. 'insert into Target ... select ... on conflict on constraint uk_target do update set ...', while the session uses the HANA legacy dialect. Target-less and column-list conflict targets are unaffected.","commonSituations":"HANA production databases pinned to the legacy dialect after a Hibernate upgrade; upsert HQL shared with PostgreSQL environments where the named-constraint form is natural; batch import jobs switching to the 6.6+ upsert syntax.","solutions":["Remove the constraint name and let Hibernate infer the target: 'on conflict do update set ...'","Use the column-list target 'on conflict (business_key) do update set ...' when you must pin the conflict target","Rewrite as native HANA UPSERT via createNativeQuery for full control","Plan migration off the legacy HANA dialect, whose translator handles modern conflict-clause features more completely"],"exampleFix":"// before (HQL, throws on HANA legacy dialect)\ninsert into Stock (sku, qty) select s.sku, s.qty from Stage s\n  on conflict on constraint pk_stock do update set qty = excluded.qty\n\n// after (column-list target)\ninsert into Stock (sku, qty) select s.sku, s.qty from Stage s\n  on conflict (sku) do update set qty = excluded.qty","handlingStrategy":"validation","validationCode":"Dialect d = sessionFactory.getJdbcServices().getDialect();\nif (d instanceof org.hibernate.community.dialect.HANALegacyDialect && hql.contains(\"on conflict on constraint\")) {\n    hql = hql.replaceFirst(\"on constraint \\\\w+\", \"\"); // or switch to column-list target\n}","typeGuard":"static boolean namedConflictTargetSafe(Dialect d) {\n    return !(d instanceof org.hibernate.community.dialect.HANALegacyDialect);\n}","tryCatchPattern":"try {\n    q = session.createQuery(hql);\n} catch (org.hibernate.query.IllegalQueryOperationException e) {\n    if (e.getMessage().contains(\"constraint name\")) {\n        q = session.createQuery(hql.replaceFirst(\"on constraint \\\\w+\", \"\"));\n    } else throw e;\n}","preventionTips":["Prefer the target-less or column-list conflict clause in HQL shared across databases","Track which dialects your upsert HQL must support, and run it against each in CI","For full control of HANA upserts, use native UPSERT statements"],"tags":["hibernate","hana","legacy-dialect","hql","upsert","on-conflict"],"backgroundTag":"upsert-conflict-target-unsupported","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}