{"record":{"id":"57eeaa7b425497b8","repo":"hibernate/hibernate-orm","slug":"dialect-does-not-support-constraint-name-in-confli","errorCode":null,"errorMessage":"Dialect does not support constraint name in conflict clause","messagePattern":"Dialect does not support constraint name in conflict clause","errorType":"exception","errorClass":"IllegalQueryOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java","lineNumber":1464,"sourceCode":"\t\treturn expression.getExpressionType().getSingleJdbcMapping().getJdbcType();\n\t}\n\n\tprotected void visitInsertSource(InsertSelectStatement statement) {\n\t\tif ( statement.getSourceSelectStatement() != null ) {\n\t\t\tstatement.getSourceSelectStatement().accept( this );\n\t\t}\n\t\telse {\n\t\t\tvisitValuesList( statement.getValuesList() );\n\t\t}\n\t}\n\n\tprotected void visitInsertStatementEmulateMerge(InsertSelectStatement statement) {\n\t\tassert statement.getConflictClause() != null;\n\n\t\tfinal ConflictClause conflictClause = statement.getConflictClause();\n\t\tfinal String constraintName = conflictClause.getConstraintName();\n\t\tif ( constraintName != null ) {\n\t\t\tthrow new IllegalQueryOperationException( \"Dialect does not support constraint name in conflict clause\" );\n\t\t}\n\n\t\tappendSql( \"merge into \" );\n\t\tclauseStack.push( Clause.MERGE );\n\t\trenderNamedTableReference( statement.getTargetTable(), LockMode.NONE );\n\t\tclauseStack.pop();\n\t\tappendSql(\" using \" );\n\n\t\tfinal List<ColumnReference> targetColumnReferences = statement.getTargetColumns();\n\t\tfinal List<String> columnNames = new ArrayList<>( targetColumnReferences.size() );\n\t\tfor ( ColumnReference targetColumnReference : targetColumnReferences ) {\n\t\t\tcolumnNames.add( targetColumnReference.getColumnExpression() );\n\t\t}\n\n\t\tfinal DerivedTableReference derivedTableReference;\n\t\tif ( statement.getSourceSelectStatement() != null ) {\n\t\t\tderivedTableReference = new QueryPartTableReference(\n\t\t\t\t\tnew SelectStatement( statement.getSourceSelectStatement() ),","sourceCodeStart":1446,"sourceCodeEnd":1482,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java#L1446-L1482","documentation":"visitInsertStatementEmulateMerge rewrites an HQL insert-with-conflict-clause as a database MERGE statement; used by translators for DB2, SQL Server, Oracle, Sybase/ASE, HANA, H2, and HSQLDB when the dialect has no native upsert. A MERGE statement matches rows by predicate and cannot target a named constraint, so if the SQM conflict clause has a non-null constraint name the translation aborts with IllegalQueryOperationException before any SQL is emitted.","triggerScenarios":"HQL 'insert ... on conflict on constraint <name> [do nothing | do update ...]' executed on a dialect whose translator routes upserts through visitInsertStatementEmulateMerge (DB2, SQL Server, Oracle pre-native-upsert, Sybase ASE, HANA, H2, HSQLDB).","commonSituations":"Writing database-agnostic upsert HQL and testing it on H2 while targeting SQL Server/Oracle; copying PostgreSQL ON CONFLICT ON CONSTRAINT syntax to DB2; Hibernate 6.5+ HQL insert conflict feature enabled in multi-dialect apps.","solutions":["Drop the constraint name from the conflict clause — 'on conflict do nothing' or 'on conflict (col1, col2) ...' works through the MERGE emulation.","If you must target a specific constraint, run a native MERGE/upsert statement for that dialect.","For SQL Server/Oracle newer versions, ensure the dialect version is detected correctly so native upsert/MERGE paths with conflict-column support are used."],"exampleFix":"// before — named constraint cannot be represented in the MERGE emulation\nsession.createQuery(\n    \"insert into Customer (id,email) values (:i,:e) on conflict on constraint uk_email do nothing\")\n    .executeUpdate();\n\n// after — use conflict column names instead of the constraint name\nsession.createQuery(\n    \"insert into Customer (id,email) values (:i,:e) on conflict (email) do nothing\")\n    .executeUpdate();","handlingStrategy":"validation","validationCode":"org.hibernate.dialect.Dialect d = sessionFactory.getJdbcServices().getDialect();\nboolean mergeEmulatedUpsert = d instanceof org.hibernate.dialect.DB2Dialect\n        || d instanceof org.hibernate.dialect.SQLServerDialect\n        || d instanceof org.hibernate.dialect.SybaseASEDialect\n        || d instanceof org.hibernate.dialect.HANADialect;\nif (mergeEmulatedUpsert && constraintName != null) {\n    // MERGE emulation cannot target a named constraint\n    constraintName = null; // or switch to conflict column names\n}","typeGuard":null,"tryCatchPattern":"try { session.createQuery(insertHql).executeUpdate(); }\ncatch (org.hibernate.query.IllegalQueryOperationException e) {\n    if (e.getMessage().equals(\"Dialect does not support constraint name in conflict clause\")) {\n        session.createQuery(insertHql.replace(\" on constraint \" + name, \"\")).executeUpdate();\n    } else { throw e; }\n}","preventionTips":["Never name constraints in conflict clauses of portable HQL; use column names or omit.","Keep a per-dialect map of supported upsert syntax and validate before building HQL.","Test upsert HQL against every database your app supports."],"tags":["hibernate","orm","upsert","merge","on-conflict","db2","sqlserver","oracle"],"backgroundTag":"upsert-conflict-clause-unsupported","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}