HHH-4394 - @OrderBy usage on a joined classes (when using join table) produces incorred SQL syntax.
This commit is contained in:
parent
41bac11115
commit
d51a0d0c78
|
@ -164,7 +164,7 @@ orderByFragment { trace("orderByFragment"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reconition rule for what ANSI SQL terms the <tt>sort specification</tt>, which is essentially each thing upon which
|
* Recognition rule for what ANSI SQL terms the <tt>sort specification</tt>, which is essentially each thing upon which
|
||||||
* the results should be sorted.
|
* the results should be sorted.
|
||||||
*/
|
*/
|
||||||
sortSpecification { trace("sortSpecification"); }
|
sortSpecification { trace("sortSpecification"); }
|
||||||
|
@ -175,7 +175,7 @@ sortSpecification { trace("sortSpecification"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reconition rule for what ANSI SQL terms the <tt>sort key</tt> which is the expression (column, function, etc) upon
|
* Recognition rule for what ANSI SQL terms the <tt>sort key</tt> which is the expression (column, function, etc) upon
|
||||||
* which to base the sorting.
|
* which to base the sorting.
|
||||||
*/
|
*/
|
||||||
sortKey! { trace("sortKey"); }
|
sortKey! { trace("sortKey"); }
|
||||||
|
@ -185,7 +185,7 @@ sortKey! { trace("sortKey"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reconition rule what this grammar recognizes as valid <tt>sort key</tt>.
|
* Recognition rule what this grammar recognizes as valid <tt>sort key</tt>.
|
||||||
*/
|
*/
|
||||||
expression! { trace("expression"); }
|
expression! { trace("expression"); }
|
||||||
: HARD_QUOTE qi:IDENT HARD_QUOTE {
|
: HARD_QUOTE qi:IDENT HARD_QUOTE {
|
||||||
|
@ -261,7 +261,7 @@ functionParameter { trace("functionParameter"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reconition rule for what ANSI SQL terms the <tt>collation specification</tt> used to allow specifying that sorting for
|
* Recognition 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.
|
* the given {@link #sortSpecification} be treated within a specific character-set.
|
||||||
*/
|
*/
|
||||||
collationSpecification! { trace("collationSpecification"); }
|
collationSpecification! { trace("collationSpecification"); }
|
||||||
|
@ -278,7 +278,7 @@ collationName { trace("collationSpecification"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reconition rule for what ANSI SQL terms the <tt>ordering specification</tt>; <tt>ASCENDING</tt> or
|
* Recognition rule for what ANSI SQL terms the <tt>ordering specification</tt>; <tt>ASCENDING</tt> or
|
||||||
* <tt>DESCENDING</tt>.
|
* <tt>DESCENDING</tt>.
|
||||||
*/
|
*/
|
||||||
orderingSpecification! { trace("orderingSpecification"); }
|
orderingSpecification! { trace("orderingSpecification"); }
|
||||||
|
|
|
@ -23,14 +23,6 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.cfg.annotations;
|
package org.hibernate.cfg.annotations;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.StringTokenizer;
|
|
||||||
import javax.persistence.AttributeOverride;
|
import javax.persistence.AttributeOverride;
|
||||||
import javax.persistence.AttributeOverrides;
|
import javax.persistence.AttributeOverrides;
|
||||||
import javax.persistence.ElementCollection;
|
import javax.persistence.ElementCollection;
|
||||||
|
@ -43,6 +35,11 @@ import javax.persistence.ManyToMany;
|
||||||
import javax.persistence.MapKey;
|
import javax.persistence.MapKey;
|
||||||
import javax.persistence.MapKeyColumn;
|
import javax.persistence.MapKeyColumn;
|
||||||
import javax.persistence.OneToMany;
|
import javax.persistence.OneToMany;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
@ -110,9 +107,7 @@ import org.hibernate.mapping.KeyValue;
|
||||||
import org.hibernate.mapping.ManyToOne;
|
import org.hibernate.mapping.ManyToOne;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
import org.hibernate.mapping.Property;
|
import org.hibernate.mapping.Property;
|
||||||
import org.hibernate.mapping.Selectable;
|
|
||||||
import org.hibernate.mapping.SimpleValue;
|
import org.hibernate.mapping.SimpleValue;
|
||||||
import org.hibernate.mapping.SingleTableSubclass;
|
|
||||||
import org.hibernate.mapping.Table;
|
import org.hibernate.mapping.Table;
|
||||||
import org.hibernate.mapping.TypeDef;
|
import org.hibernate.mapping.TypeDef;
|
||||||
|
|
||||||
|
@ -946,192 +941,39 @@ public abstract class CollectionBinder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String buildOrderByClauseFromHql(String hqlOrderBy, PersistentClass associatedClass, String role) {
|
private static String buildOrderByClauseFromHql(String orderByFragment, PersistentClass associatedClass, String role) {
|
||||||
String orderByString = null;
|
if ( orderByFragment != null ) {
|
||||||
if ( hqlOrderBy != null ) {
|
if ( orderByFragment.length() == 0 ) {
|
||||||
List<String> properties = new ArrayList<String>();
|
|
||||||
List<String> ordering = new ArrayList<String>();
|
|
||||||
StringBuilder orderByBuffer = new StringBuilder();
|
|
||||||
if ( hqlOrderBy.length() == 0 ) {
|
|
||||||
//order by id
|
//order by id
|
||||||
Iterator it = associatedClass.getIdentifier().getColumnIterator();
|
return "id asc";
|
||||||
while ( it.hasNext() ) {
|
|
||||||
Selectable col = (Selectable) it.next();
|
|
||||||
orderByBuffer.append( col.getText() ).append( " asc" ).append( ", " );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else if ( "desc".equals( orderByFragment ) ) {
|
||||||
StringTokenizer st = new StringTokenizer( hqlOrderBy, " ,", false );
|
return "id desc";
|
||||||
String currentOrdering = null;
|
|
||||||
//FIXME make this code decent
|
|
||||||
while ( st.hasMoreTokens() ) {
|
|
||||||
String token = st.nextToken();
|
|
||||||
if ( isNonPropertyToken( token ) ) {
|
|
||||||
if ( currentOrdering != null ) {
|
|
||||||
throw new AnnotationException(
|
|
||||||
"Error while parsing HQL orderBy clause: " + hqlOrderBy
|
|
||||||
+ " (" + role + ")"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
currentOrdering = token;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//Add ordering of the previous
|
|
||||||
if ( currentOrdering == null ) {
|
|
||||||
//default ordering
|
|
||||||
ordering.add( "asc" );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ordering.add( currentOrdering );
|
|
||||||
currentOrdering = null;
|
|
||||||
}
|
|
||||||
properties.add( token );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ordering.remove( 0 ); //first one is the algorithm starter
|
|
||||||
// add last one ordering
|
|
||||||
if ( currentOrdering == null ) {
|
|
||||||
//default ordering
|
|
||||||
ordering.add( "asc" );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ordering.add( currentOrdering );
|
|
||||||
currentOrdering = null;
|
|
||||||
}
|
|
||||||
int index = 0;
|
|
||||||
|
|
||||||
for (String property : properties) {
|
|
||||||
Property p = BinderHelper.findPropertyByName( associatedClass, property );
|
|
||||||
if ( p == null ) {
|
|
||||||
throw new AnnotationException(
|
|
||||||
"property from @OrderBy clause not found: "
|
|
||||||
+ associatedClass.getEntityName() + "." + property
|
|
||||||
);
|
|
||||||
}
|
|
||||||
PersistentClass pc = p.getPersistentClass();
|
|
||||||
String table;
|
|
||||||
if ( pc == null ) {
|
|
||||||
//we are touching a @IdClass property, the pc is not set
|
|
||||||
//this means pc == associatedClass
|
|
||||||
//TODO check whether @ManyToOne @JoinTable in @IdClass used for @OrderBy works: doh!
|
|
||||||
table = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (pc == associatedClass
|
|
||||||
|| (associatedClass instanceof SingleTableSubclass && pc
|
|
||||||
.getMappedClass().isAssignableFrom(
|
|
||||||
associatedClass.getMappedClass()))) {
|
|
||||||
table = "";
|
|
||||||
} else {
|
|
||||||
table = pc.getTable().getQuotedName() + ".";
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator propertyColumns = p.getColumnIterator();
|
|
||||||
while ( propertyColumns.hasNext() ) {
|
|
||||||
Selectable column = (Selectable) propertyColumns.next();
|
|
||||||
orderByBuffer.append( table )
|
|
||||||
.append( column.getText() )
|
|
||||||
.append( " " )
|
|
||||||
.append( ordering.get( index ) )
|
|
||||||
.append( ", " );
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
orderByString = orderByBuffer.substring( 0, orderByBuffer.length() - 2 );
|
|
||||||
}
|
|
||||||
return orderByString;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String buildOrderByClauseFromHql(String hqlOrderBy, Component component, String role) {
|
|
||||||
String orderByString = null;
|
|
||||||
if ( hqlOrderBy != null ) {
|
|
||||||
List<String> properties = new ArrayList<String>();
|
|
||||||
List<String> ordering = new ArrayList<String>();
|
|
||||||
StringBuilder orderByBuffer = new StringBuilder();
|
|
||||||
if ( hqlOrderBy.length() == 0 ) {
|
|
||||||
//TODO : Check that. Maybe order by key for maps
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
StringTokenizer st = new StringTokenizer( hqlOrderBy, " ,", false );
|
|
||||||
String currentOrdering = null;
|
|
||||||
//FIXME make this code decent
|
|
||||||
while ( st.hasMoreTokens() ) {
|
|
||||||
String token = st.nextToken();
|
|
||||||
if ( isNonPropertyToken( token ) ) {
|
|
||||||
if ( currentOrdering != null ) {
|
|
||||||
throw new AnnotationException(
|
|
||||||
"Error while parsing HQL orderBy clause: " + hqlOrderBy
|
|
||||||
+ " (" + role + ")"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
currentOrdering = token;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//Add ordering of the previous
|
|
||||||
if ( currentOrdering == null ) {
|
|
||||||
//default ordering
|
|
||||||
ordering.add( "asc" );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ordering.add( currentOrdering );
|
|
||||||
currentOrdering = null;
|
|
||||||
}
|
|
||||||
properties.add( token );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ordering.remove( 0 ); //first one is the algorithm starter
|
|
||||||
// add last one ordering
|
|
||||||
if ( currentOrdering == null ) {
|
|
||||||
//default ordering
|
|
||||||
ordering.add( "asc" );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ordering.add( currentOrdering );
|
|
||||||
currentOrdering = null;
|
|
||||||
}
|
|
||||||
int index = 0;
|
|
||||||
|
|
||||||
for (String property : properties) {
|
|
||||||
Property p = BinderHelper.findPropertyByName( component, property );
|
|
||||||
if ( p == null ) {
|
|
||||||
throw new AnnotationException(
|
|
||||||
"property from @OrderBy clause not found: "
|
|
||||||
+ role + "." + property
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator propertyColumns = p.getColumnIterator();
|
|
||||||
while ( propertyColumns.hasNext() ) {
|
|
||||||
Selectable column = (Selectable) propertyColumns.next();
|
|
||||||
orderByBuffer.append( column.getText() )
|
|
||||||
.append( " " )
|
|
||||||
.append( ordering.get( index ) )
|
|
||||||
.append( ", " );
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( orderByBuffer.length() >= 2 ) {
|
|
||||||
orderByString = orderByBuffer.substring( 0, orderByBuffer.length() - 2 );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return orderByString;
|
return orderByFragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isNonPropertyToken(String token) {
|
private static String adjustUserSuppliedValueCollectionOrderingFragment(String orderByFragment) {
|
||||||
if ( " ".equals( token ) ) return true;
|
if ( orderByFragment != null ) {
|
||||||
if ( ",".equals( token ) ) return true;
|
// NOTE: "$element$" is a specially recognized collection property recognized by the collection persister
|
||||||
if ( token.equalsIgnoreCase( "desc" ) ) return true;
|
if ( orderByFragment.length() == 0 ) {
|
||||||
if ( token.equalsIgnoreCase( "asc" ) ) return true;
|
//order by element
|
||||||
return false;
|
return "$element$ asc";
|
||||||
|
}
|
||||||
|
else if ( "desc".equals( orderByFragment ) ) {
|
||||||
|
return "$element$ desc";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return orderByFragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SimpleValue buildCollectionKey(
|
private static SimpleValue buildCollectionKey(
|
||||||
Collection collValue, Ejb3JoinColumn[] joinColumns, boolean cascadeDeleteEnabled,
|
Collection collValue,
|
||||||
XProperty property, Mappings mappings
|
Ejb3JoinColumn[] joinColumns,
|
||||||
) {
|
boolean cascadeDeleteEnabled,
|
||||||
|
XProperty property,
|
||||||
|
Mappings mappings) {
|
||||||
//binding key reference using column
|
//binding key reference using column
|
||||||
KeyValue keyVal;
|
KeyValue keyVal;
|
||||||
//give a chance to override the referenced property name
|
//give a chance to override the referenced property name
|
||||||
|
@ -1406,7 +1248,7 @@ public abstract class CollectionBinder {
|
||||||
|
|
||||||
if ( StringHelper.isNotEmpty( hqlOrderBy ) ) {
|
if ( StringHelper.isNotEmpty( hqlOrderBy ) ) {
|
||||||
String path = collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName();
|
String path = collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName();
|
||||||
String orderBy = buildOrderByClauseFromHql( hqlOrderBy, component, path );
|
String orderBy = adjustUserSuppliedValueCollectionOrderingFragment( hqlOrderBy );
|
||||||
if ( orderBy != null ) {
|
if ( orderBy != null ) {
|
||||||
collValue.setOrderBy( orderBy );
|
collValue.setOrderBy( orderBy );
|
||||||
}
|
}
|
||||||
|
@ -1437,6 +1279,10 @@ public abstract class CollectionBinder {
|
||||||
elementBinder.setColumns( elementColumns );
|
elementBinder.setColumns( elementColumns );
|
||||||
elementBinder.setType( property, elementClass );
|
elementBinder.setType( property, elementClass );
|
||||||
collValue.setElement( elementBinder.make() );
|
collValue.setElement( elementBinder.make() );
|
||||||
|
String orderBy = adjustUserSuppliedValueCollectionOrderingFragment( hqlOrderBy );
|
||||||
|
if ( orderBy != null ) {
|
||||||
|
collValue.setOrderBy( orderBy );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -240,13 +240,22 @@ public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener i
|
||||||
}
|
}
|
||||||
|
|
||||||
// this class has no proxies (so do a shortcut)
|
// this class has no proxies (so do a shortcut)
|
||||||
if (!persister.hasProxy()) return load(event, persister, keyToLoad, options);
|
if (!persister.hasProxy()) {
|
||||||
|
return load(event, persister, keyToLoad, options);
|
||||||
|
}
|
||||||
|
|
||||||
final PersistenceContext persistenceContext = event.getSession().getPersistenceContext();
|
final PersistenceContext persistenceContext = event.getSession().getPersistenceContext();
|
||||||
|
|
||||||
// look for a proxy
|
// look for a proxy
|
||||||
Object proxy = persistenceContext.getProxy(keyToLoad);
|
Object proxy = persistenceContext.getProxy(keyToLoad);
|
||||||
if (proxy != null) return returnNarrowedProxy(event, persister, keyToLoad, options, persistenceContext, proxy);
|
if (proxy != null) {
|
||||||
if (options.isAllowProxyCreation()) return createProxyIfNecessary(event, persister, keyToLoad, options, persistenceContext);
|
return returnNarrowedProxy(event, persister, keyToLoad, options, persistenceContext, proxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.isAllowProxyCreation()) {
|
||||||
|
return createProxyIfNecessary(event, persister, keyToLoad, options, persistenceContext);
|
||||||
|
}
|
||||||
|
|
||||||
// return a newly loaded object
|
// return a newly loaded object
|
||||||
return load(event, persister, keyToLoad, options);
|
return load(event, persister, keyToLoad, options);
|
||||||
}
|
}
|
||||||
|
|
|
@ -930,7 +930,7 @@ public class JoinWalker {
|
||||||
if ( buf.length()>0 ) buf.setLength( buf.length()-2 );
|
if ( buf.length()>0 ) buf.setLength( buf.length()-2 );
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the where condition for a (batch) load by identifier / collection key
|
* Render the where condition for a (batch) load by identifier / collection key
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -47,6 +47,7 @@ import org.hibernate.cache.spi.entry.StructuredCollectionCacheEntry;
|
||||||
import org.hibernate.cache.spi.entry.StructuredMapCacheEntry;
|
import org.hibernate.cache.spi.entry.StructuredMapCacheEntry;
|
||||||
import org.hibernate.cache.spi.entry.UnstructuredCacheEntry;
|
import org.hibernate.cache.spi.entry.UnstructuredCacheEntry;
|
||||||
import org.hibernate.cfg.Configuration;
|
import org.hibernate.cfg.Configuration;
|
||||||
|
import org.hibernate.cfg.NotYetImplementedException;
|
||||||
import org.hibernate.collection.spi.PersistentCollection;
|
import org.hibernate.collection.spi.PersistentCollection;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey;
|
import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey;
|
||||||
|
@ -77,13 +78,21 @@ import org.hibernate.mapping.Selectable;
|
||||||
import org.hibernate.mapping.Table;
|
import org.hibernate.mapping.Table;
|
||||||
import org.hibernate.metadata.CollectionMetadata;
|
import org.hibernate.metadata.CollectionMetadata;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
import org.hibernate.persister.entity.Loadable;
|
||||||
import org.hibernate.persister.entity.PropertyMapping;
|
import org.hibernate.persister.entity.PropertyMapping;
|
||||||
|
import org.hibernate.persister.entity.Queryable;
|
||||||
import org.hibernate.pretty.MessageHelper;
|
import org.hibernate.pretty.MessageHelper;
|
||||||
import org.hibernate.sql.Alias;
|
import org.hibernate.sql.Alias;
|
||||||
import org.hibernate.sql.SelectFragment;
|
import org.hibernate.sql.SelectFragment;
|
||||||
import org.hibernate.sql.SimpleSelect;
|
import org.hibernate.sql.SimpleSelect;
|
||||||
import org.hibernate.sql.Template;
|
import org.hibernate.sql.Template;
|
||||||
import org.hibernate.sql.ordering.antlr.ColumnMapper;
|
import org.hibernate.sql.ordering.antlr.ColumnMapper;
|
||||||
|
import org.hibernate.sql.ordering.antlr.ColumnReference;
|
||||||
|
import org.hibernate.sql.ordering.antlr.FormulaReference;
|
||||||
|
import org.hibernate.sql.ordering.antlr.OrderByAliasResolver;
|
||||||
|
import org.hibernate.sql.ordering.antlr.OrderByFragmentParser;
|
||||||
|
import org.hibernate.sql.ordering.antlr.OrderByTranslation;
|
||||||
|
import org.hibernate.sql.ordering.antlr.SqlValueReference;
|
||||||
import org.hibernate.type.CollectionType;
|
import org.hibernate.type.CollectionType;
|
||||||
import org.hibernate.type.CompositeType;
|
import org.hibernate.type.CompositeType;
|
||||||
import org.hibernate.type.EntityType;
|
import org.hibernate.type.EntityType;
|
||||||
|
@ -116,11 +125,16 @@ public abstract class AbstractCollectionPersister
|
||||||
private final String sqlDetectRowByIndexString;
|
private final String sqlDetectRowByIndexString;
|
||||||
private final String sqlDetectRowByElementString;
|
private final String sqlDetectRowByElementString;
|
||||||
|
|
||||||
protected final String sqlWhereString;
|
|
||||||
private final String sqlOrderByStringTemplate;
|
|
||||||
private final String sqlWhereStringTemplate;
|
|
||||||
private final boolean hasOrder;
|
|
||||||
protected final boolean hasWhere;
|
protected final boolean hasWhere;
|
||||||
|
protected final String sqlWhereString;
|
||||||
|
private final String sqlWhereStringTemplate;
|
||||||
|
|
||||||
|
private final boolean hasOrder;
|
||||||
|
private final OrderByTranslation orderByTranslation;
|
||||||
|
|
||||||
|
private final boolean hasManyToManyOrder;
|
||||||
|
private final OrderByTranslation manyToManyOrderByTranslation;
|
||||||
|
|
||||||
private final int baseIndex;
|
private final int baseIndex;
|
||||||
|
|
||||||
private final String nodeName;
|
private final String nodeName;
|
||||||
|
@ -202,9 +216,6 @@ public abstract class AbstractCollectionPersister
|
||||||
private final String manyToManyWhereString;
|
private final String manyToManyWhereString;
|
||||||
private final String manyToManyWhereTemplate;
|
private final String manyToManyWhereTemplate;
|
||||||
|
|
||||||
private final boolean hasManyToManyOrder;
|
|
||||||
private final String manyToManyOrderByTemplate;
|
|
||||||
|
|
||||||
// custom sql
|
// custom sql
|
||||||
private final boolean insertCallable;
|
private final boolean insertCallable;
|
||||||
private final boolean updateCallable;
|
private final boolean updateCallable;
|
||||||
|
@ -549,22 +560,16 @@ public abstract class AbstractCollectionPersister
|
||||||
|
|
||||||
hasOrder = collection.getOrderBy() != null;
|
hasOrder = collection.getOrderBy() != null;
|
||||||
if ( hasOrder ) {
|
if ( hasOrder ) {
|
||||||
ColumnMapper mapper = new ColumnMapper() {
|
orderByTranslation = Template.translateOrderBy(
|
||||||
|
|
||||||
public String[] map(String reference) {
|
|
||||||
return elementPropertyMapping.toColumns( reference );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
sqlOrderByStringTemplate = Template.renderOrderByStringTemplate(
|
|
||||||
collection.getOrderBy(),
|
collection.getOrderBy(),
|
||||||
mapper,
|
new ColumnMapperImpl(),
|
||||||
factory,
|
factory,
|
||||||
dialect,
|
dialect,
|
||||||
factory.getSqlFunctionRegistry()
|
factory.getSqlFunctionRegistry()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sqlOrderByStringTemplate = null;
|
orderByTranslation = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle any filters applied to this collection
|
// Handle any filters applied to this collection
|
||||||
|
@ -581,27 +586,76 @@ public abstract class AbstractCollectionPersister
|
||||||
|
|
||||||
hasManyToManyOrder = collection.getManyToManyOrdering() != null;
|
hasManyToManyOrder = collection.getManyToManyOrdering() != null;
|
||||||
if ( hasManyToManyOrder ) {
|
if ( hasManyToManyOrder ) {
|
||||||
ColumnMapper mapper = new ColumnMapper() {
|
manyToManyOrderByTranslation = Template.translateOrderBy(
|
||||||
|
|
||||||
public String[] map(String reference) {
|
|
||||||
return elementPropertyMapping.toColumns( reference );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
manyToManyOrderByTemplate = Template.renderOrderByStringTemplate(
|
|
||||||
collection.getManyToManyOrdering(),
|
collection.getManyToManyOrdering(),
|
||||||
mapper,
|
new ColumnMapperImpl(),
|
||||||
factory,
|
factory,
|
||||||
dialect,
|
dialect,
|
||||||
factory.getSqlFunctionRegistry()
|
factory.getSqlFunctionRegistry()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
manyToManyOrderByTemplate = null;
|
manyToManyOrderByTranslation = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
initCollectionPropertyMap();
|
initCollectionPropertyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ColumnMapperImpl implements ColumnMapper {
|
||||||
|
@Override
|
||||||
|
public SqlValueReference[] map(String reference) {
|
||||||
|
final String[] columnNames;
|
||||||
|
final String[] formulaTemplates;
|
||||||
|
|
||||||
|
// handle the special "$element$" property name...
|
||||||
|
if ( "$element$".equals( reference ) ) {
|
||||||
|
columnNames = elementColumnNames;
|
||||||
|
formulaTemplates = elementFormulaTemplates;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
columnNames = elementPropertyMapping.toColumns( reference );
|
||||||
|
formulaTemplates = formulaTemplates( reference, columnNames.length );
|
||||||
|
}
|
||||||
|
|
||||||
|
final SqlValueReference[] result = new SqlValueReference[ columnNames.length ];
|
||||||
|
int i = 0;
|
||||||
|
for ( final String columnName : columnNames ) {
|
||||||
|
if ( columnName == null ) {
|
||||||
|
// if the column name is null, it indicates that this index in the property value mapping is
|
||||||
|
// actually represented by a formula.
|
||||||
|
final int propertyIndex = elementPersister.getEntityMetamodel().getPropertyIndex( reference );
|
||||||
|
final String formulaTemplate = formulaTemplates[i];
|
||||||
|
result[i] = new FormulaReference() {
|
||||||
|
@Override
|
||||||
|
public String getFormulaFragment() {
|
||||||
|
return formulaTemplate;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result[i] = new ColumnReference() {
|
||||||
|
@Override
|
||||||
|
public String getColumnName() {
|
||||||
|
return columnName;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] formulaTemplates(String reference, int expectedSize) {
|
||||||
|
try {
|
||||||
|
final int propertyIndex = elementPersister.getEntityMetamodel().getPropertyIndex( reference );
|
||||||
|
return ( (Queryable) elementPersister ).getSubclassPropertyFormulaTemplateClosure()[propertyIndex];
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
return new String[expectedSize];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void postInstantiate() throws MappingException {
|
public void postInstantiate() throws MappingException {
|
||||||
initializer = queryLoaderName == null ?
|
initializer = queryLoaderName == null ?
|
||||||
createCollectionInitializer( LoadQueryInfluencers.NONE ) :
|
createCollectionInitializer( LoadQueryInfluencers.NONE ) :
|
||||||
|
@ -693,13 +747,13 @@ public abstract class AbstractCollectionPersister
|
||||||
|
|
||||||
public String getSQLOrderByString(String alias) {
|
public String getSQLOrderByString(String alias) {
|
||||||
return hasOrdering()
|
return hasOrdering()
|
||||||
? StringHelper.replace( sqlOrderByStringTemplate, Template.TEMPLATE, alias )
|
? orderByTranslation.injectAliases( new StandardOrderByAliasResolver( alias ) )
|
||||||
: "";
|
: "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getManyToManyOrderByString(String alias) {
|
public String getManyToManyOrderByString(String alias) {
|
||||||
return hasManyToManyOrdering()
|
return hasManyToManyOrdering()
|
||||||
? StringHelper.replace( manyToManyOrderByTemplate, Template.TEMPLATE, alias )
|
? manyToManyOrderByTranslation.injectAliases( new StandardOrderByAliasResolver( alias ) )
|
||||||
: "";
|
: "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1856,4 +1910,23 @@ public abstract class AbstractCollectionPersister
|
||||||
public CollectionInitializer getInitializer() {
|
public CollectionInitializer getInitializer() {
|
||||||
return initializer;
|
return initializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class StandardOrderByAliasResolver implements OrderByAliasResolver {
|
||||||
|
private final String rootAlias;
|
||||||
|
|
||||||
|
private StandardOrderByAliasResolver(String rootAlias) {
|
||||||
|
this.rootAlias = rootAlias;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String resolveTableAlias(String columnReference) {
|
||||||
|
if ( elementPersister == null ) {
|
||||||
|
// we have collection of non-entity elements...
|
||||||
|
return rootAlias;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return ( (Loadable) elementPersister ).getTableAliasForColumn( columnReference, rootAlias );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1969,7 +1969,8 @@ public abstract class AbstractEntityPersister
|
||||||
return propertyDefinedOnSubclass[i];
|
return propertyDefinedOnSubclass[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String[][] getSubclassPropertyFormulaTemplateClosure() {
|
@Override
|
||||||
|
public String[][] getSubclassPropertyFormulaTemplateClosure() {
|
||||||
return subclassPropertyFormulaTemplateClosure;
|
return subclassPropertyFormulaTemplateClosure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4748,4 +4749,13 @@ public abstract class AbstractEntityPersister
|
||||||
public EntityInstrumentationMetadata getInstrumentationMetadata() {
|
public EntityInstrumentationMetadata getInstrumentationMetadata() {
|
||||||
return entityMetamodel.getInstrumentationMetadata();
|
return entityMetamodel.getInstrumentationMetadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTableAliasForColumn(String columnName, String rootAlias) {
|
||||||
|
return generateTableAlias( rootAlias, determineTableNumberForColumn( columnName ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public int determineTableNumberForColumn(String columnName) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -840,4 +840,24 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
}
|
}
|
||||||
return super.getSubclassPropertyDeclarer( propertyPath );
|
return super.getSubclassPropertyDeclarer( propertyPath );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int determineTableNumberForColumn(String columnName) {
|
||||||
|
final String[] subclassColumnNameClosure = getSubclassColumnClosure();
|
||||||
|
for ( int i = 0, max = subclassColumnNameClosure.length; i < max; i++ ) {
|
||||||
|
final boolean quoted = subclassColumnNameClosure[i].startsWith( "\"" )
|
||||||
|
&& subclassColumnNameClosure[i].endsWith( "\"" );
|
||||||
|
if ( quoted ) {
|
||||||
|
if ( subclassColumnNameClosure[i].equals( columnName ) ) {
|
||||||
|
return getSubclassColumnTableNumberClosure()[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( subclassColumnNameClosure[i].equalsIgnoreCase( columnName ) ) {
|
||||||
|
return getSubclassColumnTableNumberClosure()[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new HibernateException( "Could not locate table which owns column [" + columnName + "] referenced in order-by mapping" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,4 +120,18 @@ public interface Loadable extends EntityPersister {
|
||||||
* @param fetchProfileName The name of the profile affecting this.
|
* @param fetchProfileName The name of the profile affecting this.
|
||||||
*/
|
*/
|
||||||
public void registerAffectingFetchProfile(String fetchProfileName);
|
public void registerAffectingFetchProfile(String fetchProfileName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a column name and the root table alias in use for the entity hierarchy, determine the proper table alias
|
||||||
|
* for the table in that hierarchy that contains said column.
|
||||||
|
* <p/>
|
||||||
|
* NOTE : Generally speaking the column is not validated to exist. Most implementations simply return the
|
||||||
|
* root alias; the exception is {@link JoinedSubclassEntityPersister}
|
||||||
|
*
|
||||||
|
* @param columnName The column name
|
||||||
|
* @param rootAlias The hierarchy root alias
|
||||||
|
*
|
||||||
|
* @return The proper table alias for qualifying the given column.
|
||||||
|
*/
|
||||||
|
public String getTableAliasForColumn(String columnName, String rootAlias);
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,6 +170,8 @@ public interface Queryable extends Loadable, PropertyMapping, Joinable {
|
||||||
*/
|
*/
|
||||||
public DiscriminatorMetadata getTypeDiscriminatorMetadata();
|
public DiscriminatorMetadata getTypeDiscriminatorMetadata();
|
||||||
|
|
||||||
|
String[][] getSubclassPropertyFormulaTemplateClosure();
|
||||||
|
|
||||||
public static class Declarer {
|
public static class Declarer {
|
||||||
public static final Declarer CLASS = new Declarer( "class" );
|
public static final Declarer CLASS = new Declarer( "class" );
|
||||||
public static final Declarer SUBCLASS = new Declarer( "subclass" );
|
public static final Declarer SUBCLASS = new Declarer( "subclass" );
|
||||||
|
|
|
@ -37,7 +37,10 @@ import org.hibernate.dialect.function.SQLFunctionRegistry;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.sql.ordering.antlr.ColumnMapper;
|
import org.hibernate.sql.ordering.antlr.ColumnMapper;
|
||||||
|
import org.hibernate.sql.ordering.antlr.OrderByAliasResolver;
|
||||||
import org.hibernate.sql.ordering.antlr.OrderByFragmentTranslator;
|
import org.hibernate.sql.ordering.antlr.OrderByFragmentTranslator;
|
||||||
|
import org.hibernate.sql.ordering.antlr.OrderByTranslation;
|
||||||
|
import org.hibernate.sql.ordering.antlr.SqlValueReference;
|
||||||
import org.hibernate.sql.ordering.antlr.TranslationContext;
|
import org.hibernate.sql.ordering.antlr.TranslationContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -624,8 +627,9 @@ public final class Template {
|
||||||
|
|
||||||
public static class NoOpColumnMapper implements ColumnMapper {
|
public static class NoOpColumnMapper implements ColumnMapper {
|
||||||
public static final NoOpColumnMapper INSTANCE = new NoOpColumnMapper();
|
public static final NoOpColumnMapper INSTANCE = new NoOpColumnMapper();
|
||||||
public String[] map(String reference) {
|
public SqlValueReference[] map(String reference) {
|
||||||
return new String[] { reference };
|
// return new String[] { reference };
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -639,7 +643,7 @@ public final class Template {
|
||||||
*
|
*
|
||||||
* @return The rendered <tt>ORDER BY</tt> template.
|
* @return The rendered <tt>ORDER BY</tt> template.
|
||||||
*
|
*
|
||||||
* @deprecated Use {@link #renderOrderByStringTemplate(String,ColumnMapper,SessionFactoryImplementor,Dialect,SQLFunctionRegistry)} instead
|
* @deprecated Use {@link #translateOrderBy} instead
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static String renderOrderByStringTemplate(
|
public static String renderOrderByStringTemplate(
|
||||||
|
@ -655,6 +659,28 @@ public final class Template {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String renderOrderByStringTemplate(
|
||||||
|
String orderByFragment,
|
||||||
|
final ColumnMapper columnMapper,
|
||||||
|
final SessionFactoryImplementor sessionFactory,
|
||||||
|
final Dialect dialect,
|
||||||
|
final SQLFunctionRegistry functionRegistry) {
|
||||||
|
return translateOrderBy(
|
||||||
|
orderByFragment,
|
||||||
|
columnMapper,
|
||||||
|
sessionFactory,
|
||||||
|
dialect,
|
||||||
|
functionRegistry
|
||||||
|
).injectAliases( LEGACY_ORDER_BY_ALIAS_RESOLVER );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OrderByAliasResolver LEGACY_ORDER_BY_ALIAS_RESOLVER = new OrderByAliasResolver() {
|
||||||
|
@Override
|
||||||
|
public String resolveTableAlias(String columnReference) {
|
||||||
|
return TEMPLATE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs order-by template rendering allowing {@link ColumnMapper column mapping}. An <tt>ORDER BY</tt> template
|
* 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
|
* has all column references "qualified" with a placeholder identified by {@link Template#TEMPLATE} which can later
|
||||||
|
@ -668,7 +694,7 @@ public final class Template {
|
||||||
*
|
*
|
||||||
* @return The rendered <tt>ORDER BY</tt> template.
|
* @return The rendered <tt>ORDER BY</tt> template.
|
||||||
*/
|
*/
|
||||||
public static String renderOrderByStringTemplate(
|
public static OrderByTranslation translateOrderBy(
|
||||||
String orderByFragment,
|
String orderByFragment,
|
||||||
final ColumnMapper columnMapper,
|
final ColumnMapper columnMapper,
|
||||||
final SessionFactoryImplementor sessionFactory,
|
final SessionFactoryImplementor sessionFactory,
|
||||||
|
@ -692,8 +718,7 @@ public final class Template {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
OrderByFragmentTranslator translator = new OrderByFragmentTranslator( context );
|
return OrderByFragmentTranslator.translate( context, orderByFragment );
|
||||||
return translator.render( orderByFragment );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isNamedParameter(String token) {
|
private static boolean isNamedParameter(String token) {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008 Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,11 +20,9 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.sql.ordering.antlr;
|
package org.hibernate.sql.ordering.antlr;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Models a collation specification (<tt>COLLATE</tt> using a specific character-set) within a
|
* Models a collation specification (<tt>COLLATE</tt> using a specific character-set) within a
|
||||||
* {@link SortSpecification}.
|
* {@link SortSpecification}.
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008 Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,9 +20,9 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.sql.ordering.antlr;
|
package org.hibernate.sql.ordering.antlr;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,10 +36,11 @@ public interface ColumnMapper {
|
||||||
*
|
*
|
||||||
* @param reference The property reference name.
|
* @param reference The property reference name.
|
||||||
*
|
*
|
||||||
* @return The underlying columns, or null if the property reference is unknown.
|
* @return References to the columns/formulas that define the value mapping for the given property, or null
|
||||||
|
* if the property reference is unknown.
|
||||||
*
|
*
|
||||||
* @throws HibernateException Generally indicates that the property reference is unkown; interpretation is the
|
* @throws HibernateException Generally indicates that the property reference is unknown; interpretation
|
||||||
* same as a null return.
|
* should be the same as a null return.
|
||||||
*/
|
*/
|
||||||
public String[] map(String reference) throws HibernateException;
|
public SqlValueReference[] map(String reference) throws HibernateException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a column name.
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface ColumnReference extends SqlValueReference {
|
||||||
|
/**
|
||||||
|
* Retrieve the column name.
|
||||||
|
*
|
||||||
|
* @return THe column name
|
||||||
|
*/
|
||||||
|
public String getColumnName();
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008 Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,9 +20,9 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.sql.ordering.antlr;
|
package org.hibernate.sql.ordering.antlr;
|
||||||
|
|
||||||
import antlr.ASTFactory;
|
import antlr.ASTFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,9 +31,7 @@ import antlr.ASTFactory;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class Factory extends ASTFactory implements OrderByTemplateTokenTypes {
|
public class Factory extends ASTFactory implements OrderByTemplateTokenTypes {
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public Class getASTNodeType(int i) {
|
public Class getASTNodeType(int i) {
|
||||||
switch ( i ) {
|
switch ( i ) {
|
||||||
case ORDER_BY:
|
case ORDER_BY:
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a formula fragment.
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface FormulaReference extends SqlValueReference {
|
||||||
|
/**
|
||||||
|
* Retrieve the formula fragment. It is important to note that this is what the persister calls the
|
||||||
|
* "formula template", which has the $PlaceHolder$ (see {@link org.hibernate.sql.Template#TEMPLATE})
|
||||||
|
* markers injected.
|
||||||
|
*
|
||||||
|
* @return The formula fragment template.
|
||||||
|
*/
|
||||||
|
public String getFormulaFragment();
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008 Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,11 +20,9 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.sql.ordering.antlr;
|
package org.hibernate.sql.ordering.antlr;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* General contract for AST nodes.
|
* General contract for AST nodes.
|
||||||
*
|
*
|
||||||
|
@ -48,7 +46,7 @@ public interface Node {
|
||||||
/**
|
/**
|
||||||
* Build the node's representation for use in the resulting rendering.
|
* Build the node's representation for use in the resulting rendering.
|
||||||
*
|
*
|
||||||
* @return The renderable text.
|
* @return The text for use in the translated output.
|
||||||
*/
|
*/
|
||||||
public String getRenderableText();
|
public String getRenderableText();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008, Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,27 +20,23 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.sql.ordering.antlr;
|
package org.hibernate.sql.ordering.antlr;
|
||||||
|
|
||||||
import antlr.CommonAST;
|
import antlr.CommonAST;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basic implementation of a {@link Node}.
|
* Basic implementation of a {@link Node} briding to the Antlr {@link CommonAST} hierarchy.
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class NodeSupport extends CommonAST implements Node {
|
public class NodeSupport extends CommonAST implements Node {
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public String getDebugText() {
|
public String getDebugText() {
|
||||||
return getText();
|
return getText();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public String getRenderableText() {
|
public String getRenderableText() {
|
||||||
return getText();
|
return getText();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a column reference, resolve the table alias to apply to the column to qualify it.
|
||||||
|
*/
|
||||||
|
public interface OrderByAliasResolver {
|
||||||
|
/**
|
||||||
|
* Given a column reference, resolve the table alias to apply to the column to qualify it.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public String resolveTableAlias(String columnReference);
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008 Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,11 +20,9 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.sql.ordering.antlr;
|
package org.hibernate.sql.ordering.antlr;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a parsed <tt>order-by</tt> mapping fragment. This holds the tree of all {@link SortSpecification}s.
|
* Represents a parsed <tt>order-by</tt> mapping fragment. This holds the tree of all {@link SortSpecification}s.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008 Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,116 +20,99 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.sql.ordering.antlr;
|
package org.hibernate.sql.ordering.antlr;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import antlr.CommonAST;
|
import antlr.CommonAST;
|
||||||
import antlr.TokenStream;
|
import antlr.TokenStream;
|
||||||
import antlr.collections.AST;
|
import antlr.collections.AST;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
import org.hibernate.dialect.function.SQLFunction;
|
import org.hibernate.dialect.function.SQLFunction;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.sql.Template;
|
import org.hibernate.sql.Template;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extension of the Antlr-generated parser for the purpose of adding our custom parsing behavior.
|
* Extension of the Antlr-generated parser for the purpose of adding our custom parsing behavior
|
||||||
|
* (semantic analysis, etc).
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class OrderByFragmentParser extends GeneratedOrderByFragmentParser {
|
public class OrderByFragmentParser extends GeneratedOrderByFragmentParser {
|
||||||
|
private static final Logger LOG = Logger.getLogger(OrderByFragmentParser.class.getName());
|
||||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, OrderByFragmentParser.class.getName());
|
|
||||||
|
|
||||||
private final TranslationContext context;
|
private final TranslationContext context;
|
||||||
|
|
||||||
|
private Set<String> columnReferences = new HashSet<String>();
|
||||||
|
|
||||||
public OrderByFragmentParser(TokenStream lexer, TranslationContext context) {
|
public OrderByFragmentParser(TokenStream lexer, TranslationContext context) {
|
||||||
super( lexer );
|
super( lexer );
|
||||||
super.setASTFactory( new Factory() );
|
super.setASTFactory( new Factory() );
|
||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<String> getColumnReferences() {
|
||||||
// handle trace logging ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
return columnReferences;
|
||||||
|
|
||||||
private int traceDepth = 0;
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void traceIn(String ruleName) {
|
|
||||||
if ( inputState.guessing > 0 ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String prefix = StringHelper.repeat( '-', (traceDepth++ * 2) ) + "-> ";
|
|
||||||
LOG.trace(prefix + ruleName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void traceOut(String ruleName) {
|
|
||||||
if ( inputState.guessing > 0 ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String prefix = "<-" + StringHelper.repeat( '-', (--traceDepth * 2) ) + " ";
|
|
||||||
LOG.trace(prefix + ruleName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void trace(String msg) {
|
|
||||||
LOG.trace( msg );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected AST quotedIdentifier(AST ident) {
|
protected AST quotedIdentifier(AST ident) {
|
||||||
return getASTFactory().create(
|
/*
|
||||||
OrderByTemplateTokenTypes.IDENT,
|
* Semantic action used during recognition of quoted identifiers (quoted column names)
|
||||||
Template.TEMPLATE + "." + context.getDialect().quote( '`' + ident.getText() + '`' )
|
*/
|
||||||
);
|
final String columnName = context.getDialect().quote( '`' + ident.getText() + '`' );
|
||||||
|
columnReferences.add( columnName );
|
||||||
|
final String marker = '{' + columnName + '}';
|
||||||
|
return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, marker );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
protected AST quotedString(AST ident) {
|
protected AST quotedString(AST ident) {
|
||||||
|
/*
|
||||||
|
* Semantic action used during recognition of quoted strings (string literals)
|
||||||
|
*/
|
||||||
return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, context.getDialect().quote( ident.getText() ) );
|
return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, context.getDialect().quote( ident.getText() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isFunctionName(AST ast) {
|
@SuppressWarnings("SimplifiableIfStatement")
|
||||||
|
protected boolean isFunctionName(AST ast) {
|
||||||
|
/*
|
||||||
|
* Semantic predicate used to determine whether a given AST node represents a function call
|
||||||
|
*/
|
||||||
|
|
||||||
AST child = ast.getFirstChild();
|
AST child = ast.getFirstChild();
|
||||||
// assume it is a function if it has parameters
|
// assume it is a function if it has parameters
|
||||||
if ( child != null && "{param list}".equals( child.getText() ) ) {
|
if ( child != null && "{param list}".equals( child.getText() ) ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// otherwise, in order for this to be a function logically it has to be a function that does not
|
||||||
|
// have arguments. So try to assert that using the registry of known functions
|
||||||
final SQLFunction function = context.getSqlFunctionRegistry().findSQLFunction( ast.getText() );
|
final SQLFunction function = context.getSqlFunctionRegistry().findSQLFunction( ast.getText() );
|
||||||
if ( function == null ) {
|
if ( function == null ) {
|
||||||
|
// no registered function, so we cannot know for certain
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
// if function.hasParenthesesIfNoArguments() is true, then assume
|
// if function.hasParenthesesIfNoArguments() is true, then assume the node is not a function
|
||||||
// ast.getText() is not a function.
|
return ! function.hasParenthesesIfNoArguments();
|
||||||
return ! function.hasParenthesesIfNoArguments();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@SuppressWarnings("unchecked")
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
protected AST resolveFunction(AST ast) {
|
protected AST resolveFunction(AST ast) {
|
||||||
|
/*
|
||||||
|
* Semantic action used during recognition of a *known* function
|
||||||
|
*/
|
||||||
AST child = ast.getFirstChild();
|
AST child = ast.getFirstChild();
|
||||||
if ( child != null ) {
|
if ( child != null ) {
|
||||||
assert "{param list}".equals( child.getText() );
|
assert "{param list}".equals( child.getText() );
|
||||||
|
@ -143,7 +126,7 @@ public class OrderByFragmentParser extends GeneratedOrderByFragmentParser {
|
||||||
if ( child != null ) {
|
if ( child != null ) {
|
||||||
text += '(';
|
text += '(';
|
||||||
while ( child != null ) {
|
while ( child != null ) {
|
||||||
text += child.getText();
|
text += resolveFunctionArgument( child );
|
||||||
child = child.getNextSibling();
|
child = child.getNextSibling();
|
||||||
if ( child != null ) {
|
if ( child != null ) {
|
||||||
text += ", ";
|
text += ", ";
|
||||||
|
@ -156,7 +139,7 @@ public class OrderByFragmentParser extends GeneratedOrderByFragmentParser {
|
||||||
else {
|
else {
|
||||||
ArrayList expressions = new ArrayList();
|
ArrayList expressions = new ArrayList();
|
||||||
while ( child != null ) {
|
while ( child != null ) {
|
||||||
expressions.add( child.getText() );
|
expressions.add( resolveFunctionArgument( child ) );
|
||||||
child = child.getNextSibling();
|
child = child.getNextSibling();
|
||||||
}
|
}
|
||||||
final String text = function.render( null, expressions, context.getSessionFactory() );
|
final String text = function.render( null, expressions, context.getSessionFactory() );
|
||||||
|
@ -164,39 +147,119 @@ public class OrderByFragmentParser extends GeneratedOrderByFragmentParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private String resolveFunctionArgument(AST argumentNode) {
|
||||||
* {@inheritDoc}
|
final String nodeText = argumentNode.getText();
|
||||||
*/
|
final String adjustedText;
|
||||||
|
if ( nodeText.contains( Template.TEMPLATE ) ) {
|
||||||
|
// we have a SQL order-by fragment
|
||||||
|
adjustedText = adjustTemplateReferences( nodeText );
|
||||||
|
}
|
||||||
|
else if ( nodeText.startsWith( "{" ) && nodeText.endsWith( "}" ) ) {
|
||||||
|
columnReferences.add( nodeText.substring( 1, nodeText.length() - 1 ) );
|
||||||
|
return nodeText;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
adjustedText = nodeText;
|
||||||
|
// because we did not process the node text, we need to attempt to find any column references
|
||||||
|
// contained in it.
|
||||||
|
// NOTE : uses regex for the time being; we should check the performance of this
|
||||||
|
Pattern pattern = Pattern.compile( "\\{(.*)\\}" );
|
||||||
|
Matcher matcher = pattern.matcher( adjustedText );
|
||||||
|
while ( matcher.find() ) {
|
||||||
|
columnReferences.add( matcher.group( 1 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return adjustedText;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AST resolveIdent(AST ident) {
|
protected AST resolveIdent(AST ident) {
|
||||||
|
/*
|
||||||
|
* Semantic action used during recognition of an identifier. This identifier might be a column name, it might
|
||||||
|
* be a property name.
|
||||||
|
*/
|
||||||
String text = ident.getText();
|
String text = ident.getText();
|
||||||
String[] replacements;
|
SqlValueReference[] sqlValueReferences;
|
||||||
try {
|
try {
|
||||||
replacements = context.getColumnMapper().map( text );
|
sqlValueReferences = context.getColumnMapper().map( text );
|
||||||
}
|
}
|
||||||
catch( Throwable t ) {
|
catch( Throwable t ) {
|
||||||
replacements = null;
|
sqlValueReferences = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( replacements == null || replacements.length == 0 ) {
|
if ( sqlValueReferences == null || sqlValueReferences.length == 0 ) {
|
||||||
return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, Template.TEMPLATE + "." + text );
|
return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, makeColumnReference( text ) );
|
||||||
}
|
}
|
||||||
else if ( replacements.length == 1 ) {
|
else if ( sqlValueReferences.length == 1 ) {
|
||||||
return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, Template.TEMPLATE + "." + replacements[0] );
|
return processSqlValueReference( sqlValueReferences[0] );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final AST root = getASTFactory().create( OrderByTemplateTokenTypes.IDENT_LIST, "{ident list}" );
|
final AST root = getASTFactory().create( OrderByTemplateTokenTypes.IDENT_LIST, "{ident list}" );
|
||||||
for ( int i = 0; i < replacements.length; i++ ) {
|
for ( SqlValueReference sqlValueReference : sqlValueReferences ) {
|
||||||
final String identText = Template.TEMPLATE + '.' + replacements[i];
|
root.addChild( processSqlValueReference( sqlValueReference ) );
|
||||||
root.addChild( getASTFactory().create( OrderByTemplateTokenTypes.IDENT, identText ) );
|
|
||||||
}
|
}
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private AST processSqlValueReference(SqlValueReference sqlValueReference) {
|
||||||
* {@inheritDoc}
|
if ( ColumnReference.class.isInstance( sqlValueReference ) ) {
|
||||||
*/
|
final String columnName = ( (ColumnReference) sqlValueReference ).getColumnName();
|
||||||
|
return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, makeColumnReference( columnName ) );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final String formulaFragment = ( (FormulaReference) sqlValueReference ).getFormulaFragment();
|
||||||
|
// formulas have already been "adjusted" for aliases by appending Template.TEMPLATE to places
|
||||||
|
// where we believe column references are. Fixing that is beyond scope of this work. But we need
|
||||||
|
// to re-adjust that to use the order-by expectation of wrapping the column names in curly
|
||||||
|
// braces (i.e., `{column_name}`).
|
||||||
|
final String adjustedText = adjustTemplateReferences( formulaFragment );
|
||||||
|
return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, adjustedText );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String makeColumnReference(String text) {
|
||||||
|
columnReferences.add( text );
|
||||||
|
return "{" + text + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int TEMPLATE_MARKER_LENGTH = Template.TEMPLATE.length();
|
||||||
|
|
||||||
|
private String adjustTemplateReferences(String template) {
|
||||||
|
int templateLength = template.length();
|
||||||
|
int startPos = template.indexOf( Template.TEMPLATE );
|
||||||
|
while ( startPos < templateLength ) {
|
||||||
|
int dotPos = startPos + TEMPLATE_MARKER_LENGTH;
|
||||||
|
|
||||||
|
// from here we need to seek the end of the qualified identifier
|
||||||
|
int pos = dotPos + 1;
|
||||||
|
while ( pos < templateLength && isValidIdentifierCharacter( template.charAt( pos ) ) ) {
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point we know all 3 points in the template that are needed for replacement.
|
||||||
|
// Basically we will be replacing the whole match with the bit following the dot, but will wrap
|
||||||
|
// the replacement in curly braces.
|
||||||
|
final String columnReference = template.substring( dotPos + 1, pos );
|
||||||
|
final String replacement = "{" + columnReference + "}";
|
||||||
|
template = template.replace( template.substring( startPos, pos ), replacement );
|
||||||
|
columnReferences.add( columnReference );
|
||||||
|
|
||||||
|
// prep for the next seek
|
||||||
|
startPos = ( pos - TEMPLATE_MARKER_LENGTH ) + 1;
|
||||||
|
templateLength = template.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isValidIdentifierCharacter(char c) {
|
||||||
|
return Character.isLetter( c )
|
||||||
|
|| Character.isDigit( c )
|
||||||
|
|| '_' == c
|
||||||
|
|| '\"' == c;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AST postProcessSortSpecification(AST sortSpec) {
|
protected AST postProcessSortSpecification(AST sortSpec) {
|
||||||
assert SORT_SPEC == sortSpec.getType();
|
assert SORT_SPEC == sortSpec.getType();
|
||||||
|
@ -238,4 +301,34 @@ public class OrderByFragmentParser extends GeneratedOrderByFragmentParser {
|
||||||
}
|
}
|
||||||
return ( SortSpecification ) sortSpecification;
|
return ( SortSpecification ) sortSpecification;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// trace logging ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
private int traceDepth = 0;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void traceIn(String ruleName) {
|
||||||
|
if ( inputState.guessing > 0 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String prefix = StringHelper.repeat( '-', (traceDepth++ * 2) ) + "-> ";
|
||||||
|
LOG.trace(prefix + ruleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void traceOut(String ruleName) {
|
||||||
|
if ( inputState.guessing > 0 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String prefix = "<-" + StringHelper.repeat( '-', (--traceDepth * 2) ) + " ";
|
||||||
|
LOG.trace(prefix + ruleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void trace(String msg) {
|
||||||
|
LOG.trace( msg );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008 Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,24 +20,25 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.sql.ordering.antlr;
|
package org.hibernate.sql.ordering.antlr;
|
||||||
|
|
||||||
import antlr.collections.AST;
|
import antlr.collections.AST;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
import org.hibernate.hql.internal.ast.util.ASTPrinter;
|
import org.hibernate.hql.internal.ast.util.ASTPrinter;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO : javadoc
|
* Extension of the Antlr-generated tree walker for rendering the parsed order-by tree back to String form.
|
||||||
|
* {@link #out(antlr.collections.AST)} is the sole semantic action here and it is used to utilize our
|
||||||
|
* split between text (tree debugging text) and "renderable text" (text to use during rendering).
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class OrderByFragmentRenderer extends GeneratedOrderByFragmentRenderer {
|
public class OrderByFragmentRenderer extends GeneratedOrderByFragmentRenderer {
|
||||||
|
|
||||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, OrderByFragmentRenderer.class.getName() );
|
private static final Logger LOG = Logger.getLogger( OrderByFragmentRenderer.class.getName() );
|
||||||
private static final ASTPrinter printer = new ASTPrinter( GeneratedOrderByFragmentRendererTokenTypes.class );
|
private static final ASTPrinter printer = new ASTPrinter( GeneratedOrderByFragmentRendererTokenTypes.class );
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008 Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,41 +20,44 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.sql.ordering.antlr;
|
package org.hibernate.sql.ordering.antlr;
|
||||||
|
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.hql.internal.ast.util.ASTPrinter;
|
import org.hibernate.hql.internal.ast.util.ASTPrinter;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A translator which coordinates translation of an <tt>order-by</tt> mapping.
|
* A translator for order-by mappings, whether specified by hbm.xml files, Hibernate
|
||||||
|
* {@link org.hibernate.annotations.OrderBy} annotation or JPA {@link javax.persistence.OrderBy} annotation.
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class OrderByFragmentTranslator {
|
public class OrderByFragmentTranslator {
|
||||||
|
private static final Logger LOG = Logger.getLogger( OrderByFragmentTranslator.class.getName() );
|
||||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, OrderByFragmentTranslator.class.getName() );
|
|
||||||
|
|
||||||
public final TranslationContext context;
|
|
||||||
|
|
||||||
public OrderByFragmentTranslator(TranslationContext context) {
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The main contract, performing the transaction.
|
* Perform the translation of the user-supplied fragment, returning the translation.
|
||||||
|
* <p/>
|
||||||
|
* The important distinction to this split between (1) translating and (2) resolving aliases is that
|
||||||
|
* both happen at different times
|
||||||
*
|
*
|
||||||
* @param fragment The <tt>order-by</tt> mapping fragment to be translated.
|
|
||||||
*
|
*
|
||||||
* @return The translated fragment.
|
* @param context Context giving access to delegates needed during translation.
|
||||||
|
* @param fragment The user-supplied order-by fragment
|
||||||
|
*
|
||||||
|
* @return The translation.
|
||||||
*/
|
*/
|
||||||
public String render(String fragment) {
|
public static OrderByTranslation translate(TranslationContext context, String fragment) {
|
||||||
GeneratedOrderByLexer lexer = new GeneratedOrderByLexer( new StringReader( fragment ) );
|
GeneratedOrderByLexer lexer = new GeneratedOrderByLexer( new StringReader( fragment ) );
|
||||||
|
|
||||||
|
// Perform the parsing (and some analysis/resolution). Another important aspect is the collection
|
||||||
|
// of "column references" which are important later to seek out replacement points in the
|
||||||
|
// translated fragment.
|
||||||
OrderByFragmentParser parser = new OrderByFragmentParser( lexer, context );
|
OrderByFragmentParser parser = new OrderByFragmentParser( lexer, context );
|
||||||
try {
|
try {
|
||||||
parser.orderByFragment();
|
parser.orderByFragment();
|
||||||
|
@ -71,6 +74,7 @@ public class OrderByFragmentTranslator {
|
||||||
LOG.trace( printer.showAsString( parser.getAST(), "--- {order-by fragment} ---" ) );
|
LOG.trace( printer.showAsString( parser.getAST(), "--- {order-by fragment} ---" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Render the parsed tree to text.
|
||||||
OrderByFragmentRenderer renderer = new OrderByFragmentRenderer();
|
OrderByFragmentRenderer renderer = new OrderByFragmentRenderer();
|
||||||
try {
|
try {
|
||||||
renderer.orderByFragment( parser.getAST() );
|
renderer.orderByFragment( parser.getAST() );
|
||||||
|
@ -82,6 +86,29 @@ public class OrderByFragmentTranslator {
|
||||||
throw new HibernateException( "Unable to render parsed order-by fragment", t );
|
throw new HibernateException( "Unable to render parsed order-by fragment", t );
|
||||||
}
|
}
|
||||||
|
|
||||||
return renderer.getRenderedFragment();
|
return new StandardOrderByTranslationImpl( renderer.getRenderedFragment(), parser.getColumnReferences() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class StandardOrderByTranslationImpl implements OrderByTranslation {
|
||||||
|
private final String sqlTemplate;
|
||||||
|
private final Set<String> columnReferences;
|
||||||
|
|
||||||
|
public StandardOrderByTranslationImpl(String sqlTemplate, Set<String> columnReferences) {
|
||||||
|
this.sqlTemplate = sqlTemplate;
|
||||||
|
this.columnReferences = columnReferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String injectAliases(OrderByAliasResolver aliasResolver) {
|
||||||
|
String sql = sqlTemplate;
|
||||||
|
for ( String columnReference : columnReferences ) {
|
||||||
|
final String replacementToken = "{" + columnReference + "}";
|
||||||
|
sql = sql.replace(
|
||||||
|
replacementToken,
|
||||||
|
aliasResolver.resolveTableAlias( columnReference ) + '.' + columnReference
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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 the result of an order-by translation by {@link @OrderByTranslator}
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface OrderByTranslation {
|
||||||
|
/**
|
||||||
|
* Inject table aliases into the translated fragment to properly qualify column references, using
|
||||||
|
* the given 'aliasResolver' to determine the the proper table alias to use for each column reference.
|
||||||
|
*
|
||||||
|
* @param aliasResolver The strategy to resolver the proper table alias to use per column
|
||||||
|
*
|
||||||
|
* @return The fully translated and replaced fragment.
|
||||||
|
*/
|
||||||
|
public String injectAliases(OrderByAliasResolver aliasResolver);
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008 Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,11 +20,9 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.sql.ordering.antlr;
|
package org.hibernate.sql.ordering.antlr;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Models an ordering specification (<tt>ASCENDING</tt> or <tt>DESCENDING</tt>) within a {@link SortSpecification}.
|
* Models an ordering specification (<tt>ASCENDING</tt> or <tt>DESCENDING</tt>) within a {@link SortSpecification}.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008 Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,7 +20,6 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.sql.ordering.antlr;
|
package org.hibernate.sql.ordering.antlr;
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008 Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,13 +20,13 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.sql.ordering.antlr;
|
package org.hibernate.sql.ordering.antlr;
|
||||||
|
|
||||||
import antlr.collections.AST;
|
import antlr.collections.AST;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Models each sorting exprersion.
|
* Models each sorting expression.
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unifying interface between column and formula references mainly to give more strictly typed result
|
||||||
|
* to {@link ColumnMapper#map(String)}
|
||||||
|
*
|
||||||
|
* @see ColumnReference
|
||||||
|
* @see FormulaReference
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface SqlValueReference {
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
* Copyright (c) 2008 Red Hat Inc. or third-party contributors as
|
||||||
* indicated by the @author tags or express copyright attribution
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Middleware LLC.
|
* distributed under license by Red Hat Inc.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,9 +20,9 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.sql.ordering.antlr;
|
package org.hibernate.sql.ordering.antlr;
|
||||||
|
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.dialect.function.SQLFunctionRegistry;
|
import org.hibernate.dialect.function.SQLFunctionRegistry;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
|
|
@ -34,6 +34,9 @@ import org.hibernate.dialect.function.SQLFunctionRegistry;
|
||||||
import org.hibernate.persister.entity.PropertyMapping;
|
import org.hibernate.persister.entity.PropertyMapping;
|
||||||
import org.hibernate.sql.ordering.antlr.ColumnMapper;
|
import org.hibernate.sql.ordering.antlr.ColumnMapper;
|
||||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||||
|
|
||||||
|
import org.hibernate.sql.ordering.antlr.ColumnReference;
|
||||||
|
import org.hibernate.sql.ordering.antlr.SqlValueReference;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
@ -76,10 +79,22 @@ public class TemplateTest extends BaseUnitTestCase {
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final ColumnMapper MAPPER = new ColumnMapper() {
|
private static final ColumnMapper MAPPER = new ColumnMapper() {
|
||||||
public String[] map(String reference) {
|
public SqlValueReference[] map(String reference) {
|
||||||
return PROPERTY_MAPPING.toColumns( reference );
|
final String[] columnNames = PROPERTY_MAPPING.toColumns( reference );
|
||||||
|
final SqlValueReference[] result = new SqlValueReference[ columnNames.length ];
|
||||||
|
int i = 0;
|
||||||
|
for ( final String columnName : columnNames ) {
|
||||||
|
result[i] = new ColumnReference() {
|
||||||
|
@Override
|
||||||
|
public String getColumnName() {
|
||||||
|
return columnName;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final Dialect DIALECT = new HSQLDialect();
|
private static final Dialect DIALECT = new HSQLDialect();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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.test.annotations.collectionelement.ordered;
|
||||||
|
|
||||||
|
import javax.persistence.Embeddable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Embeddable
|
||||||
|
public class Address {
|
||||||
|
private String street;
|
||||||
|
private String city;
|
||||||
|
private String country;
|
||||||
|
|
||||||
|
public String getStreet() {
|
||||||
|
return street;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStreet(String street) {
|
||||||
|
this.street = street;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCity() {
|
||||||
|
return city;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCity(String city) {
|
||||||
|
this.city = city;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCountry() {
|
||||||
|
return country;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCountry(String country) {
|
||||||
|
this.country = country;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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.test.annotations.collectionelement.ordered;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class ElementCollectionSortingTest extends BaseCoreFunctionalTestCase {
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] { Person.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSortingElementCollectionSyntax() {
|
||||||
|
Session session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
|
||||||
|
session.createQuery( "from Person p join fetch p.nickNamesAscendingNaturalSort" ).list();
|
||||||
|
session.createQuery( "from Person p join fetch p.nickNamesDescendingNaturalSort" ).list();
|
||||||
|
|
||||||
|
session.createQuery( "from Person p join fetch p.addressesAscendingNaturalSort" ).list();
|
||||||
|
session.createQuery( "from Person p join fetch p.addressesDescendingNaturalSort" ).list();
|
||||||
|
session.createQuery( "from Person p join fetch p.addressesCityAscendingSort" ).list();
|
||||||
|
session.createQuery( "from Person p join fetch p.addressesCityDescendingSort" ).list();
|
||||||
|
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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.test.annotations.collectionelement.ordered;
|
||||||
|
|
||||||
|
import javax.persistence.ElementCollection;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.OrderBy;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.GenericGenerator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
public class Person {
|
||||||
|
private Long id;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private Set<String> nickNamesAscendingNaturalSort = new HashSet<String>();
|
||||||
|
private Set<String> nickNamesDescendingNaturalSort = new HashSet<String>();
|
||||||
|
|
||||||
|
private Set<Address> addressesAscendingNaturalSort = new HashSet<Address>();
|
||||||
|
private Set<Address> addressesDescendingNaturalSort = new HashSet<Address>();
|
||||||
|
private Set<Address> addressesCityAscendingSort = new HashSet<Address>();
|
||||||
|
private Set<Address> addressesCityDescendingSort = new HashSet<Address>();
|
||||||
|
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue( generator = "increment" )
|
||||||
|
@GenericGenerator( name = "increment", strategy = "increment" )
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ElementCollection
|
||||||
|
@JoinColumn
|
||||||
|
@OrderBy
|
||||||
|
public Set<String> getNickNamesAscendingNaturalSort() {
|
||||||
|
return nickNamesAscendingNaturalSort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNickNamesAscendingNaturalSort(Set<String> nickNamesAscendingNaturalSort) {
|
||||||
|
this.nickNamesAscendingNaturalSort = nickNamesAscendingNaturalSort;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ElementCollection
|
||||||
|
@JoinColumn
|
||||||
|
@OrderBy( "desc" )
|
||||||
|
public Set<String> getNickNamesDescendingNaturalSort() {
|
||||||
|
return nickNamesDescendingNaturalSort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNickNamesDescendingNaturalSort(Set<String> nickNamesDescendingNaturalSort) {
|
||||||
|
this.nickNamesDescendingNaturalSort = nickNamesDescendingNaturalSort;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ElementCollection
|
||||||
|
@JoinColumn
|
||||||
|
@OrderBy
|
||||||
|
public Set<Address> getAddressesAscendingNaturalSort() {
|
||||||
|
return addressesAscendingNaturalSort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddressesAscendingNaturalSort(Set<Address> addressesAscendingNaturalSort) {
|
||||||
|
this.addressesAscendingNaturalSort = addressesAscendingNaturalSort;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ElementCollection
|
||||||
|
@JoinColumn
|
||||||
|
@OrderBy( "desc" )
|
||||||
|
public Set<Address> getAddressesDescendingNaturalSort() {
|
||||||
|
return addressesDescendingNaturalSort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddressesDescendingNaturalSort(Set<Address> addressesDescendingNaturalSort) {
|
||||||
|
this.addressesDescendingNaturalSort = addressesDescendingNaturalSort;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ElementCollection
|
||||||
|
@JoinColumn
|
||||||
|
@OrderBy( "city" )
|
||||||
|
public Set<Address> getAddressesCityAscendingSort() {
|
||||||
|
return addressesCityAscendingSort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddressesCityAscendingSort(Set<Address> addressesCityAscendingSort) {
|
||||||
|
this.addressesCityAscendingSort = addressesCityAscendingSort;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ElementCollection
|
||||||
|
@JoinColumn
|
||||||
|
@OrderBy( "city desc" )
|
||||||
|
public Set<Address> getAddressesCityDescendingSort() {
|
||||||
|
return addressesCityDescendingSort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddressesCityDescendingSort(Set<Address> addressesCityDescendingSort) {
|
||||||
|
this.addressesCityDescendingSort = addressesCityDescendingSort;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ package org.hibernate.test.annotations.onetomany;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
import javax.persistence.GeneratedValue;
|
import javax.persistence.GeneratedValue;
|
||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
import javax.persistence.JoinColumn;
|
import javax.persistence.JoinColumn;
|
||||||
|
@ -50,7 +51,7 @@ class City {
|
||||||
this.streets = streets;
|
this.streets = streets;
|
||||||
}
|
}
|
||||||
|
|
||||||
@OneToMany()
|
@OneToMany
|
||||||
@JoinColumn(name = "mainstreetcity_id")
|
@JoinColumn(name = "mainstreetcity_id")
|
||||||
@ForeignKey(name = "CITYSTR_FK")
|
@ForeignKey(name = "CITYSTR_FK")
|
||||||
@OrderBy
|
@OrderBy
|
||||||
|
|
|
@ -32,6 +32,7 @@ import java.util.Set;
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.hibernate.Hibernate;
|
import org.hibernate.Hibernate;
|
||||||
|
@ -113,10 +114,17 @@ public class OneToManyTest extends BaseCoreFunctionalTestCase {
|
||||||
s.flush();
|
s.flush();
|
||||||
s.clear();
|
s.clear();
|
||||||
|
|
||||||
//testing @OrderBy with explicit values including Formula
|
// Assert the primary key value relationship amongst the 3 streets...
|
||||||
|
Assert.assertTrue( rochechoir.getId() < chmpsElysees.getId() );
|
||||||
|
Assert.assertTrue( chmpsElysees.getId() < grandeArmee.getId() );
|
||||||
|
|
||||||
paris = ( City ) s.get( City.class, paris.getId() );
|
paris = ( City ) s.get( City.class, paris.getId() );
|
||||||
|
|
||||||
|
// City.streets is defined to be ordered by name primarily...
|
||||||
assertEquals( 3, paris.getStreets().size() );
|
assertEquals( 3, paris.getStreets().size() );
|
||||||
assertEquals( chmpsElysees.getStreetName(), paris.getStreets().get( 0 ).getStreetName() );
|
assertEquals( chmpsElysees.getStreetName(), paris.getStreets().get( 0 ).getStreetName() );
|
||||||
|
assertEquals( grandeArmee.getStreetName(), paris.getStreets().get( 1 ).getStreetName() );
|
||||||
|
// City.mainStreets is defined to be ordered by street id
|
||||||
List<Street> mainStreets = paris.getMainStreets();
|
List<Street> mainStreets = paris.getMainStreets();
|
||||||
assertEquals( 2, mainStreets.size() );
|
assertEquals( 2, mainStreets.size() );
|
||||||
Integer previousId = -1;
|
Integer previousId = -1;
|
||||||
|
@ -445,7 +453,7 @@ public class OneToManyTest extends BaseCoreFunctionalTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@FailureExpected(jiraKey = "HHH-3577")
|
@TestForIssue( jiraKey = "HHH-4394" )
|
||||||
public void testOrderByOnSuperclassProperty() {
|
public void testOrderByOnSuperclassProperty() {
|
||||||
OrganisationUser user = new OrganisationUser();
|
OrganisationUser user = new OrganisationUser();
|
||||||
user.setFirstName( "Emmanuel" );
|
user.setFirstName( "Emmanuel" );
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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.test.collection.ordered.joinedInheritence;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Inheritance;
|
||||||
|
import javax.persistence.InheritanceType;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.GenericGenerator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Inheritance( strategy = InheritanceType.JOINED )
|
||||||
|
public class Animal {
|
||||||
|
private Long id;
|
||||||
|
private long weight;
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue( generator = "increment" )
|
||||||
|
@GenericGenerator( strategy = "increment", name = "increment" )
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getWeight() {
|
||||||
|
return weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWeight(long weight) {
|
||||||
|
this.weight = weight;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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.test.collection.ordered.joinedInheritence;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
public class Lion extends Animal {
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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.test.collection.ordered.joinedInheritence;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class OrderCollectionOfJoinedHierarchyTest extends BaseCoreFunctionalTestCase {
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] { Animal.class, Lion.class, Tiger.class, Zoo.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQuerySyntaxCheck() {
|
||||||
|
Session session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
session.get( Zoo.class, 1L );
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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.test.collection.ordered.joinedInheritence;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
public class Tiger extends Animal {
|
||||||
|
private int numberOfStripes;
|
||||||
|
|
||||||
|
public int getNumberOfStripes() {
|
||||||
|
return numberOfStripes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumberOfStripes(int numberOfStripes) {
|
||||||
|
this.numberOfStripes = numberOfStripes;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012, Red Hat Inc. 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 Inc.
|
||||||
|
*
|
||||||
|
* 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.test.collection.ordered.joinedInheritence;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.GenericGenerator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
public class Zoo {
|
||||||
|
private Long id;
|
||||||
|
private String name;
|
||||||
|
private String city;
|
||||||
|
private Set<Tiger> tigers = new HashSet<Tiger>();
|
||||||
|
private Set<Lion> lions = new HashSet<Lion>();
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue( generator = "increment" )
|
||||||
|
@GenericGenerator( strategy = "increment", name = "increment" )
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCity() {
|
||||||
|
return city;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCity(String city) {
|
||||||
|
this.city = city;
|
||||||
|
}
|
||||||
|
|
||||||
|
@OneToMany( fetch = FetchType.EAGER ) // eager so that load-by-id queries include this association
|
||||||
|
@JoinColumn
|
||||||
|
@javax.persistence.OrderBy( "weight" )
|
||||||
|
public Set<Tiger> getTigers() {
|
||||||
|
return tigers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTigers(Set<Tiger> tigers) {
|
||||||
|
this.tigers = tigers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@OneToMany( fetch = FetchType.EAGER ) // eager so that load-by-id queries include this association
|
||||||
|
@JoinColumn
|
||||||
|
@org.hibernate.annotations.OrderBy( clause = "weight" )
|
||||||
|
public Set<Lion> getLions() {
|
||||||
|
return lions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLions(Set<Lion> lions) {
|
||||||
|
this.lions = lions;
|
||||||
|
}
|
||||||
|
}
|
|
@ -192,6 +192,16 @@ public class ASTParserLoadingOrderByTest extends BaseCoreFunctionalTestCase {
|
||||||
s.close();
|
s.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOrderByOnJoinedSubclassPropertyWhoseColumnIsNotInDrivingTable() {
|
||||||
|
// this is simply a syntax check
|
||||||
|
Session s = openSession();
|
||||||
|
Transaction t = s.beginTransaction();
|
||||||
|
s.createQuery( "from Human h order by h.bodyWeight" ).list();
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOrderByNoSelectAliasRef() {
|
public void testOrderByNoSelectAliasRef() {
|
||||||
createData();
|
createData();
|
||||||
|
|
|
@ -12,4 +12,6 @@ log4j.logger.org.hibernate.testing.cache=debug
|
||||||
# SQL Logging - HHH-6833
|
# SQL Logging - HHH-6833
|
||||||
log4j.logger.org.hibernate.SQL=debug
|
log4j.logger.org.hibernate.SQL=debug
|
||||||
|
|
||||||
log4j.logger.org.hibernate.hql.internal.ast=debug
|
log4j.logger.org.hibernate.hql.internal.ast=debug
|
||||||
|
|
||||||
|
log4j.logger.org.hibernate.sql.ordering.antlr=trace
|
Loading…
Reference in New Issue