{"record":{"id":"80b47dd747a5ac12","repo":"hibernate/hibernate-orm","slug":"dialect-returns-null-temporarytablestrategy-for-te","errorCode":null,"errorMessage":"Dialect returns null TemporaryTableStrategy for temporary table {} of type {}","messagePattern":"Dialect returns null TemporaryTableStrategy for temporary table (.+?) of type (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/dialect/temptable/StandardTemporaryTableExporter.java","lineNumber":67,"sourceCode":"\t}\n\n\t@Deprecated(forRemoval = true, since = \"7.1\")\n\tprotected String getTruncateTableCommand() {\n\t\treturn dialect.getTemporaryTableTruncateCommand();\n\t}\n\n\tprotected String getTruncateTableCommand(TemporaryTableStrategy temporaryTableStrategy) {\n\t\treturn temporaryTableStrategy.getTemporaryTableTruncateCommand();\n\t}\n\n\tprivate TemporaryTableStrategy getDefaultTemporaryTableStrategy(TemporaryTable temporaryTable) {\n\t\tfinal TemporaryTableStrategy temporaryTableStrategy = switch ( temporaryTable.getTemporaryTableKind() ) {\n\t\t\t\t\tcase LOCAL -> dialect.getLocalTemporaryTableStrategy();\n\t\t\t\t\tcase GLOBAL -> dialect.getGlobalTemporaryTableStrategy();\n\t\t\t\t\tcase PERSISTENT -> dialect.getPersistentTemporaryTableStrategy();\n\t\t\t\t};\n\t\tif ( temporaryTableStrategy == null ) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Dialect returns null TemporaryTableStrategy for temporary table \" + temporaryTable.getQualifiedTableName() + \" of type \" + temporaryTable.getTemporaryTableKind() );\n\t\t}\n\t\treturn temporaryTableStrategy;\n\t}\n\n\t@Override\n\tpublic String getSqlCreateCommand(TemporaryTable temporaryTable) {\n\t\tfinal TemporaryTableStrategy temporaryTableStrategy = getDefaultTemporaryTableStrategy( temporaryTable );\n\t\tfinal var buffer = new StringBuilder( getCreateCommand( temporaryTableStrategy ) ).append( ' ' );\n\t\tbuffer.append( temporaryTable.getQualifiedTableName() );\n\t\tbuffer.append( '(' );\n\n\t\tfor ( TemporaryTableColumn column : temporaryTable.getColumnsForExport() ) {\n\t\t\tbuffer.append( column.getColumnName() ).append( ' ' );\n\t\t\tfinal int sqlTypeCode = column.getJdbcMapping().getJdbcType().getDdlTypeCode();\n\t\t\tfinal String databaseTypeName = column.getSqlTypeDefinition();\n\n\t\t\tbuffer.append( databaseTypeName );","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/dialect/temptable/StandardTemporaryTableExporter.java#L49-L85","documentation":"Hibernate uses temporary tables to execute multi-table bulk HQL (UPDATE/DELETE on JOINED-inheritance or secondary-table entities). StandardTemporaryTableExporter.getDefaultTemporaryTableStrategy maps the TemporaryTable's kind (LOCAL/GLOBAL/PERSISTENT) to dialect.getLocalTemporaryTableStrategy()/getGlobalTemporaryTableStrategy()/getPersistentTemporaryTableStrategy(). Since Hibernate 7.1 the base Dialect returns a non-null strategy only for getSupportedTemporaryTableKind() and null for the other kinds (Dialect.java:3996-4010), so asking for a kind the dialect does not support throws IllegalStateException('Dialect returns null TemporaryTableStrategy ...') the first time temp-table SQL (create/drop/truncate) is generated.","triggerScenarios":"Configuring an SQM mutation strategy whose temp-table kind is unsupported by the dialect -- e.g. enabling the global-temporary-table bulk-id strategy on a LOCAL-only dialect (MySQL, HSQLDB, SQL Server/Sybase) or the local-temporary strategy on a GLOBAL dialect (H2, Oracle, HANA, DB2) -- and then executing a bulk UPDATE/DELETE against a JOINED entity. Also caused by a custom Dialect overriding getSupportedTemporaryTableKind()/the strategy getters inconsistently (returning null).","commonSituations":"Copying hibernate.query.mutation_strategy / bulk-id settings between projects running different databases; performance tuning that pins the temporary-table strategy without checking dialect support; upgrading to Hibernate 7.1 where these strategy getters became nullable; custom dialect subclasses that return null.","solutions":["Remove the explicit temporary-table mutation-strategy setting and let Hibernate choose the dialect-appropriate default","Match the strategy to the dialect: local_temporary_table only on LOCAL dialects (MySQL, HSQLDB, Transact-SQL family), global_temporary_table only on GLOBAL dialects (H2, Oracle, HANA, DB2)","In a custom dialect, override getLocalTemporaryTableStrategy()/getGlobalTemporaryTableStrategy() to return a real TemporaryTableStrategy (StandardLocalTemporaryTableStrategy/StandardGlobalTemporaryTableStrategy) instead of the null default","If the mismatch cannot be fixed by config, execute the bulk operation via native SQL"],"exampleFix":"// before: GLOBAL temp-table strategy forced on a LOCAL-only dialect\nMap<String,Object> cfg = new HashMap<>();\ncfg.put(\"hibernate.query.mutation_strategy\", \"global_temporary_table\"); // -> IllegalStateException on MySQL\n\n// after: let the dialect pick\n// (remove the property entirely; Dialect default is used)","handlingStrategy":"validation","validationCode":"// At startup, assert the configured bulk-id strategy is actually usable on this dialect\nstatic void assertTemporaryTableStrategyConsistent(Dialect dialect, TemporaryTableKind configuredKind) {\n    TemporaryTableStrategy strategy = switch (configuredKind) {\n        case LOCAL -> dialect.getLocalTemporaryTableStrategy();\n        case GLOBAL -> dialect.getGlobalTemporaryTableStrategy();\n        case PERSISTENT -> dialect.getPersistentTemporaryTableStrategy();\n    };\n    if (strategy == null) {\n        throw new IllegalStateException(dialect + \" has no \" + configuredKind\n            + \" temporary table strategy; remove the mutation-strategy override or fix the dialect\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    em.createQuery(\"delete from JoinedRoot e where e.flag = :f\").executeUpdate();\n} catch (IllegalStateException e) {\n    if (e.getMessage().startsWith(\"Dialect returns null TemporaryTableStrategy\")) {\n        // config mismatch: fall back to per-row operations or native bulk SQL for this dialect\n        throw new ConfigurationException(\"Remove the temporary-table mutation strategy override for this dialect\", e);\n    }\n    throw e;\n}","preventionTips":["Do not copy hibernate.query.mutation_strategy settings between projects on different databases","If you subclass Dialect, never return null from the temporary-table strategy getters -- return a Standard*TemporaryTableStrategy","Exercise one bulk UPDATE/DELETE on a JOINED entity in a startup/CI test per supported dialect"],"tags":["hibernate","temporary-tables","bulk-operations","joined-inheritance","dialect","configuration"],"backgroundTag":"temporary-table-strategy-misconfigured","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}