[hibernate-commits] Hibernate SVN: r15359 - in core/trunk/core: src/main/antlr and 7 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Mon Oct 20 13:57:45 EDT 2008


Author: steve.ebersole at jboss.com
Date: 2008-10-20 13:57:44 -0400 (Mon, 20 Oct 2008)
New Revision: 15359

Added:
   core/trunk/core/src/main/antlr/order-by-render.g
   core/trunk/core/src/main/antlr/order-by.g
   core/trunk/core/src/main/java/org/hibernate/sql/ordering/
   core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/
   core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/CollationSpecification.java
   core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/ColumnMapper.java
   core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/Factory.java
   core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/Node.java
   core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/NodeSupport.java
   core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/OrderByFragment.java
   core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/OrderByFragmentParser.java
   core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/OrderByFragmentRenderer.java
   core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/OrderByFragmentTranslator.java
   core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/OrderingSpecification.java
   core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/SortKey.java
   core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/SortSpecification.java
   core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/TranslationContext.java
   core/trunk/core/src/test/java/org/hibernate/sql/
   core/trunk/core/src/test/java/org/hibernate/sql/TemplateTest.java
Modified:
   core/trunk/core/pom.xml
   core/trunk/core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java
   core/trunk/core/src/main/java/org/hibernate/sql/Template.java
   core/trunk/core/src/test/resources/log4j.properties
Log:
HHH-2802 : order-by mapping -> support for property names

Modified: core/trunk/core/pom.xml
===================================================================
--- core/trunk/core/pom.xml	2008-10-20 17:13:25 UTC (rev 15358)
+++ core/trunk/core/pom.xml	2008-10-20 17:57:44 UTC (rev 15359)
@@ -77,7 +77,7 @@
                 <artifactId>antlr-maven-plugin</artifactId>
                 <version>${antlrPluginVersion}</version>
                 <configuration>
-                    <grammars>hql.g,hql-sql.g,sql-gen.g</grammars>
+                    <grammars>hql.g,hql-sql.g,sql-gen.g,order-by.g,order-by-render.g</grammars>
                 </configuration>
                 <executions>
                     <execution>

Added: core/trunk/core/src/main/antlr/order-by-render.g
===================================================================
--- core/trunk/core/src/main/antlr/order-by-render.g	                        (rev 0)
+++ core/trunk/core/src/main/antlr/order-by-render.g	2008-10-20 17:57:44 UTC (rev 15359)
@@ -0,0 +1,92 @@
+header
+{
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ *
+ */
+package org.hibernate.sql.ordering.antlr;
+}
+/**
+ * Antlr grammar for rendering <tt>ORDER_BY</tt> trees as described by the {@link OrderByFragmentParser}
+
+ * @author Steve Ebersole
+ */
+class GeneratedOrderByFragmentRenderer extends TreeParser;
+
+options {
+	importVocab=OrderByTemplate;
+	buildAST=false;
+}
+
+{
+    // the buffer to which we write the resulting SQL.
+	private StringBuffer buffer = new StringBuffer();
+
+	protected void out(String text) {
+	    buffer.append( text );
+	}
+
+	protected void out(AST ast) {
+	    buffer.append( ast.getText() );
+	}
+
+    /*package*/ String getRenderedFragment() {
+        return buffer.toString();
+    }
+}
+
+orderByFragment
+    : #(
+        ORDER_BY sortSpecification ( {out(", ");} sortSpecification)*
+    )
+    ;
+
+sortSpecification
+    : #(
+        SORT_SPEC sortKeySpecification (collationSpecification)? (orderingSpecification)?
+    )
+    ;
+
+sortKeySpecification
+    : #(SORT_KEY sortKey)
+    ;
+
+sortKey
+    : i:IDENT {
+        out( #i );
+    }
+    ;
+
+collationSpecification
+    : c:COLLATE {
+        out( " collate " );
+        out( c );
+    }
+    ;
+
+orderingSpecification
+    : o:ORDER_SPEC {
+        out( " " );
+        out( #o );
+    }
+    ;
\ No newline at end of file

Added: core/trunk/core/src/main/antlr/order-by.g
===================================================================
--- core/trunk/core/src/main/antlr/order-by.g	                        (rev 0)
+++ core/trunk/core/src/main/antlr/order-by.g	2008-10-20 17:57:44 UTC (rev 15359)
@@ -0,0 +1,440 @@
+header
+{
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ *
+ */
+package org.hibernate.sql.ordering.antlr;
+}
+/**
+ * Antlr grammar for dealing with <tt>order-by</tt> mapping fragments.
+
+ * @author Steve Ebersole
+ */
+class GeneratedOrderByFragmentParser extends Parser;
+
+options
+{
+	exportVocab=OrderByTemplate;
+	buildAST=true;
+	k=3;
+}
+
+tokens
+{
+    // synthetic tokens
+    ORDER_BY;
+    SORT_SPEC;
+    ORDER_SPEC;
+    SORT_KEY;
+    EXPR_LIST;
+    DOT;
+    IDENT_LIST;
+    COLUMN_REF;
+
+    COLLATE="collate";
+	ASCENDING="asc";
+	DESCENDING="desc";
+}
+
+
+{
+    /**
+     * Method for logging execution trace information.
+     *
+     * @param msg The trace message.
+     */
+    protected void trace(String msg) {
+        System.out.println( msg );
+    }
+
+    /**
+     * Extract a node's text.
+     *
+     * @param ast The node
+     *
+     * @return The text.
+     */
+    protected final String extractText(AST ast) {
+        // for some reason, within AST creation blocks "[]" I am somtimes unable to refer to the AST.getText() method
+        // using #var (the #var is not interpreted as the rule's output AST).
+        return ast.getText();
+    }
+
+    /**
+     * Process the given node as a quote identifier.  These need to be quoted in the dialect-specific way.
+     *
+     * @param ident The quoted-identifier node.
+     *
+     * @return The processed node.
+     *
+     * @see org.hibernate.dialect.Dialect#quote
+     */
+    protected AST quotedIdentifier(AST ident) {
+        return ident;
+    }
+
+    /**
+     * Process the given node as a quote string.
+     *
+     * @param ident The quoted string.  This is used from within function param recognition, and represents a
+     * SQL-quoted string.
+     *
+     * @return The processed node.
+     */
+    protected AST quotedString(AST ident) {
+        return ident;
+    }
+
+    /**
+     * A check to see if the text of the given node represents a known function name.
+     *
+     * @param ast The node whose text we want to check.
+     *
+     * @return True if the node's text is a known function name, false otherwise.
+     *
+     * @see org.hibernate.dialect.function.SQLFunctionRegistry
+     */
+    protected boolean isFunctionName(AST ast) {
+        return false;
+    }
+
+    /**
+     * Process the given node as a function.
+     *
+     * @param The node representing the function invocation (including parameters as subtree components).
+     *
+     * @return The processed node.
+     */
+    protected AST resolveFunction(AST ast) {
+        return ast;
+    }
+
+    /**
+     * Process the given node as an IDENT.  May represent either a column reference or a property reference.
+     *
+     * @param ident The node whose text represents either a column or property reference.
+     *
+     * @return The processed node.
+     */
+    protected AST resolveIdent(AST ident) {
+        return ident;
+    }
+
+    /**
+     * Allow post processing of each <tt>sort specification</tt>
+     *
+     * @param The grammar-built sort specification subtree.
+     *
+     * @return The processed sort specification subtree.
+     */
+    protected AST postProcessSortSpecification(AST sortSpec) {
+        return sortSpec;
+    }
+
+}
+
+/**
+ * Main recognition rule for this grammar
+ */
+orderByFragment { trace("orderByFragment"); }
+    : sortSpecification ( COMMA! sortSpecification  )* {
+        #orderByFragment = #( [ORDER_BY, "order-by"], #orderByFragment );
+    }
+    ;
+
+/**
+ * Reconition rule for what ANSI SQL terms the <tt>sort specification</tt>, which is essentially each thing upon which
+ * the results should be sorted.
+ */
+sortSpecification { trace("sortSpecification"); }
+    : sortKey (collationSpecification)? (orderingSpecification)? {
+        #sortSpecification = #( [SORT_SPEC, "{sort specification}"], #sortSpecification );
+        #sortSpecification = postProcessSortSpecification( #sortSpecification );
+    }
+    ;
+
+/**
+ * Reconition rule for what ANSI SQL terms the <tt>sort key</tt> which is the expression (column, function, etc) upon
+ * which to base the sorting.
+ */
+sortKey! { trace("sortKey"); }
+    : e:expression {
+        #sortKey = #( [SORT_KEY, "sort key"], #e );
+    }
+    ;
+
+/**
+ * Reconition rule what this grammar recognizes as valid <tt>sort key</tt>.
+ */
+expression! { trace("expression"); }
+    : HARD_QUOTE qi:IDENT HARD_QUOTE {
+        #expression = quotedIdentifier( #qi );
+    }
+    | ( IDENT (DOT IDENT)* OPEN_PAREN ) => f:functionCall {
+        #expression = #f;
+    }
+    | p:simplePropertyPath {
+        #expression = resolveIdent( #p );
+    }
+    | i:IDENT {
+        if ( isFunctionName( #i ) ) {
+            #expression = resolveFunction( #i );
+        }
+        else {
+            #expression = resolveIdent( #i );
+        }
+    }
+    ;
+
+/**
+ * Intended for use as a syntactic predicate to determine whether an IDENT represents a known SQL function name.
+ */
+functionCallCheck! { trace("functionCallCheck"); }
+    : IDENT (DOT IDENT)* OPEN_PAREN { true }?
+    ;
+
+/**
+ * Recognition rule for a function call
+ */
+functionCall! { trace("functionCall"); }
+    : fn:functionName OPEN_PAREN pl:functionParameterList CLOSE_PAREN {
+        #functionCall = #( [IDENT, extractText( #fn )], #pl );
+        #functionCall = resolveFunction( #functionCall );
+    }
+    ;
+
+/**
+ * A function-name is an IDENT followed by zero or more (DOT IDENT) sequences
+ */
+functionName {
+        trace("functionName");
+        StringBuffer buffer = new StringBuffer();
+    }
+    : i:IDENT { buffer.append( i.getText() ); }
+            ( DOT i2:IDENT { buffer.append( '.').append( i2.getText() ); } )* {
+        #functionName = #( [IDENT,buffer.toString()] );
+    }
+    ;
+
+/**
+ * Recognition rule used to "wrap" all function parameters into an EXPR_LIST node
+ */
+functionParameterList { trace("functionParameterList"); }
+    : functionParameter ( COMMA! functionParameter )* {
+        #functionParameterList = #( [EXPR_LIST, "{param list}"], #functionParameterList );
+    }
+    ;
+
+/**
+ * Recognized function parameters.
+ */
+functionParameter { trace("functionParameter"); }
+    : expression
+    | NUM_DOUBLE
+    | NUM_FLOAT
+    | NUM_INT
+    | NUM_LONG
+    | QUOTED_STRING {
+        #functionParameter = quotedString( #functionParameter );
+    }
+    ;
+
+/**
+ * Reconition rule for what ANSI SQL terms the <tt>collation specification</tt> used to allow specifying that sorting for
+ * the given {@link #sortSpecification} be treated within a specific character-set.
+ */
+collationSpecification! { trace("collationSpecification"); }
+    : c:COLLATE cn:collationName {
+        #collationSpecification = #( [COLLATE, extractText( #cn )] );
+    }
+    ;
+
+/**
+ * The collation name wrt {@link #collationSpecification}.  Namely, the character-set.
+ */
+collationName { trace("collationSpecification"); }
+    : IDENT
+    ;
+
+/**
+ * Reconition rule for what ANSI SQL terms the <tt>ordering specification</tt>; <tt>ASCENDING</tt> or
+ * <tt>DESCENDING</tt>.
+ */
+orderingSpecification! { trace("orderingSpecification"); }
+    : ( "asc" | "ascending" ) {
+        #orderingSpecification = #( [ORDER_SPEC, "asc"] );
+    }
+    | ( "desc" | "descending") {
+        #orderingSpecification = #( [ORDER_SPEC, "desc"] );
+    }
+    ;
+
+/**
+ * A simple-property-path is an IDENT followed by one or more (DOT IDENT) sequences
+ */
+simplePropertyPath {
+        trace("simplePropertyPath");
+        StringBuffer buffer = new StringBuffer();
+    }
+    : i:IDENT { buffer.append( i.getText() ); }
+            ( DOT i2:IDENT { buffer.append( '.').append( i2.getText() ); } )+ {
+        #simplePropertyPath = #( [IDENT,buffer.toString()] );
+    }
+    ;
+
+
+// **** LEXER ******************************************************************
+
+/**
+ * Lexer for the <tt>order-by</tt> fragment parser
+
+ * @author Steve Ebersole
+ * @author Joshua Davis
+ */
+class GeneratedOrderByLexer extends Lexer;
+
+options {
+	exportVocab=OrderByTemplate;
+	testLiterals = false;
+	k=2;
+	charVocabulary='\u0000'..'\uFFFE';	// Allow any char but \uFFFF (16 bit -1, ANTLR's EOF character)
+	caseSensitive = false;
+	caseSensitiveLiterals = false;
+}
+
+// -- Keywords --
+
+OPEN_PAREN: '(';
+CLOSE_PAREN: ')';
+
+COMMA: ',';
+
+HARD_QUOTE: '`';
+
+IDENT options { testLiterals=true; }
+	: ID_START_LETTER ( ID_LETTER )*
+	;
+
+protected
+ID_START_LETTER
+    :    '_'
+    |    '$'
+    |    'a'..'z'
+    |    '\u0080'..'\ufffe'       // HHH-558 : Allow unicode chars in identifiers
+    ;
+
+protected
+ID_LETTER
+    :    ID_START_LETTER
+    |    '0'..'9'
+    ;
+
+QUOTED_STRING
+	  : '\'' ( (ESCqs)=> ESCqs | ~'\'' )* '\''
+	;
+
+protected
+ESCqs
+	:
+		'\'' '\''
+	;
+
+//--- From the Java example grammar ---
+// a numeric literal
+NUM_INT
+	{boolean isDecimal=false; Token t=null;}
+	:   '.' {_ttype = DOT;}
+			(	('0'..'9')+ (EXPONENT)? (f1:FLOAT_SUFFIX {t=f1;})?
+				{
+					if (t != null && t.getText().toUpperCase().indexOf('F')>=0)
+					{
+						_ttype = NUM_FLOAT;
+					}
+					else
+					{
+						_ttype = NUM_DOUBLE; // assume double
+					}
+				}
+			)?
+	|	(	'0' {isDecimal = true;} // special case for just '0'
+			(	('x')
+				(											// hex
+					// the 'e'|'E' and float suffix stuff look
+					// like hex digits, hence the (...)+ doesn't
+					// know when to stop: ambig.  ANTLR resolves
+					// it correctly by matching immediately.  It
+					// is therefore ok to hush warning.
+					options { warnWhenFollowAmbig=false; }
+				:	HEX_DIGIT
+				)+
+			|	('0'..'7')+									// octal
+			)?
+		|	('1'..'9') ('0'..'9')*  {isDecimal=true;}		// non-zero decimal
+		)
+		(	('l') { _ttype = NUM_LONG; }
+
+		// only check to see if it's a float if looks like decimal so far
+		|	{isDecimal}?
+			(   '.' ('0'..'9')* (EXPONENT)? (f2:FLOAT_SUFFIX {t=f2;})?
+			|   EXPONENT (f3:FLOAT_SUFFIX {t=f3;})?
+			|   f4:FLOAT_SUFFIX {t=f4;}
+			)
+			{
+				if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0)
+				{
+					_ttype = NUM_FLOAT;
+				}
+				else
+				{
+					_ttype = NUM_DOUBLE; // assume double
+				}
+			}
+		)?
+	;
+
+// hexadecimal digit (again, note it's protected!)
+protected
+HEX_DIGIT
+	:	('0'..'9'|'a'..'f')
+	;
+
+// a couple protected methods to assist in matching floating point numbers
+protected
+EXPONENT
+	:	('e') ('+'|'-')? ('0'..'9')+
+	;
+
+protected
+FLOAT_SUFFIX
+	:	'f'|'d'
+	;
+
+WS  :   (   ' '
+		|   '\t'
+		|   '\r' '\n' { newline(); }
+		|   '\n'      { newline(); }
+		|   '\r'      { newline(); }
+		)
+		{$setType(Token.SKIP);} //ignore this token
+	;

Modified: core/trunk/core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java	2008-10-20 17:13:25 UTC (rev 15358)
+++ core/trunk/core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java	2008-10-20 17:57:44 UTC (rev 15359)
@@ -80,12 +80,12 @@
 import org.hibernate.sql.SelectFragment;
 import org.hibernate.sql.SimpleSelect;
 import org.hibernate.sql.Template;
+import org.hibernate.sql.ordering.antlr.ColumnMapper;
 import org.hibernate.type.AbstractComponentType;
 import org.hibernate.type.CollectionType;
 import org.hibernate.type.EntityType;
 import org.hibernate.type.Type;
 import org.hibernate.util.ArrayHelper;
-import org.hibernate.util.CollectionHelper;
 import org.hibernate.util.FilterHelper;
 import org.hibernate.util.StringHelper;
 
@@ -113,7 +113,6 @@
 	private final String sqlDetectRowByIndexString;
 	private final String sqlDetectRowByElementString;
 
-	private final String sqlOrderByString;
 	protected final String sqlWhereString;
 	private final String sqlOrderByStringTemplate;
 	private final String sqlWhereStringTemplate;
@@ -197,7 +196,7 @@
 	private final String manyToManyWhereString;
 	private final String manyToManyWhereTemplate;
 
-	private final String manyToManyOrderByString;
+	private final boolean hasManyToManyOrder;
 	private final String manyToManyOrderByTemplate;
 
 	// custom sql
@@ -266,12 +265,7 @@
 		for ( int i = 1; i < spacesSize; i++ ) {
 			spaces[i] = (String) iter.next();
 		}
-		
-		sqlOrderByString = collection.getOrderBy();
-		hasOrder = sqlOrderByString != null;
-		sqlOrderByStringTemplate = hasOrder ?
-				Template.renderOrderByStringTemplate(sqlOrderByString, dialect, factory.getSqlFunctionRegistry()) :
-				null;
+
 		sqlWhereString = StringHelper.isNotEmpty( collection.getWhere() ) ? "( " + collection.getWhere() + ") " : null;
 		hasWhere = sqlWhereString != null;
 		sqlWhereStringTemplate = hasWhere ?
@@ -540,7 +534,26 @@
 					);
 			}
 		}
-			
+
+		hasOrder = collection.getOrderBy() != null;
+		if ( hasOrder ) {
+			ColumnMapper mapper = new ColumnMapper() {
+				public String[] map(String reference) {
+					return elementPropertyMapping.toColumns( reference );
+				}
+			};
+			sqlOrderByStringTemplate = Template.renderOrderByStringTemplate(
+					collection.getOrderBy(),
+					mapper,
+					factory,
+					dialect,
+					factory.getSqlFunctionRegistry()
+			);
+		}
+		else {
+			sqlOrderByStringTemplate = null;
+		}
+
 		// Handle any filters applied to this collection
 		filterHelper = new FilterHelper( collection.getFilterMap(), dialect, factory.getSqlFunctionRegistry() );
 
@@ -552,11 +565,26 @@
 		manyToManyWhereTemplate = manyToManyWhereString == null ?
 				null :
 				Template.renderWhereStringTemplate( manyToManyWhereString, factory.getDialect(), factory.getSqlFunctionRegistry() );
-		manyToManyOrderByString = collection.getManyToManyOrdering();
-		manyToManyOrderByTemplate = manyToManyOrderByString == null
-				? null
-	            : Template.renderOrderByStringTemplate( manyToManyOrderByString, factory.getDialect(), factory.getSqlFunctionRegistry() );
 
+		hasManyToManyOrder = collection.getManyToManyOrdering() != null;
+		if ( hasManyToManyOrder ) {
+			ColumnMapper mapper = new ColumnMapper() {
+				public String[] map(String reference) {
+					return elementPropertyMapping.toColumns( reference );
+				}
+			};
+			manyToManyOrderByTemplate = Template.renderOrderByStringTemplate(
+					collection.getManyToManyOrdering(),
+					mapper,
+					factory,
+					dialect,
+					factory.getSqlFunctionRegistry()
+			);
+		}
+		else {
+			manyToManyOrderByTemplate = null;
+		}
+
 		initCollectionPropertyMap();
 	}
 
@@ -658,17 +686,15 @@
 	}
 
 	public String getSQLOrderByString(String alias) {
-		return hasOrdering() ? 
-			StringHelper.replace( sqlOrderByStringTemplate, Template.TEMPLATE, alias ) : "";
+		return hasOrdering()
+				? StringHelper.replace( sqlOrderByStringTemplate, Template.TEMPLATE, alias )
+				: "";
 	}
 
 	public String getManyToManyOrderByString(String alias) {
-		if ( isManyToMany() && manyToManyOrderByString != null ) {
-			return StringHelper.replace( manyToManyOrderByTemplate, Template.TEMPLATE, alias );
-		}
-		else {
-			return "";
-		}
+		return hasManyToManyOrdering()
+				? StringHelper.replace( manyToManyOrderByTemplate, Template.TEMPLATE, alias )
+				: "";
 	}
 	public FetchMode getFetchMode() {
 		return fetchMode;
@@ -679,7 +705,7 @@
 	}
 
 	public boolean hasManyToManyOrdering() {
-		return isManyToMany() && manyToManyOrderByTemplate != null;
+		return isManyToMany() && hasManyToManyOrder;
 	}
 
 	public boolean hasWhere() {

Modified: core/trunk/core/src/main/java/org/hibernate/sql/Template.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/sql/Template.java	2008-10-20 17:13:25 UTC (rev 15358)
+++ core/trunk/core/src/main/java/org/hibernate/sql/Template.java	2008-10-20 17:57:44 UTC (rev 15359)
@@ -30,6 +30,10 @@
 import org.hibernate.dialect.Dialect;
 import org.hibernate.dialect.function.SQLFunctionRegistry;
 import org.hibernate.util.StringHelper;
+import org.hibernate.sql.ordering.antlr.ColumnMapper;
+import org.hibernate.sql.ordering.antlr.TranslationContext;
+import org.hibernate.sql.ordering.antlr.OrderByFragmentTranslator;
+import org.hibernate.engine.SessionFactoryImplementor;
 
 /**
  * Parses SQL fragments specified in mapping documents
@@ -233,93 +237,79 @@
 		return result.toString();
 	}
 
+	public static class NoOpColumnMapper implements ColumnMapper {
+		public static final NoOpColumnMapper INSTANCE = new NoOpColumnMapper();
+		public String[] map(String reference) {
+			return new String[] { reference };
+		}
+	}
+
 	/**
-	 * Takes order by clause provided in the mapping attribute and interpolates the alias.
-	 * Handles asc, desc, SQL functions, quoted identifiers.
+	 * Performs order-by template rendering without {@link ColumnMapper column mapping}.  An <tt>ORDER BY</tt> template
+	 * has all column references "qualified" with a placeholder identified by {@link Template#TEMPLATE}
+	 *
+	 * @param orderByFragment The order-by fragment to render.
+	 * @param dialect The SQL dialect being used.
+	 * @param functionRegistry The SQL function registry
+	 *
+	 * @return The rendered <tt>ORDER BY</tt> template.
+	 * 
+	 * @see #renderOrderByStringTemplate(String,ColumnMapper,SessionFactoryImplementor,Dialect,SQLFunctionRegistry)
 	 */
-	public static String renderOrderByStringTemplate(String sqlOrderByString, Dialect dialect, SQLFunctionRegistry functionRegistry) {
-		//TODO: make this a bit nicer
-		String symbols = new StringBuffer()
-			.append("=><!+-*/()',|&`")
-			.append(StringHelper.WHITESPACE)
-			.append( dialect.openQuote() )
-			.append( dialect.closeQuote() )
-			.toString();
-		StringTokenizer tokens = new StringTokenizer(sqlOrderByString, symbols, true);
-		
-		StringBuffer result = new StringBuffer();
-		boolean quoted = false;
-		boolean quotedIdentifier = false;
-		
-		boolean hasMore = tokens.hasMoreTokens();
-		String nextToken = hasMore ? tokens.nextToken() : null;
-		while (hasMore) {
-			String token = nextToken;
-			String lcToken = token.toLowerCase();
-			hasMore = tokens.hasMoreTokens();
-			nextToken = hasMore ? tokens.nextToken() : null;
-			
-			boolean isQuoteCharacter = false;
-			
-			if ( !quotedIdentifier && "'".equals(token) ) {
-				quoted = !quoted;
-				isQuoteCharacter = true;
+	public static String renderOrderByStringTemplate(
+			String orderByFragment,
+			Dialect dialect,
+			SQLFunctionRegistry functionRegistry) {
+		return renderOrderByStringTemplate(
+				orderByFragment,
+				NoOpColumnMapper.INSTANCE,
+				null,
+				dialect,
+				functionRegistry
+		);
+	}
+
+	/**
+	 * Performs order-by template rendering allowing {@link ColumnMapper column mapping}.  An <tt>ORDER BY</tt> template
+	 * has all column references "qualified" with a placeholder identified by {@link Template#TEMPLATE} which can later
+	 * be used to easily inject the SQL alias.
+	 *
+	 * @param orderByFragment The order-by fragment to render.
+	 * @param columnMapper The column mapping strategy to use.
+	 * @param sessionFactory The session factory.
+	 * @param dialect The SQL dialect being used.
+	 * @param functionRegistry The SQL function registry
+	 *
+	 * @return The rendered <tt>ORDER BY</tt> template.
+	 */
+	public static String renderOrderByStringTemplate(
+			String orderByFragment,
+			final ColumnMapper columnMapper,
+			final SessionFactoryImplementor sessionFactory,
+			final Dialect dialect,
+			final SQLFunctionRegistry functionRegistry) {
+		TranslationContext context = new TranslationContext() {
+			public SessionFactoryImplementor getSessionFactory() {
+				return sessionFactory;
 			}
-			
-			if ( !quoted ) {
-				
-				boolean isOpenQuote;
-				if ( "`".equals(token) ) {
-					isOpenQuote = !quotedIdentifier;
-					token = lcToken = isOpenQuote ? 
-						new Character( dialect.openQuote() ).toString() :
-						new Character( dialect.closeQuote() ).toString();
-					quotedIdentifier = isOpenQuote;	
-					isQuoteCharacter = true;
-				}
-				else if ( !quotedIdentifier && ( dialect.openQuote()==token.charAt(0) ) ) {
-					isOpenQuote = true;
-					quotedIdentifier = true;	
-					isQuoteCharacter = true;
-				}
-				else if ( quotedIdentifier && ( dialect.closeQuote()==token.charAt(0) ) ) {
-					quotedIdentifier = false;
-					isQuoteCharacter = true;
-					isOpenQuote = false;
-				}
-				else {
-					isOpenQuote = false;
-				}
-				
-				if (isOpenQuote) {
-					result.append(TEMPLATE).append('.');
-				}
-				
+
+			public Dialect getDialect() {
+				return dialect;
 			}
-	
-			boolean quotedOrWhitespace = quoted || 
-				quotedIdentifier || 
-				isQuoteCharacter || 
-				Character.isWhitespace( token.charAt(0) );
-			
-			if (quotedOrWhitespace) {
-				result.append(token);
+
+			public SQLFunctionRegistry getSqlFunctionRegistry() {
+				return functionRegistry;
 			}
-			else if (
-				isIdentifier(token, dialect) &&
-				!isFunctionOrKeyword(lcToken, nextToken, dialect, functionRegistry)
-			) {
-				result.append(TEMPLATE)
-					.append('.')
-					.append( dialect.quote(token) );
+
+			public ColumnMapper getColumnMapper() {
+				return columnMapper;
 			}
-			else {
-				result.append(token);
-			}
-		}
-		return result.toString();
+		};
+
+		OrderByFragmentTranslator translator = new OrderByFragmentTranslator( context );
+		return translator.render( orderByFragment );
 	}
-	
+
 	private static boolean isNamedParameter(String token) {
 		return token.startsWith(":");
 	}

Added: core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/CollationSpecification.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/CollationSpecification.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/CollationSpecification.java	2008-10-20 17:57:44 UTC (rev 15359)
@@ -0,0 +1,34 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ *
+ */
+package org.hibernate.sql.ordering.antlr;
+
+/**
+ * Models a collation specification (<tt>COLLATE</tt> using a specific character-set) within a
+ * {@link SortSpecification}.
+ *
+ * @author Steve Ebersole
+ */
+public class CollationSpecification extends NodeSupport {
+}

Added: core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/ColumnMapper.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/ColumnMapper.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/ColumnMapper.java	2008-10-20 17:57:44 UTC (rev 15359)
@@ -0,0 +1,46 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ *
+ */
+package org.hibernate.sql.ordering.antlr;
+
+import org.hibernate.HibernateException;
+
+/**
+ * Contract for mapping a (an assumed) property reference to its columns.
+ *
+ * @author Steve Ebersole
+ */
+public interface ColumnMapper {
+	/**
+	 * Resolve the property reference to its underlying columns.
+	 *
+	 * @param reference The property reference name.
+	 *
+	 * @return The underlying columns, or null if the property reference is unknown.
+	 *
+	 * @throws HibernateException Generally indicates that the property reference is unkown; interpretation is the
+	 * same as a null return.
+	 */
+	public String[] map(String reference) throws HibernateException;
+}

Added: core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/Factory.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/Factory.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/Factory.java	2008-10-20 17:57:44 UTC (rev 15359)
@@ -0,0 +1,54 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ *
+ */
+package org.hibernate.sql.ordering.antlr;
+
+import antlr.ASTFactory;
+
+/**
+ * Acts as a {@link ASTFactory} for injecting our specific AST node classes into the Antlr generated trees.
+ *
+ * @author Steve Ebersole
+ */
+public class Factory extends ASTFactory implements OrderByTemplateTokenTypes {
+	/**
+	 * {@inheritDoc}
+	 */
+	public Class getASTNodeType(int i) {
+		switch ( i ) {
+			case ORDER_BY:
+				return OrderByFragment.class;
+			case SORT_SPEC:
+				return SortSpecification.class;
+			case ORDER_SPEC:
+				return OrderingSpecification.class;
+			case COLLATE:
+				return CollationSpecification.class;
+			case SORT_KEY:
+				return SortKey.class;
+			default:
+				return NodeSupport.class;
+		}
+	}
+}

Added: core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/Node.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/Node.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/Node.java	2008-10-20 17:57:44 UTC (rev 15359)
@@ -0,0 +1,53 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ *
+ */
+package org.hibernate.sql.ordering.antlr;
+
+/**
+ * General contract for AST nodes.
+ *
+ * @author Steve Ebersole
+ */
+public interface Node {
+	/**
+	 * Get the intrinsic text of this node.
+	 *
+	 * @return The node's text.
+	 */
+	public String getText();
+
+	/**
+	 * Get a string representation of this node usable for debug logging or similar.
+	 *
+	 * @return The node's debugging text.
+	 */
+	public String getDebugText();
+
+	/**
+	 * Build the node's representation for use in the resulting rendering.
+	 *
+	 * @return The renderable text.
+	 */
+	public String getRenderableText();
+}

Added: core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/NodeSupport.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/NodeSupport.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/NodeSupport.java	2008-10-20 17:57:44 UTC (rev 15359)
@@ -0,0 +1,48 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ *
+ */
+package org.hibernate.sql.ordering.antlr;
+
+import antlr.CommonAST;
+
+/**
+ * Basic implementation of a {@link Node}.
+ *
+ * @author Steve Ebersole
+ */
+public class NodeSupport extends CommonAST implements Node {
+	/**
+	 * {@inheritDoc}
+	 */
+	public String getDebugText() {
+		return getText();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public String getRenderableText() {
+		return getText();
+	}
+}

Added: core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/OrderByFragment.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/OrderByFragment.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/OrderByFragment.java	2008-10-20 17:57:44 UTC (rev 15359)
@@ -0,0 +1,33 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ *
+ */
+package org.hibernate.sql.ordering.antlr;
+
+/**
+ * Represents a parsed <tt>order-by</tt> mapping fragment.  This holds the tree of all {@link SortSpecification}s.
+ *
+ * @author Steve Ebersole
+ */
+public class OrderByFragment extends NodeSupport {
+}

Added: core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/OrderByFragmentParser.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/OrderByFragmentParser.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/OrderByFragmentParser.java	2008-10-20 17:57:44 UTC (rev 15359)
@@ -0,0 +1,194 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ *
+ */
+package org.hibernate.sql.ordering.antlr;
+
+import java.util.ArrayList;
+
+import antlr.TokenStream;
+import antlr.CommonAST;
+import antlr.collections.AST;
+
+import org.hibernate.sql.Template;
+import org.hibernate.dialect.function.SQLFunction;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Extension of the Antlr-generated parser for the purpose of adding our custom parsing behavior.
+ *
+ * @author Steve Ebersole
+ */
+public class OrderByFragmentParser extends GeneratedOrderByFragmentParser {
+	private static final Logger log = LoggerFactory.getLogger( OrderByFragmentParser.class );
+
+	private final TranslationContext context;
+
+	public OrderByFragmentParser(TokenStream lexer, TranslationContext context) {
+		super( lexer );
+		super.setASTFactory( new Factory() );
+		this.context = context;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	protected void trace(String msg) {
+		log.trace( msg );
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	protected AST quotedIdentifier(AST ident) {
+		return getASTFactory().create(
+				OrderByTemplateTokenTypes.IDENT,
+				Template.TEMPLATE + "." + context.getDialect().quote( '`' + ident.getText() + '`' )
+		);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	protected AST quotedString(AST ident) {
+		return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, context.getDialect().quote( ident.getText() ) );
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	protected boolean isFunctionName(AST ast) {
+		return context.getSqlFunctionRegistry().hasFunction( ast.getText() );
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	protected AST resolveFunction(AST ast) {
+		AST child = ast.getFirstChild();
+		assert "{param list}".equals(  child.getText() );
+		child = child.getFirstChild();
+
+		final String functionName = ast.getText();
+		final SQLFunction function = context.getSqlFunctionRegistry().findSQLFunction( functionName );
+		if ( function == null ) {
+			String text = functionName;
+			if ( child != null ) {
+				text += '(';
+				while ( child != null ) {
+					text += child.getText();
+					child = child.getNextSibling();
+					if ( child != null ) {
+						text += ", ";
+					}
+				}
+				text += ')';
+			}
+			return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, text );
+		}
+		else {
+			ArrayList expressions = new ArrayList();
+			while ( child != null ) {
+				expressions.add( child.getText() );
+				child = child.getNextSibling();
+			}
+			final String text = function.render( expressions, context.getSessionFactory() );
+			return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, text );
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	protected AST resolveIdent(AST ident) {
+		String text = ident.getText();
+		String[] replacements;
+		try {
+			replacements = context.getColumnMapper().map( text );
+		}
+		catch( Throwable t ) {
+			replacements = null;
+		}
+
+		if ( replacements == null || replacements.length == 0 ) {
+			return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, Template.TEMPLATE + "." + ident );
+		}
+		else if ( replacements.length == 1 ) {
+			return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, Template.TEMPLATE + "." + replacements[0] );
+		}
+		else {
+			final AST root = getASTFactory().create( OrderByTemplateTokenTypes.IDENT_LIST, "{ident list}" );
+			for ( int i = 0; i < replacements.length; i++ ) {
+				final String identText = Template.TEMPLATE + '.' + replacements[i];
+				root.addChild( getASTFactory().create( OrderByTemplateTokenTypes.IDENT, identText ) );
+			}
+			return root;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	protected AST postProcessSortSpecification(AST sortSpec) {
+		assert SORT_SPEC == sortSpec.getType();
+		SortSpecification sortSpecification = ( SortSpecification ) sortSpec;
+		AST sortKey = sortSpecification.getSortKey();
+		if ( IDENT_LIST == sortKey.getFirstChild().getType() ) {
+			AST identList = sortKey.getFirstChild();
+			AST ident = identList.getFirstChild();
+			AST holder = new CommonAST();
+			do {
+				holder.addChild(
+						createSortSpecification(
+								ident,
+								sortSpecification.getCollation(),
+								sortSpecification.getOrdering()
+						)
+				);
+				ident = ident.getNextSibling();
+			} while ( ident != null );
+			sortSpec = holder.getFirstChild();
+		}
+		return sortSpec;
+	}
+
+	private SortSpecification createSortSpecification(
+			AST ident,
+			CollationSpecification collationSpecification,
+			OrderingSpecification orderingSpecification) {
+		AST sortSpecification = getASTFactory().create( SORT_SPEC, "{{sort specification}}" );
+		AST sortKey = getASTFactory().create( SORT_KEY, "{{sort key}}" );
+		AST newIdent = getASTFactory().create( ident.getType(), ident.getText() );
+		sortKey.setFirstChild( newIdent );
+		sortSpecification.setFirstChild( sortKey );
+		if ( collationSpecification != null ) {
+			sortSpecification.addChild( collationSpecification );
+		}
+		if ( orderingSpecification != null ) {
+			sortSpecification.addChild( orderingSpecification );
+		}
+		return ( SortSpecification ) sortSpecification;
+	}
+}

Added: core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/OrderByFragmentRenderer.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/OrderByFragmentRenderer.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/OrderByFragmentRenderer.java	2008-10-20 17:57:44 UTC (rev 15359)
@@ -0,0 +1,38 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ *
+ */
+package org.hibernate.sql.ordering.antlr;
+
+import antlr.collections.AST;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+public class OrderByFragmentRenderer extends GeneratedOrderByFragmentRenderer {
+	protected void out(AST ast) {
+		out( ( ( Node ) ast ).getRenderableText() );
+	}
+}

Added: core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/OrderByFragmentTranslator.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/OrderByFragmentTranslator.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/OrderByFragmentTranslator.java	2008-10-20 17:57:44 UTC (rev 15359)
@@ -0,0 +1,87 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ *
+ */
+package org.hibernate.sql.ordering.antlr;
+
+import java.io.StringReader;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.hibernate.HibernateException;
+import org.hibernate.hql.ast.util.ASTPrinter;
+
+/**
+ * A translator which coordinates translation of an <tt>order-by</tt> mapping.
+ *
+ * @author Steve Ebersole
+ */
+public class OrderByFragmentTranslator {
+	private static final Logger log = LoggerFactory.getLogger( OrderByFragmentTranslator.class );
+
+	public final TranslationContext context;
+
+	public OrderByFragmentTranslator(TranslationContext context) {
+		this.context = context;
+	}
+
+	/**
+	 * The main contract, performing the transaction.
+	 *
+	 * @param fragment The <tt>order-by</tt> mapping fragment to be translated.
+	 *
+	 * @return The translated fragment.
+	 */
+	public String render(String fragment) {
+		GeneratedOrderByLexer lexer = new GeneratedOrderByLexer( new StringReader( fragment ) );
+		OrderByFragmentParser parser = new OrderByFragmentParser( lexer, context );
+		try {
+			parser.orderByFragment();
+		}
+		catch ( HibernateException e ) {
+			throw e;
+		}
+		catch ( Throwable t ) {
+			throw new HibernateException( "Unable to parse order-by fragment", t );
+		}
+
+		if ( log.isTraceEnabled() ) {
+			ASTPrinter printer = new ASTPrinter( OrderByTemplateTokenTypes.class );
+			log.trace( printer.showAsString( parser.getAST(), "--- {order-by fragment} ---" ) );
+		}
+
+		GeneratedOrderByFragmentRenderer renderer = new GeneratedOrderByFragmentRenderer();
+		try {
+			renderer.orderByFragment( parser.getAST() );
+		}
+		catch ( HibernateException e ) {
+			throw e;
+		}
+		catch ( Throwable t ) {
+			throw new HibernateException( "Unable to render parsed order-by fragment", t );
+		}
+
+		return renderer.getRenderedFragment();
+	}
+}

Added: core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/OrderingSpecification.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/OrderingSpecification.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/OrderingSpecification.java	2008-10-20 17:57:44 UTC (rev 15359)
@@ -0,0 +1,70 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ *
+ */
+package org.hibernate.sql.ordering.antlr;
+
+/**
+ * Models an ordering specification (<tt>ASCENDING</tt> or <tt>DESCENDING</tt>) within a {@link SortSpecification}.
+ *
+ * @author Steve Ebersole
+ */
+public class OrderingSpecification extends NodeSupport {
+	public static class Ordering {
+		public static final Ordering ASCENDING = new Ordering( "asc" );
+		public static final Ordering DESCENDING = new Ordering( "desc" );
+
+		private final String name;
+
+		private Ordering(String name) {
+			this.name = name;
+		}
+	}
+
+	private boolean resolved;
+	private Ordering ordering;
+
+	public Ordering getOrdering() {
+		if ( !resolved ) {
+			ordering = resolve( getText() );
+			resolved = true;
+		}
+		return ordering;
+	}
+
+	private static Ordering resolve(String text) {
+		if ( Ordering.ASCENDING.name.equals( text ) ) {
+			return Ordering.ASCENDING;
+		}
+		else if ( Ordering.DESCENDING.name.equals( text ) ) {
+			return Ordering.DESCENDING;
+		}
+		else {
+			throw new IllegalStateException( "Unknown ordering [" + text + "]" );
+		}
+	}
+
+	public String getRenderableText() {
+		return getOrdering().name;
+	}
+}

Added: core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/SortKey.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/SortKey.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/SortKey.java	2008-10-20 17:57:44 UTC (rev 15359)
@@ -0,0 +1,34 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ *
+ */
+package org.hibernate.sql.ordering.antlr;
+
+/**
+ * Models the container node for the <tt>sort key</tt>, which is the term given by the ANSI SQL specification to the
+ * expression upon which to sort for each {@link SortSpecification}
+ *
+ * @author Steve Ebersole
+ */
+public class SortKey extends NodeSupport {
+}

Added: core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/SortSpecification.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/SortSpecification.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/SortSpecification.java	2008-10-20 17:57:44 UTC (rev 15359)
@@ -0,0 +1,80 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ *
+ */
+package org.hibernate.sql.ordering.antlr;
+
+import antlr.collections.AST;
+
+/**
+ * Models each sorting exprersion.
+ *
+ * @author Steve Ebersole
+ */
+public class SortSpecification extends NodeSupport {
+	/**
+	 * Locate the specified {@link SortKey}.
+	 *
+	 * @return The sort key.
+	 */
+	public SortKey getSortKey() {
+		return ( SortKey ) getFirstChild();
+	}
+
+	/**
+	 * Locate the specified <tt>collation specification</tt>, if one.
+	 *
+	 * @return The <tt>collation specification</tt>, or null if none was specified.
+	 */
+	public CollationSpecification getCollation() {
+		AST possible = getSortKey().getNextSibling();
+		return  possible != null && OrderByTemplateTokenTypes.COLLATE == possible.getType()
+				? ( CollationSpecification ) possible
+				: null;
+	}
+
+	/**
+	 * Locate the specified <tt>ordering specification</tt>, if one.
+	 *
+	 * @return The <tt>ordering specification</tt>, or null if none was specified.
+	 */
+	public OrderingSpecification getOrdering() {
+		// IMPL NOTE : the ordering-spec would be either the 2nd or 3rd child (of the overall sort-spec), if it existed,
+		// 		depending on whether a collation-spec was specified.
+
+		AST possible = getSortKey().getNextSibling();
+		if ( possible == null ) {
+			// There was no sort-spec parts specified other then the sort-key so there can be no ordering-spec...
+			return null;
+		}
+
+		if ( OrderByTemplateTokenTypes.COLLATE == possible.getType() ) {
+			// the 2nd child was a collation-spec, so we need to check the 3rd child instead.
+			possible = possible.getNextSibling();
+		}
+
+		return possible != null && OrderByTemplateTokenTypes.ORDER_SPEC == possible.getType()
+				?  ( OrderingSpecification ) possible
+				:  null;
+	}
+}

Added: core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/TranslationContext.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/TranslationContext.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/sql/ordering/antlr/TranslationContext.java	2008-10-20 17:57:44 UTC (rev 15359)
@@ -0,0 +1,64 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ *
+ */
+package org.hibernate.sql.ordering.antlr;
+
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.function.SQLFunctionRegistry;
+
+/**
+ * Contract for contextual information required to perform translation.
+*
+* @author Steve Ebersole
+*/
+public interface TranslationContext {
+	/**
+	 * Retrieves the <tt>session factory</tt> for this context.
+	 *
+	 * @return The <tt>session factory</tt>
+	 */
+	public SessionFactoryImplementor getSessionFactory();
+
+	/**
+	 * Retrieves the <tt>dialect</tt> for this context.
+	 *
+	 * @return The <tt>dialect</tt>
+	 */
+	public Dialect getDialect();
+
+	/**
+	 * Retrieves the <tt>SQL function registry/tt> for this context.
+	 *
+	 * @return The SQL function registry.
+	 */
+	public SQLFunctionRegistry getSqlFunctionRegistry();
+
+	/**
+	 * Retrieves the <tt>column mapper</tt> for this context.
+	 *
+	 * @return The <tt>column mapper</tt>
+	 */
+	public ColumnMapper getColumnMapper();
+}

Added: core/trunk/core/src/test/java/org/hibernate/sql/TemplateTest.java
===================================================================
--- core/trunk/core/src/test/java/org/hibernate/sql/TemplateTest.java	                        (rev 0)
+++ core/trunk/core/src/test/java/org/hibernate/sql/TemplateTest.java	2008-10-20 17:57:44 UTC (rev 15359)
@@ -0,0 +1,184 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ *
+ */
+package org.hibernate.sql;
+
+import java.util.Collections;
+
+import junit.framework.TestCase;
+
+import org.hibernate.persister.entity.PropertyMapping;
+import org.hibernate.type.Type;
+import org.hibernate.QueryException;
+import org.hibernate.sql.ordering.antlr.ColumnMapper;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.dialect.function.SQLFunctionRegistry;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+public class TemplateTest extends TestCase {
+	private static final PropertyMapping PROPERTY_MAPPING = new PropertyMapping() {
+		public String[] toColumns(String propertyName) throws QueryException, UnsupportedOperationException {
+			if ( "sql".equals( propertyName ) ) {
+				return new String[] { "sql" };
+			}
+			else if ( "component".equals( propertyName ) ) {
+				return new String[] { "comp_1", "comp_2" };
+			}
+			else if ( "component.prop1".equals( propertyName ) ) {
+				return new String[] { "comp_1" };
+			}
+			else if ( "component.prop2".equals( propertyName ) ) {
+				return new String[] { "comp_2" };
+			}
+			else if ( "property".equals( propertyName ) ) {
+				return new String[] { "prop" };
+			}
+			throw new QueryException( "could not resolve property: " + propertyName );
+		}
+
+		public Type toType(String propertyName) throws QueryException {
+			return null;
+		}
+
+		public String[] toColumns(String alias, String propertyName) throws QueryException {
+			return new String[0];
+		}
+
+		public Type getType() {
+			return null;
+		}
+	};
+
+	private static final ColumnMapper MAPPER = new ColumnMapper() {
+		public String[] map(String reference) {
+			return PROPERTY_MAPPING.toColumns( reference );
+		}
+	};
+
+	private static final Dialect DIALECT = new HSQLDialect();
+
+	private static final SQLFunctionRegistry FUNCTION_REGISTRY = new SQLFunctionRegistry( DIALECT, Collections.EMPTY_MAP );
+
+	public void testSQLReferences() {
+		String fragment = "sql asc, sql desc";
+		String template = doStandardRendering( fragment );
+
+		assertEquals( Template.TEMPLATE + ".sql asc, " + Template.TEMPLATE + ".sql desc", template );
+	}
+
+	public void testQuotedSQLReferences() {
+		String fragment = "`sql` asc, `sql` desc";
+		String template = doStandardRendering( fragment );
+
+		assertEquals( Template.TEMPLATE + ".\"sql\" asc, " + Template.TEMPLATE + ".\"sql\" desc", template );
+	}
+
+	public void testPropertyReference() {
+		String fragment = "property asc, property desc";
+		String template = doStandardRendering( fragment );
+
+		assertEquals( Template.TEMPLATE + ".prop asc, " + Template.TEMPLATE + ".prop desc", template );
+	}
+
+	public void testFunctionReference() {
+		String fragment = "upper(sql) asc, lower(sql) desc";
+		String template = doStandardRendering( fragment );
+
+		assertEquals( "upper(" + Template.TEMPLATE + ".sql) asc, lower(" + Template.TEMPLATE + ".sql) desc", template );
+	}
+
+	public void testQualifiedFunctionReference() {
+		String fragment = "qual.upper(property) asc, qual.lower(property) desc";
+		String template = doStandardRendering( fragment );
+
+		assertEquals( "qual.upper(" + Template.TEMPLATE + ".prop) asc, qual.lower(" + Template.TEMPLATE + ".prop) desc", template );
+	}
+
+	public void testDoubleQualifiedFunctionReference() {
+		String fragment = "qual1.qual2.upper(property) asc, qual1.qual2.lower(property) desc";
+		String template = doStandardRendering( fragment );
+
+		assertEquals( "qual1.qual2.upper(" + Template.TEMPLATE + ".prop) asc, qual1.qual2.lower(" + Template.TEMPLATE + ".prop) desc", template );
+	}
+
+	public void testFunctionWithPropertyReferenceAsParam() {
+		String fragment = "upper(property) asc, lower(property) desc";
+		String template = doStandardRendering( fragment );
+
+		assertEquals( "upper(" + Template.TEMPLATE + ".prop) asc, lower(" + Template.TEMPLATE + ".prop) desc", template );
+	}
+
+	public void testNestedFunctionReferences() {
+		String fragment = "upper(lower(sql)) asc, lower(upper(sql)) desc";
+		String template = doStandardRendering( fragment );
+
+		assertEquals( "upper(lower(" + Template.TEMPLATE + ".sql)) asc, lower(upper(" + Template.TEMPLATE + ".sql)) desc", template );
+	}
+
+	public void testComplexNestedFunctionReferences() {
+		String fragment = "mod(mod(sql,2),3) asc";
+		String template = doStandardRendering( fragment );
+
+		assertEquals( "mod(mod(" + Template.TEMPLATE + ".sql, 2), 3) asc", template );
+	}
+
+	public void testCollation() {
+		String fragment = "`sql` COLLATE my_collation, `sql` COLLATE your_collation";
+		String template = doStandardRendering( fragment );
+
+		assertEquals( Template.TEMPLATE + ".\"sql\" collate my_collation, " + Template.TEMPLATE + ".\"sql\" collate your_collation", template );
+	}
+
+	public void testCollationAndOrdering() {
+		String fragment = "sql COLLATE my_collation, upper(prop) COLLATE your_collation asc, `sql` desc";
+		String template = doStandardRendering( fragment );
+
+		assertEquals( Template.TEMPLATE + ".sql collate my_collation, upper(" + Template.TEMPLATE + ".prop) collate your_collation asc, " + Template.TEMPLATE + ".\"sql\" desc", template );
+
+	}
+
+	public void testComponentReferences() {
+		String fragment = "component asc";
+		String template = doStandardRendering( fragment );
+
+		assertEquals( Template.TEMPLATE + ".comp_1 asc, " + Template.TEMPLATE + ".comp_2 asc", template );
+
+	}
+
+	public void testComponentDerefReferences() {
+		String fragment = "component.prop1 asc";
+		String template = doStandardRendering( fragment );
+
+		assertEquals( Template.TEMPLATE + ".comp_1 asc", template );
+	}
+
+	public String doStandardRendering(String fragment) {
+		return Template.renderOrderByStringTemplate( fragment, MAPPER, null, DIALECT, FUNCTION_REGISTRY );
+	}
+}
\ No newline at end of file

Modified: core/trunk/core/src/test/resources/log4j.properties
===================================================================
--- core/trunk/core/src/test/resources/log4j.properties	2008-10-20 17:13:25 UTC (rev 15358)
+++ core/trunk/core/src/test/resources/log4j.properties	2008-10-20 17:57:44 UTC (rev 15359)
@@ -21,7 +21,6 @@
 # 51 Franklin Street, Fifth Floor
 # Boston, MA  02110-1301  USA
 #
-#
 log4j.appender.stdout=org.apache.log4j.ConsoleAppender
 log4j.appender.stdout.Target=System.out
 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
@@ -31,3 +30,4 @@
 
 log4j.logger.org.hibernate.test=info
 log4j.logger.org.hibernate.tool.hbm2ddl=debug
+log4j.logger.org.hibernate.sql.ordering.antlr.OrderByFragmentTranslator=trace
\ No newline at end of file




More information about the hibernate-commits mailing list