{"record":{"id":"fd762f9fb3bff371","repo":"hibernate/hibernate-orm","slug":"insert-conflict-do-update-clause-with-constraint-fd762f","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/SybaseLegacySqlAstTranslator.java","lineNumber":89,"sourceCode":"\t\t\tclauseStack.push( Clause.DELETE );\n\t\t\trenderDmlTargetTableExpression( statement.getTargetTable() );\n\t\t}\n\t\tfinally {\n\t\t\tclauseStack.pop();\n\t\t}\n\t\tvisitFromClause( statement.getFromClause() );\n\t}\n\n\t@Override\n\tprotected void renderFromClauseAfterUpdateSet(UpdateStatement statement) {\n\t\tvisitFromClause( statement.getFromClause() );\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\t// Sybase does not allow CASE expressions where all result arms contain plain parameters.\n\t// At least one result arm must provide some type context for inference,\n\t// so we cast the first result arm if we encounter this condition\n\n\t@Override\n\tprotected void visitAnsiCaseSearchedExpression(\n\t\t\tCaseSearchedExpression caseSearchedExpression,\n\t\t\tConsumer<Expression> resultRenderer) {\n\t\tif ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSearchedExpression ) ) {\n\t\t\tfinal List<CaseSearchedExpression.WhenFragment> whenFragments = caseSearchedExpression.getWhenFragments();\n\t\t\tfinal Expression firstResult = whenFragments.get( 0 ).getResult();\n\t\t\tsuper.visitAnsiCaseSearchedExpression(\n\t\t\t\t\tcaseSearchedExpression,\n\t\t\t\t\te -> {","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseLegacySqlAstTranslator.java#L71-L107","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Replace the constraint-name target with the conflict column list: `on conflict (email) do update set ...`","Use `on conflict do nothing` when update-on-conflict is not required","Execute the upsert as a native SQL statement","Deduplicate in application code and issue a plain insert"],"exampleFix":"// before\ninsert into Customer(id, email) select :id, :email\n on conflict on constraint uk_customer_email do update set email = :email\n\n// after\ninsert into Customer(id, email) select :id, :email\n on conflict (email) do update set id = :id","handlingStrategy":"validation","validationCode":"// Emit only column-targeted conflict clauses on Sybase\nstatic String conflictClause(Dialect d) {\n    if (d instanceof SybaseLegacyDialect) {\n        return \"on conflict (email) do update set id = :id\"; // columns only\n    }\n    return \"on conflict on constraint uk_customer_email do update set id = :id\";\n}","typeGuard":null,"tryCatchPattern":"try {\n    return em.createQuery(upsertHql).executeUpdate();\n} catch (IllegalQueryOperationException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"constraint name\")) {\n        // rebuild HQL with a column-list conflict target and retry\n    }\n    throw e;\n}","preventionTips":["Prefer column-list conflict targets (`on conflict (cols)`); they are portable across all dialects","Keep upsert HQL in one place so switching conflict-target syntax is a one-line change","Test insert...on conflict statements against every backend in the support matrix"],"tags":["hibernate","sybase-ase","upsert","on-conflict","insert"],"backgroundTag":"upsert-on-conflict-unsupported","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}