diff --git a/hibernate-core/src/main/antlr/sql-gen.g b/hibernate-core/src/main/antlr/sql-gen.g index ab9151d86c..031586a1e0 100644 --- a/hibernate-core/src/main/antlr/sql-gen.g +++ b/hibernate-core/src/main/antlr/sql-gen.g @@ -193,13 +193,13 @@ whereClauseExpr orderExprs { String ordExp = null; String ordDir = null; String ordNul = null; } // TODO: remove goofy space before the comma when we don't have to regression test anymore. - // Dialect is provided a hook to render each ORDER BY element, so the expression is being captured instead of + // Dialect is provided a hook to render each ORDER BY element(except SQL_TOKEN), so the expression is being captured instead of // printing to the SQL output directly. See Dialect#renderOrderByElement(String, String, String, NullPrecedence). : { captureExpressionStart(); } ( e:expr ) { captureExpressionFinish(); ordExp = resetCapture(); } (dir:orderDirection { ordDir = #dir.getText(); })? (ordNul=nullOrdering)? - // SQL Tokens without a direction and null ordering can be passed through as-is. + // SQL Tokens can be passed through as-is. // These tokens could be mapping defined order by fragments which are already rendered via the dialect hook - { out( #e.getType() == SQL_TOKEN && ordDir == null && ordNul == null ? ordExp : renderOrderByElement( ordExp, ordDir, ordNul ) ); } + { out( #e.getType() == SQL_TOKEN ? ordExp : renderOrderByElement( ordExp, ordDir, ordNul ) ); } ( {out(", "); } orderExprs )? ; diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/FromClause.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/FromClause.java index 0288159da8..2e03bf1130 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/FromClause.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/FromClause.java @@ -91,13 +91,23 @@ public class FromClause extends HqlSqlWalkerNode implements HqlSqlTokenTypes, Di } } + void moveFromElementToEnd(FromElement element) { + fromElements.remove( element ); + fromElements.add( element ); + } + public void finishInit() { - // Insert EntityJoinFromElements while maintaining their original position during depth-first traversal. + // Insert the from elements into the AST in the same order as they were added to the HQL AST FromElement lastFromElement = null; for ( FromElement fromElement : fromElements ) { - if ( fromElement instanceof EntityJoinFromElement ) { - assert lastFromElement != null; - ASTUtil.insertChild( lastFromElement, fromElement ); + if ( fromElement instanceof ComponentJoin ) { + // Component joins are no "real" joins, so they can't be put into the AST + continue; + } + fromElement.setFirstChild( null ); + fromElement.setNextSibling( null ); + if ( lastFromElement != null ) { + ASTUtil.appendChild( lastFromElement, fromElement ); } lastFromElement = fromElement; } diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/FromElement.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/FromElement.java index b4cf19dd7b..91237a8955 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/FromElement.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/FromElement.java @@ -642,6 +642,9 @@ public class FromElement extends HqlSqlWalkerNode implements DisplayableNode, Pa } public void setWithClauseFragment(AST ast, String withClauseFragment) { + // Normally, the from element is added first, but since the with clause could introduce joins, + // we have to move the from element to the end to retain the proper join order + getFromClause().moveFromElementToEnd( this ); this.withClauseAst = ast; this.withClauseFragment = withClauseFragment; }