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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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"); }
|
||||
: 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.
|
||||
*/
|
||||
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>.
|
||||
*/
|
||||
orderingSpecification! { trace("orderingSpecification"); }
|
||||
|
|
|
@ -23,14 +23,6 @@
|
|||
*/
|
||||
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.AttributeOverrides;
|
||||
import javax.persistence.ElementCollection;
|
||||
|
@ -43,6 +35,11 @@ import javax.persistence.ManyToMany;
|
|||
import javax.persistence.MapKey;
|
||||
import javax.persistence.MapKeyColumn;
|
||||
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;
|
||||
|
||||
|
@ -110,9 +107,7 @@ import org.hibernate.mapping.KeyValue;
|
|||
import org.hibernate.mapping.ManyToOne;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Selectable;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.mapping.SingleTableSubclass;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.TypeDef;
|
||||
|
||||
|
@ -946,192 +941,39 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
}
|
||||
|
||||
private static String buildOrderByClauseFromHql(String hqlOrderBy, PersistentClass associatedClass, 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 ) {
|
||||
private static String buildOrderByClauseFromHql(String orderByFragment, PersistentClass associatedClass, String role) {
|
||||
if ( orderByFragment != null ) {
|
||||
if ( orderByFragment.length() == 0 ) {
|
||||
//order by id
|
||||
Iterator it = associatedClass.getIdentifier().getColumnIterator();
|
||||
while ( it.hasNext() ) {
|
||||
Selectable col = (Selectable) it.next();
|
||||
orderByBuffer.append( col.getText() ).append( " asc" ).append( ", " );
|
||||
}
|
||||
return "id asc";
|
||||
}
|
||||
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( 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 );
|
||||
}
|
||||
else if ( "desc".equals( orderByFragment ) ) {
|
||||
return "id desc";
|
||||
}
|
||||
}
|
||||
return orderByString;
|
||||
return orderByFragment;
|
||||
}
|
||||
|
||||
private static boolean isNonPropertyToken(String token) {
|
||||
if ( " ".equals( token ) ) return true;
|
||||
if ( ",".equals( token ) ) return true;
|
||||
if ( token.equalsIgnoreCase( "desc" ) ) return true;
|
||||
if ( token.equalsIgnoreCase( "asc" ) ) return true;
|
||||
return false;
|
||||
private static String adjustUserSuppliedValueCollectionOrderingFragment(String orderByFragment) {
|
||||
if ( orderByFragment != null ) {
|
||||
// NOTE: "$element$" is a specially recognized collection property recognized by the collection persister
|
||||
if ( orderByFragment.length() == 0 ) {
|
||||
//order by element
|
||||
return "$element$ asc";
|
||||
}
|
||||
else if ( "desc".equals( orderByFragment ) ) {
|
||||
return "$element$ desc";
|
||||
}
|
||||
}
|
||||
return orderByFragment;
|
||||
}
|
||||
|
||||
private static SimpleValue buildCollectionKey(
|
||||
Collection collValue, Ejb3JoinColumn[] joinColumns, boolean cascadeDeleteEnabled,
|
||||
XProperty property, Mappings mappings
|
||||
) {
|
||||
Collection collValue,
|
||||
Ejb3JoinColumn[] joinColumns,
|
||||
boolean cascadeDeleteEnabled,
|
||||
XProperty property,
|
||||
Mappings mappings) {
|
||||
//binding key reference using column
|
||||
KeyValue keyVal;
|
||||
//give a chance to override the referenced property name
|
||||
|
@ -1406,7 +1248,7 @@ public abstract class CollectionBinder {
|
|||
|
||||
if ( StringHelper.isNotEmpty( hqlOrderBy ) ) {
|
||||
String path = collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName();
|
||||
String orderBy = buildOrderByClauseFromHql( hqlOrderBy, component, path );
|
||||
String orderBy = adjustUserSuppliedValueCollectionOrderingFragment( hqlOrderBy );
|
||||
if ( orderBy != null ) {
|
||||
collValue.setOrderBy( orderBy );
|
||||
}
|
||||
|
@ -1437,6 +1279,10 @@ public abstract class CollectionBinder {
|
|||
elementBinder.setColumns( elementColumns );
|
||||
elementBinder.setType( property, elementClass );
|
||||
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)
|
||||
if (!persister.hasProxy()) return load(event, persister, keyToLoad, options);
|
||||
if (!persister.hasProxy()) {
|
||||
return load(event, persister, keyToLoad, options);
|
||||
}
|
||||
|
||||
final PersistenceContext persistenceContext = event.getSession().getPersistenceContext();
|
||||
|
||||
// look for a proxy
|
||||
Object proxy = persistenceContext.getProxy(keyToLoad);
|
||||
if (proxy != null) return returnNarrowedProxy(event, persister, keyToLoad, options, persistenceContext, proxy);
|
||||
if (options.isAllowProxyCreation()) return createProxyIfNecessary(event, persister, keyToLoad, options, persistenceContext);
|
||||
if (proxy != null) {
|
||||
return returnNarrowedProxy(event, persister, keyToLoad, options, persistenceContext, proxy);
|
||||
}
|
||||
|
||||
if (options.isAllowProxyCreation()) {
|
||||
return createProxyIfNecessary(event, persister, keyToLoad, options, persistenceContext);
|
||||
}
|
||||
|
||||
// return a newly loaded object
|
||||
return load(event, persister, keyToLoad, options);
|
||||
}
|
||||
|
|
|
@ -930,7 +930,7 @@ public class JoinWalker {
|
|||
if ( buf.length()>0 ) buf.setLength( buf.length()-2 );
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.UnstructuredCacheEntry;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.NotYetImplementedException;
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
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.metadata.CollectionMetadata;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.Loadable;
|
||||
import org.hibernate.persister.entity.PropertyMapping;
|
||||
import org.hibernate.persister.entity.Queryable;
|
||||
import org.hibernate.pretty.MessageHelper;
|
||||
import org.hibernate.sql.Alias;
|
||||
import org.hibernate.sql.SelectFragment;
|
||||
import org.hibernate.sql.SimpleSelect;
|
||||
import org.hibernate.sql.Template;
|
||||
import org.hibernate.sql.ordering.antlr.ColumnMapper;
|
||||
import org.hibernate.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.CompositeType;
|
||||
import org.hibernate.type.EntityType;
|
||||
|
@ -116,11 +125,16 @@ public abstract class AbstractCollectionPersister
|
|||
private final String sqlDetectRowByIndexString;
|
||||
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 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 String nodeName;
|
||||
|
@ -202,9 +216,6 @@ public abstract class AbstractCollectionPersister
|
|||
private final String manyToManyWhereString;
|
||||
private final String manyToManyWhereTemplate;
|
||||
|
||||
private final boolean hasManyToManyOrder;
|
||||
private final String manyToManyOrderByTemplate;
|
||||
|
||||
// custom sql
|
||||
private final boolean insertCallable;
|
||||
private final boolean updateCallable;
|
||||
|
@ -549,22 +560,16 @@ public abstract class AbstractCollectionPersister
|
|||
|
||||
hasOrder = collection.getOrderBy() != null;
|
||||
if ( hasOrder ) {
|
||||
ColumnMapper mapper = new ColumnMapper() {
|
||||
|
||||
public String[] map(String reference) {
|
||||
return elementPropertyMapping.toColumns( reference );
|
||||
}
|
||||
};
|
||||
sqlOrderByStringTemplate = Template.renderOrderByStringTemplate(
|
||||
orderByTranslation = Template.translateOrderBy(
|
||||
collection.getOrderBy(),
|
||||
mapper,
|
||||
new ColumnMapperImpl(),
|
||||
factory,
|
||||
dialect,
|
||||
factory.getSqlFunctionRegistry()
|
||||
);
|
||||
);
|
||||
}
|
||||
else {
|
||||
sqlOrderByStringTemplate = null;
|
||||
orderByTranslation = null;
|
||||
}
|
||||
|
||||
// Handle any filters applied to this collection
|
||||
|
@ -581,27 +586,76 @@ public abstract class AbstractCollectionPersister
|
|||
|
||||
hasManyToManyOrder = collection.getManyToManyOrdering() != null;
|
||||
if ( hasManyToManyOrder ) {
|
||||
ColumnMapper mapper = new ColumnMapper() {
|
||||
|
||||
public String[] map(String reference) {
|
||||
return elementPropertyMapping.toColumns( reference );
|
||||
}
|
||||
};
|
||||
manyToManyOrderByTemplate = Template.renderOrderByStringTemplate(
|
||||
manyToManyOrderByTranslation = Template.translateOrderBy(
|
||||
collection.getManyToManyOrdering(),
|
||||
mapper,
|
||||
new ColumnMapperImpl(),
|
||||
factory,
|
||||
dialect,
|
||||
factory.getSqlFunctionRegistry()
|
||||
);
|
||||
);
|
||||
}
|
||||
else {
|
||||
manyToManyOrderByTemplate = null;
|
||||
manyToManyOrderByTranslation = null;
|
||||
}
|
||||
|
||||
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 {
|
||||
initializer = queryLoaderName == null ?
|
||||
createCollectionInitializer( LoadQueryInfluencers.NONE ) :
|
||||
|
@ -693,13 +747,13 @@ public abstract class AbstractCollectionPersister
|
|||
|
||||
public String getSQLOrderByString(String alias) {
|
||||
return hasOrdering()
|
||||
? StringHelper.replace( sqlOrderByStringTemplate, Template.TEMPLATE, alias )
|
||||
? orderByTranslation.injectAliases( new StandardOrderByAliasResolver( alias ) )
|
||||
: "";
|
||||
}
|
||||
|
||||
public String getManyToManyOrderByString(String alias) {
|
||||
return hasManyToManyOrdering()
|
||||
? StringHelper.replace( manyToManyOrderByTemplate, Template.TEMPLATE, alias )
|
||||
? manyToManyOrderByTranslation.injectAliases( new StandardOrderByAliasResolver( alias ) )
|
||||
: "";
|
||||
}
|
||||
|
||||
|
@ -1856,4 +1910,23 @@ public abstract class AbstractCollectionPersister
|
|||
public CollectionInitializer getInitializer() {
|
||||
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];
|
||||
}
|
||||
|
||||
protected String[][] getSubclassPropertyFormulaTemplateClosure() {
|
||||
@Override
|
||||
public String[][] getSubclassPropertyFormulaTemplateClosure() {
|
||||
return subclassPropertyFormulaTemplateClosure;
|
||||
}
|
||||
|
||||
|
@ -4748,4 +4749,13 @@ public abstract class AbstractEntityPersister
|
|||
public EntityInstrumentationMetadata 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 );
|
||||
}
|
||||
|
||||
@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.
|
||||
*/
|
||||
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();
|
||||
|
||||
String[][] getSubclassPropertyFormulaTemplateClosure();
|
||||
|
||||
public static class Declarer {
|
||||
public static final Declarer CLASS = new Declarer( "class" );
|
||||
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.internal.util.StringHelper;
|
||||
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.OrderByTranslation;
|
||||
import org.hibernate.sql.ordering.antlr.SqlValueReference;
|
||||
import org.hibernate.sql.ordering.antlr.TranslationContext;
|
||||
|
||||
/**
|
||||
|
@ -624,8 +627,9 @@ public final class Template {
|
|||
|
||||
public static class NoOpColumnMapper implements ColumnMapper {
|
||||
public static final NoOpColumnMapper INSTANCE = new NoOpColumnMapper();
|
||||
public String[] map(String reference) {
|
||||
return new String[] { reference };
|
||||
public SqlValueReference[] map(String reference) {
|
||||
// return new String[] { reference };
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -639,7 +643,7 @@ public final class 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
|
||||
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
|
||||
* 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.
|
||||
*/
|
||||
public static String renderOrderByStringTemplate(
|
||||
public static OrderByTranslation translateOrderBy(
|
||||
String orderByFragment,
|
||||
final ColumnMapper columnMapper,
|
||||
final SessionFactoryImplementor sessionFactory,
|
||||
|
@ -692,8 +718,7 @@ public final class Template {
|
|||
}
|
||||
};
|
||||
|
||||
OrderByFragmentTranslator translator = new OrderByFragmentTranslator( context );
|
||||
return translator.render( orderByFragment );
|
||||
return OrderByFragmentTranslator.translate( context, orderByFragment );
|
||||
}
|
||||
|
||||
private static boolean isNamedParameter(String token) {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -20,11 +20,9 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.sql.ordering.antlr;
|
||||
|
||||
|
||||
/**
|
||||
* Models a collation specification (<tt>COLLATE</tt> using a specific character-set) within a
|
||||
* {@link SortSpecification}.
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -20,9 +20,9 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.sql.ordering.antlr;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
|
||||
/**
|
||||
|
@ -36,10 +36,11 @@ public interface ColumnMapper {
|
|||
*
|
||||
* @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
|
||||
* same as a null return.
|
||||
* @throws HibernateException Generally indicates that the property reference is unknown; interpretation
|
||||
* 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
|
||||
*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -20,9 +20,9 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.sql.ordering.antlr;
|
||||
|
||||
import antlr.ASTFactory;
|
||||
|
||||
/**
|
||||
|
@ -31,9 +31,7 @@ import antlr.ASTFactory;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class Factory extends ASTFactory implements OrderByTemplateTokenTypes {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Class getASTNodeType(int i) {
|
||||
switch ( i ) {
|
||||
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
|
||||
*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -20,11 +20,9 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.sql.ordering.antlr;
|
||||
|
||||
|
||||
/**
|
||||
* General contract for AST nodes.
|
||||
*
|
||||
|
@ -48,7 +46,7 @@ public interface Node {
|
|||
/**
|
||||
* 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();
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -20,27 +20,23 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.sql.ordering.antlr;
|
||||
|
||||
import antlr.CommonAST;
|
||||
|
||||
/**
|
||||
* Basic implementation of a {@link Node}.
|
||||
* Basic implementation of a {@link Node} briding to the Antlr {@link CommonAST} hierarchy.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class NodeSupport extends CommonAST implements Node {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String getDebugText() {
|
||||
return getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String getRenderableText() {
|
||||
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
|
||||
*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -20,11 +20,9 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.sql.ordering.antlr;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a parsed <tt>order-by</tt> mapping fragment. This holds the tree of all {@link SortSpecification}s.
|
||||
*
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -20,116 +20,99 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.sql.ordering.antlr;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import antlr.CommonAST;
|
||||
import antlr.TokenStream;
|
||||
import antlr.collections.AST;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.dialect.function.SQLFunction;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
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
|
||||
*/
|
||||
public class OrderByFragmentParser extends GeneratedOrderByFragmentParser {
|
||||
|
||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, OrderByFragmentParser.class.getName());
|
||||
private static final Logger LOG = Logger.getLogger(OrderByFragmentParser.class.getName());
|
||||
|
||||
private final TranslationContext context;
|
||||
|
||||
private Set<String> columnReferences = new HashSet<String>();
|
||||
|
||||
public OrderByFragmentParser(TokenStream lexer, TranslationContext context) {
|
||||
super( lexer );
|
||||
super.setASTFactory( new Factory() );
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
|
||||
// handle 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);
|
||||
public Set<String> getColumnReferences() {
|
||||
return columnReferences;
|
||||
}
|
||||
|
||||
@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) {
|
||||
return getASTFactory().create(
|
||||
OrderByTemplateTokenTypes.IDENT,
|
||||
Template.TEMPLATE + "." + context.getDialect().quote( '`' + ident.getText() + '`' )
|
||||
);
|
||||
/*
|
||||
* Semantic action used during recognition of quoted identifiers (quoted column names)
|
||||
*/
|
||||
final String columnName = context.getDialect().quote( '`' + ident.getText() + '`' );
|
||||
columnReferences.add( columnName );
|
||||
final String marker = '{' + columnName + '}';
|
||||
return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, marker );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
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() ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@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();
|
||||
// assume it is a function if it has parameters
|
||||
if ( child != null && "{param list}".equals( child.getText() ) ) {
|
||||
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() );
|
||||
if ( function == null ) {
|
||||
// no registered function, so we cannot know for certain
|
||||
return false;
|
||||
}
|
||||
|
||||
// if function.hasParenthesesIfNoArguments() is true, then assume
|
||||
// ast.getText() is not a function.
|
||||
return ! function.hasParenthesesIfNoArguments();
|
||||
else {
|
||||
// if function.hasParenthesesIfNoArguments() is true, then assume the node is not a function
|
||||
return ! function.hasParenthesesIfNoArguments();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected AST resolveFunction(AST ast) {
|
||||
/*
|
||||
* Semantic action used during recognition of a *known* function
|
||||
*/
|
||||
AST child = ast.getFirstChild();
|
||||
if ( child != null ) {
|
||||
assert "{param list}".equals( child.getText() );
|
||||
|
@ -143,7 +126,7 @@ public class OrderByFragmentParser extends GeneratedOrderByFragmentParser {
|
|||
if ( child != null ) {
|
||||
text += '(';
|
||||
while ( child != null ) {
|
||||
text += child.getText();
|
||||
text += resolveFunctionArgument( child );
|
||||
child = child.getNextSibling();
|
||||
if ( child != null ) {
|
||||
text += ", ";
|
||||
|
@ -156,7 +139,7 @@ public class OrderByFragmentParser extends GeneratedOrderByFragmentParser {
|
|||
else {
|
||||
ArrayList expressions = new ArrayList();
|
||||
while ( child != null ) {
|
||||
expressions.add( child.getText() );
|
||||
expressions.add( resolveFunctionArgument( child ) );
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
final String text = function.render( null, expressions, context.getSessionFactory() );
|
||||
|
@ -164,39 +147,119 @@ public class OrderByFragmentParser extends GeneratedOrderByFragmentParser {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
private String resolveFunctionArgument(AST argumentNode) {
|
||||
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
|
||||
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[] replacements;
|
||||
SqlValueReference[] sqlValueReferences;
|
||||
try {
|
||||
replacements = context.getColumnMapper().map( text );
|
||||
sqlValueReferences = context.getColumnMapper().map( text );
|
||||
}
|
||||
catch( Throwable t ) {
|
||||
replacements = null;
|
||||
sqlValueReferences = null;
|
||||
}
|
||||
|
||||
if ( replacements == null || replacements.length == 0 ) {
|
||||
return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, Template.TEMPLATE + "." + text );
|
||||
if ( sqlValueReferences == null || sqlValueReferences.length == 0 ) {
|
||||
return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, makeColumnReference( text ) );
|
||||
}
|
||||
else if ( replacements.length == 1 ) {
|
||||
return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, Template.TEMPLATE + "." + replacements[0] );
|
||||
else if ( sqlValueReferences.length == 1 ) {
|
||||
return processSqlValueReference( sqlValueReferences[0] );
|
||||
}
|
||||
else {
|
||||
final AST root = getASTFactory().create( OrderByTemplateTokenTypes.IDENT_LIST, "{ident list}" );
|
||||
for ( int i = 0; i < replacements.length; i++ ) {
|
||||
final String identText = Template.TEMPLATE + '.' + replacements[i];
|
||||
root.addChild( getASTFactory().create( OrderByTemplateTokenTypes.IDENT, identText ) );
|
||||
for ( SqlValueReference sqlValueReference : sqlValueReferences ) {
|
||||
root.addChild( processSqlValueReference( sqlValueReference ) );
|
||||
}
|
||||
return root;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
private AST processSqlValueReference(SqlValueReference sqlValueReference) {
|
||||
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
|
||||
protected AST postProcessSortSpecification(AST sortSpec) {
|
||||
assert SORT_SPEC == sortSpec.getType();
|
||||
|
@ -238,4 +301,34 @@ public class OrderByFragmentParser extends GeneratedOrderByFragmentParser {
|
|||
}
|
||||
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
|
||||
*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -20,24 +20,25 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.sql.ordering.antlr;
|
||||
|
||||
import antlr.collections.AST;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.hql.internal.ast.util.ASTPrinter;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
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
|
||||
*/
|
||||
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 );
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -20,41 +20,44 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.sql.ordering.antlr;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
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
|
||||
*/
|
||||
public class OrderByFragmentTranslator {
|
||||
|
||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, OrderByFragmentTranslator.class.getName() );
|
||||
|
||||
public final TranslationContext context;
|
||||
|
||||
public OrderByFragmentTranslator(TranslationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
private static final Logger LOG = Logger.getLogger( OrderByFragmentTranslator.class.getName() );
|
||||
|
||||
/**
|
||||
* 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 ) );
|
||||
|
||||
// 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 );
|
||||
try {
|
||||
parser.orderByFragment();
|
||||
|
@ -71,6 +74,7 @@ public class OrderByFragmentTranslator {
|
|||
LOG.trace( printer.showAsString( parser.getAST(), "--- {order-by fragment} ---" ) );
|
||||
}
|
||||
|
||||
// Render the parsed tree to text.
|
||||
OrderByFragmentRenderer renderer = new OrderByFragmentRenderer();
|
||||
try {
|
||||
renderer.orderByFragment( parser.getAST() );
|
||||
|
@ -82,6 +86,29 @@ public class OrderByFragmentTranslator {
|
|||
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
|
||||
*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -20,11 +20,9 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.sql.ordering.antlr;
|
||||
|
||||
|
||||
/**
|
||||
* Models an ordering specification (<tt>ASCENDING</tt> or <tt>DESCENDING</tt>) within a {@link SortSpecification}.
|
||||
*
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -20,7 +20,6 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.sql.ordering.antlr;
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -20,13 +20,13 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.sql.ordering.antlr;
|
||||
|
||||
import antlr.collections.AST;
|
||||
|
||||
/**
|
||||
* Models each sorting exprersion.
|
||||
* Models each sorting expression.
|
||||
*
|
||||
* @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
|
||||
*
|
||||
* 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
|
||||
* 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,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -20,9 +20,9 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.sql.ordering.antlr;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.function.SQLFunctionRegistry;
|
||||
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.sql.ordering.antlr.ColumnMapper;
|
||||
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 static org.junit.Assert.assertEquals;
|
||||
|
@ -76,10 +79,22 @@ public class TemplateTest extends BaseUnitTestCase {
|
|||
};
|
||||
|
||||
private static final ColumnMapper MAPPER = new ColumnMapper() {
|
||||
public String[] map(String reference) {
|
||||
return PROPERTY_MAPPING.toColumns( reference );
|
||||
public SqlValueReference[] map(String 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();
|
||||
|
||||
|
|
|
@ -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.List;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
|
@ -50,7 +51,7 @@ class City {
|
|||
this.streets = streets;
|
||||
}
|
||||
|
||||
@OneToMany()
|
||||
@OneToMany
|
||||
@JoinColumn(name = "mainstreetcity_id")
|
||||
@ForeignKey(name = "CITYSTR_FK")
|
||||
@OrderBy
|
||||
|
|
|
@ -32,6 +32,7 @@ import java.util.Set;
|
|||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
|
@ -113,10 +114,17 @@ public class OneToManyTest extends BaseCoreFunctionalTestCase {
|
|||
s.flush();
|
||||
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() );
|
||||
|
||||
// City.streets is defined to be ordered by name primarily...
|
||||
assertEquals( 3, paris.getStreets().size() );
|
||||
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();
|
||||
assertEquals( 2, mainStreets.size() );
|
||||
Integer previousId = -1;
|
||||
|
@ -445,7 +453,7 @@ public class OneToManyTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected(jiraKey = "HHH-3577")
|
||||
@TestForIssue( jiraKey = "HHH-4394" )
|
||||
public void testOrderByOnSuperclassProperty() {
|
||||
OrganisationUser user = new OrganisationUser();
|
||||
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();
|
||||
}
|
||||
|
||||
@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
|
||||
public void testOrderByNoSelectAliasRef() {
|
||||
createData();
|
||||
|
|
|
@ -12,4 +12,6 @@ log4j.logger.org.hibernate.testing.cache=debug
|
|||
# SQL Logging - HHH-6833
|
||||
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