{"record":{"id":"26ae71c39e087609","repo":"hibernate/hibernate-orm","slug":"can-t-emulate-tablegroupjoin-getjointype-ge","errorCode":null,"errorMessage":"Can't emulate '\" + tableGroupJoin.getJoinType().getText() + \"join' in a DB2 recursive query part","messagePattern":"Can't emulate '\" \\+ tableGroupJoin\\.getJoinType\\(\\)\\.getText\\(\\) \\+ \"join' in a DB2 recursive query part","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacySqlAstTranslator.java","lineNumber":117,"sourceCode":"\t\t\t\tif ( tableJoin.getPredicate() != null && !tableJoin.getPredicate().isEmpty() ) {\n\t\t\t\t\taddAdditionalWherePredicate( tableJoin.getPredicate() );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tsuper.renderTableReferenceJoins( tableGroup, lockMode, swappedJoinIndex, forceLeftJoin );\n\t\t}\n\t}\n\n\t@Override\n\tprotected void renderTableGroupJoin(TableGroupJoin tableGroupJoin, List<TableGroupJoin> tableGroupJoinCollector) {\n\t\tif ( isInRecursiveQueryPart() ) {\n\t\t\tswitch ( tableGroupJoin.getJoinType() ) {\n\t\t\t\tcase CROSS:\n\t\t\t\tcase INNER:\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new UnsupportedOperationException( \"Can't emulate '\" + tableGroupJoin.getJoinType().getText() + \"join' in a DB2 recursive query part\" );\n\t\t\t}\n\t\t\tappendSql( COMMA_SEPARATOR_CHAR );\n\n\t\t\trenderJoinedTableGroup( tableGroupJoin, null, tableGroupJoinCollector );\n\t\t\tif ( tableGroupJoin.getPredicate() != null && !tableGroupJoin.getPredicate().isEmpty() ) {\n\t\t\t\taddAdditionalWherePredicate( tableGroupJoin.getPredicate() );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tsuper.renderTableGroupJoin( tableGroupJoin, tableGroupJoinCollector );\n\t\t}\n\t}\n\n\t@Override\n\tprotected void renderExpressionAsClauseItem(Expression expression) {\n\t\tif ( expression instanceof Predicate && getDB2Version().isBefore( 11 ) ) {\n\t\t\tsuper.renderExpressionAsClauseItem( expression );\n\t\t}","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacySqlAstTranslator.java#L99-L135","documentation":"UnionTableReference is the from-element covering the unioned tables of a TABLE_PER_CLASS (union-subclass) hierarchy; it answers resolveTableReference via hasTableExpression only for the table names included in the union set and throws UnknownTableReferenceException for anything else. The error means the requested table belongs to a sibling branch of the hierarchy (or is entirely unrelated) and is not part of this union reference.","triggerScenarios":"Polymorphic queries over a union-subclass hierarchy that reference a table specific to one subclass (e.g. ordering or selecting SubA-only columns while the union path routes through SubB's branch); subclass table names not registered in the union reference after mapping edits; cross-hierarchy table name collisions.","commonSituations":"TABLE_PER_CLASS inheritance with subclass-specific tables queried through the superclass or a sibling subclass; adding a new subclass/table without rebuilding mappings in tests; dialect/translator paths resolving subclass tables per union branch.","solutions":["Query the concrete subclass that owns the table instead of going through the union of the hierarchy.","Move shared columns to the mapped superclass / common tables so all branches expose them.","Remove references to sibling-subclass columns from polymorphic queries (select/order only common attributes).","Verify union table registration after inheritance mapping changes; upgrade Hibernate for union-resolution fixes."],"exampleFix":"// before: subclass-specific column through the union hierarchy\n\"select e from Employee e order by e.contractDetailsClauses\" // column only on ContractEmployee\n\n// after: query the concrete subclass\n\"select c from ContractEmployee c order by c.contractDetailsClauses\"","handlingStrategy":"validation","validationCode":"// Before polymorphic union queries: ensure only hierarchy-common attributes are referenced\nSet<String> commonAttributes = superclassAttributes( Employee.class );\nboolean onlyCommon = referencedPaths.stream().allMatch( commonAttributes::contains );\nif ( !onlyCommon ) {\n    // narrow the query to the concrete subclass owning those columns\n    Class<?> concrete = owningSubclassFor( referencedPaths );\n}","typeGuard":null,"tryCatchPattern":"try {\n    return em.createQuery(hql, type).getResultList();\n} catch ( UnknownTableReferenceException e ) {\n    // sibling-subclass table requested through the union: query the concrete subclass\n    return em.createQuery(narrowToConcreteSubclass(hql, e.getTableExpression()), type).getResultList();\n}","preventionTips":["In TABLE_PER_CLASS hierarchies, restrict polymorphic select/order-by to attributes mapped on the common root.","Query concrete subclasses whenever subclass-specific columns are needed.","When adding a subclass table, re-run polymorphic query tests to catch union-coverage gaps."],"tags":["table-reference","union-subclass","inheritance","table-per-class","sql-ast"],"backgroundTag":"unknown-table-reference","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}