HHH-2802 : order-by mapping -> support for property names
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@15359 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
13ddb15f29
commit
538982e8e6
|
@ -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>
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
;
|
|
@ -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
|
||||
;
|
|
@ -80,12 +80,12 @@ import org.hibernate.sql.Alias;
|
|||
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 @@ public abstract class AbstractCollectionPersister
|
|||
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 @@ public abstract class AbstractCollectionPersister
|
|||
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 @@ public abstract class AbstractCollectionPersister
|
|||
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 @@ public abstract class AbstractCollectionPersister
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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,10 +565,25 @@ public abstract class AbstractCollectionPersister
|
|||
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 abstract class AbstractCollectionPersister
|
|||
}
|
||||
|
||||
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 abstract class AbstractCollectionPersister
|
|||
}
|
||||
|
||||
public boolean hasManyToManyOrdering() {
|
||||
return isManyToMany() && manyToManyOrderByTemplate != null;
|
||||
return isManyToMany() && hasManyToManyOrder;
|
||||
}
|
||||
|
||||
public boolean hasWhere() {
|
||||
|
|
|
@ -30,6 +30,10 @@ import java.util.StringTokenizer;
|
|||
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 @@ public final class Template {
|
|||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes order by clause provided in the mapping attribute and interpolates the alias.
|
||||
* Handles asc, desc, SQL functions, quoted identifiers.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
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('.');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
boolean quotedOrWhitespace = quoted ||
|
||||
quotedIdentifier ||
|
||||
isQuoteCharacter ||
|
||||
Character.isWhitespace( token.charAt(0) );
|
||||
|
||||
if (quotedOrWhitespace) {
|
||||
result.append(token);
|
||||
}
|
||||
else if (
|
||||
isIdentifier(token, dialect) &&
|
||||
!isFunctionOrKeyword(lcToken, nextToken, dialect, functionRegistry)
|
||||
) {
|
||||
result.append(TEMPLATE)
|
||||
.append('.')
|
||||
.append( dialect.quote(token) );
|
||||
}
|
||||
else {
|
||||
result.append(token);
|
||||
}
|
||||
public static class NoOpColumnMapper implements ColumnMapper {
|
||||
public static final NoOpColumnMapper INSTANCE = new NoOpColumnMapper();
|
||||
public String[] map(String reference) {
|
||||
return new String[] { reference };
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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 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;
|
||||
}
|
||||
|
||||
public Dialect getDialect() {
|
||||
return dialect;
|
||||
}
|
||||
|
||||
public SQLFunctionRegistry getSqlFunctionRegistry() {
|
||||
return functionRegistry;
|
||||
}
|
||||
|
||||
public ColumnMapper getColumnMapper() {
|
||||
return columnMapper;
|
||||
}
|
||||
};
|
||||
|
||||
OrderByFragmentTranslator translator = new OrderByFragmentTranslator( context );
|
||||
return translator.render( orderByFragment );
|
||||
}
|
||||
|
||||
private static boolean isNamedParameter(String token) {
|
||||
return token.startsWith(":");
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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() );
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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.rootLogger=info, stdout
|
|||
|
||||
log4j.logger.org.hibernate.test=info
|
||||
log4j.logger.org.hibernate.tool.hbm2ddl=debug
|
||||
log4j.logger.org.hibernate.sql.ordering.antlr.OrderByFragmentTranslator=trace
|
Loading…
Reference in New Issue