{"record":{"id":"a7b094298293b51a","repo":"hibernate/hibernate-orm","slug":"insert-conflict-do-update-clause-with-constraint-a7b094","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-core/src/main/java/org/hibernate/dialect/sql/ast/SybaseASESqlAstTranslator.java","lineNumber":122,"sourceCode":"\t}\n\n\t@Override\n\tprotected void renderFromClauseAfterUpdateSet(UpdateStatement statement) {\n\t\tif ( statement.getFromClause().getRoots().isEmpty() ) {\n\t\t\tappendSql( \" from \" );\n\t\t\trenderDmlTargetTableExpression( statement.getTargetTable() );\n\t\t\trenderTableReferenceIdentificationVariable( statement.getTargetTable() );\n\t\t}\n\t\telse {\n\t\t\tvisitFromClause( statement.getFromClause() );\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\t// Sybase ASE 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":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/dialect/sql/ast/SybaseASESqlAstTranslator.java#L104-L140","documentation":"SybaseASESqlAstTranslator.visitConflictClause rejects HQL INSERT ... ON CONFLICT statements whose conflict target is a named constraint: when the ConflictClause is a DO UPDATE clause and getConstraintName() != null, it throws IllegalQueryOperationException, because the ASE upsert rendering cannot resolve conflicts through a constraint name (no 'ON CONFLICT ON CONSTRAINT' equivalent in ASE SQL).","triggerScenarios":"Executing HQL 'insert into T (...) values/select ... on conflict on constraint <name> do update set ...' (or SQM conflictOnConstraint(\"<name>\")) while the factory uses SybaseASEDialect. The exception is thrown during query translation (createQuery/executeUpdate), before any DB call.","commonSituations":"Running PostgreSQL-derived upsert HQL against an ASE database; shared cross-dialect test suites; legacy Sybase deployments receiving code written for PostgreSQL dialect.","solutions":["Use the column-based form 'on conflict (col1, col2) do update set ...'","Verify the column list covers exactly the columns of the intended unique constraint","Use a native ASE statement (MERGE where supported, or IF EXISTS ... UPDATE ELSE INSERT) for dialect-specific upserts","Branch on dialect at runtime so PostgreSQL keeps the constraint-name form and ASE gets the column form"],"exampleFix":"// before\n\"insert into Price p (p.sku,p.value) values (:s,:v) on conflict on constraint uk_price_sku do update set p.value = excluded.value\"\n\n// after\n\"insert into Price p (p.sku,p.value) values (:s,:v) on conflict (sku) do update set p.value = excluded.value\"","handlingStrategy":"validation","validationCode":"static boolean supportsConstraintNameConflictTarget(Dialect dialect) {\n    return dialect instanceof PostgreSQLDialect; // Sybase ASE translator rejects it\n}\n\nif (!supportsConstraintNameConflictTarget(dialect)) {\n    hql = hql.replace(\"on conflict on constraint \" + constraintName,\n                     \"on conflict (\" + constraintColumns + \")\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    em.createQuery(hql).executeUpdate();\n} catch (IllegalQueryOperationException e) {\n    if (e.getMessage().contains(\"constraint name is not supported\")) {\n        em.createQuery(toColumnTargetHql(hql)).executeUpdate();\n        return;\n    }\n    throw e;\n}","preventionTips":["Use column-list conflict targets everywhere; the constraint-name form is a PostgreSQL-only convenience","Keep constraint-to-columns mapping available so dialect-specific rewriting is mechanical","Test shared upsert HQL against ASE when that profile exists"],"tags":["hibernate","sybase-ase","hql","upsert","on-conflict","insert","query-translation"],"backgroundTag":"upsert-on-conflict-unsupported","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}