HHH-530 : filters + subqueries;

HHH-3506 : filters + HQL update/delete

git-svn-id: https://svn.jboss.org/repos/hibernate/core/branches/Branch_3_2@15240 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Steve Ebersole 2008-10-01 19:32:11 +00:00
parent 9c37f6ad83
commit 43056f021c
30 changed files with 1577 additions and 269 deletions

View File

@ -1,14 +1,13 @@
//$Id$ //$Id$
package org.hibernate.criterion; package org.hibernate.criterion;
import java.util.HashMap;
import org.hibernate.Criteria; import org.hibernate.Criteria;
import org.hibernate.EntityMode; import org.hibernate.EntityMode;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.engine.QueryParameters; import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.TypedValue; import org.hibernate.engine.TypedValue;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.impl.CriteriaImpl; import org.hibernate.impl.CriteriaImpl;
import org.hibernate.loader.criteria.CriteriaJoinWalker; import org.hibernate.loader.criteria.CriteriaJoinWalker;
import org.hibernate.loader.criteria.CriteriaQueryTranslator; import org.hibernate.loader.criteria.CriteriaQueryTranslator;
@ -19,7 +18,7 @@ import org.hibernate.type.Type;
* @author Gavin King * @author Gavin King
*/ */
public abstract class SubqueryExpression implements Criterion { public abstract class SubqueryExpression implements Criterion {
private CriteriaImpl criteriaImpl; private CriteriaImpl criteriaImpl;
private String quantifier; private String quantifier;
private String op; private String op;
@ -30,49 +29,67 @@ public abstract class SubqueryExpression implements Criterion {
protected Type[] getTypes() { protected Type[] getTypes() {
return types; return types;
} }
protected SubqueryExpression(String op, String quantifier, DetachedCriteria dc) { protected SubqueryExpression(String op, String quantifier, DetachedCriteria dc) {
this.criteriaImpl = dc.getCriteriaImpl(); this.criteriaImpl = dc.getCriteriaImpl();
this.quantifier = quantifier; this.quantifier = quantifier;
this.op = op; this.op = op;
} }
protected abstract String toLeftSqlString(Criteria criteria, CriteriaQuery outerQuery); protected abstract String toLeftSqlString(Criteria criteria, CriteriaQuery outerQuery);
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
throws HibernateException {
final SessionFactoryImplementor factory = criteriaQuery.getFactory(); final SessionFactoryImplementor factory = criteriaQuery.getFactory();
final OuterJoinLoadable persister = (OuterJoinLoadable) factory.getEntityPersister( criteriaImpl.getEntityOrClassName() ); final OuterJoinLoadable persister =
( OuterJoinLoadable ) factory.getEntityPersister( criteriaImpl.getEntityOrClassName() );
createAndSetInnerQuery( criteriaQuery, factory ); createAndSetInnerQuery( criteriaQuery, factory );
criteriaImpl.setSession( deriveRootSession( criteria ) );
CriteriaJoinWalker walker = new CriteriaJoinWalker( CriteriaJoinWalker walker = new CriteriaJoinWalker(
persister, persister,
innerQuery, innerQuery,
factory, factory,
criteriaImpl, criteriaImpl,
criteriaImpl.getEntityOrClassName(), criteriaImpl.getEntityOrClassName(),
new HashMap(), criteriaImpl.getSession().getEnabledFilters(),
innerQuery.getRootSQLALias()); innerQuery.getRootSQLALias()
);
String sql = walker.getSQLString(); String sql = walker.getSQLString();
final StringBuffer buf = new StringBuffer() final StringBuffer buf = new StringBuffer( toLeftSqlString(criteria, criteriaQuery) );
.append( toLeftSqlString(criteria, criteriaQuery) ); if ( op != null ) {
if (op!=null) buf.append(' ').append(op).append(' '); buf.append( ' ' ).append( op ).append( ' ' );
if (quantifier!=null) buf.append(quantifier).append(' '); }
return buf.append('(').append(sql).append(')') if ( quantifier != null ) {
.toString(); buf.append( quantifier ).append( ' ' );
}
return buf.append( '(' ).append( sql ).append( ')' )
.toString();
} }
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) private SessionImplementor deriveRootSession(Criteria criteria) {
if ( criteria instanceof CriteriaImpl ) {
return ( ( CriteriaImpl ) criteria ).getSession();
}
else if ( criteria instanceof CriteriaImpl.Subcriteria ) {
return deriveRootSession( ( ( CriteriaImpl.Subcriteria ) criteria ).getParent() );
}
else {
// could happen for custom Criteria impls. Not likely, but...
// for long term solution, see HHH-3514
return null;
}
}
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException { throws HibernateException {
//the following two lines were added to ensure that this.params is not null, which //the following two lines were added to ensure that this.params is not null, which
//can happen with two-deep nested subqueries //can happen with two-deep nested subqueries
SessionFactoryImplementor factory = criteriaQuery.getFactory(); SessionFactoryImplementor factory = criteriaQuery.getFactory();
createAndSetInnerQuery(criteriaQuery, factory); createAndSetInnerQuery(criteriaQuery, factory);
Type[] ppTypes = params.getPositionalParameterTypes(); Type[] ppTypes = params.getPositionalParameterTypes();
Object[] ppValues = params.getPositionalParameterValues(); Object[] ppValues = params.getPositionalParameterValues();
TypedValue[] tv = new TypedValue[ppTypes.length]; TypedValue[] tv = new TypedValue[ppTypes.length];
@ -83,12 +100,12 @@ public abstract class SubqueryExpression implements Criterion {
} }
/** /**
* Creates the inner query used to extract some useful information about * Creates the inner query used to extract some useful information about types, since it is needed in both methods.
* types, since it is needed in both methods. *
* @param criteriaQuery * @param criteriaQuery The criteria query
* @param factory * @param factory The session factory.
*/ */
private void createAndSetInnerQuery(CriteriaQuery criteriaQuery, final SessionFactoryImplementor factory) { private void createAndSetInnerQuery(CriteriaQuery criteriaQuery, SessionFactoryImplementor factory) {
if ( innerQuery == null ) { if ( innerQuery == null ) {
//with two-deep subqueries, the same alias would get generated for //with two-deep subqueries, the same alias would get generated for
//both using the old method (criteriaQuery.generateSQLAlias()), so //both using the old method (criteriaQuery.generateSQLAlias()), so

View File

@ -3,7 +3,6 @@ package org.hibernate.engine;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -16,6 +15,7 @@ import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.QueryException; import org.hibernate.QueryException;
import org.hibernate.ScrollMode; import org.hibernate.ScrollMode;
import org.hibernate.impl.FilterImpl;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.hql.classic.ParserHelper; import org.hibernate.hql.classic.ParserHelper;
import org.hibernate.pretty.Printer; import org.hibernate.pretty.Printer;
@ -46,29 +46,28 @@ public final class QueryParameters {
private boolean callable = false; private boolean callable = false;
private boolean autodiscovertypes = false; private boolean autodiscovertypes = false;
private boolean isNaturalKeyLookup; private boolean isNaturalKeyLookup;
private final ResultTransformer resultTransformer; // why is all others non final ? private final ResultTransformer resultTransformer; // why is all others non final ?
private String processedSQL; private String processedSQL;
private Type[] processedPositionalParameterTypes; private Type[] processedPositionalParameterTypes;
private Object[] processedPositionalParameterValues; private Object[] processedPositionalParameterValues;
public QueryParameters() { public QueryParameters() {
this( ArrayHelper.EMPTY_TYPE_ARRAY, ArrayHelper.EMPTY_OBJECT_ARRAY ); this( ArrayHelper.EMPTY_TYPE_ARRAY, ArrayHelper.EMPTY_OBJECT_ARRAY );
} }
public QueryParameters(Type type, Object value) { public QueryParameters(Type type, Object value) {
this( new Type[] {type}, new Object[] {value} ); this( new Type[] { type }, new Object[] { value } );
} }
public QueryParameters( public QueryParameters(
final Type[] positionalParameterTypes, final Type[] positionalParameterTypes,
final Object[] postionalParameterValues, final Object[] postionalParameterValues,
final Object optionalObject, final Object optionalObject,
final String optionalEntityName, final String optionalEntityName,
final Serializable optionalObjectId final Serializable optionalObjectId) {
) { this( positionalParameterTypes, postionalParameterValues );
this(positionalParameterTypes, postionalParameterValues);
this.optionalObject = optionalObject; this.optionalObject = optionalObject;
this.optionalId = optionalObjectId; this.optionalId = optionalObjectId;
this.optionalEntityName = optionalEntityName; this.optionalEntityName = optionalEntityName;
@ -76,42 +75,24 @@ public final class QueryParameters {
} }
public QueryParameters( public QueryParameters(
final Type[] positionalParameterTypes, final Type[] positionalParameterTypes,
final Object[] postionalParameterValues final Object[] postionalParameterValues) {
) { this( positionalParameterTypes, postionalParameterValues, null, null, false, null, null, false, null );
this(
positionalParameterTypes,
postionalParameterValues,
null,
null,
false,
null,
null,
false,
null
);
} }
public QueryParameters( public QueryParameters(
final Type[] positionalParameterTypes, final Type[] positionalParameterTypes,
final Object[] postionalParameterValues, final Object[] postionalParameterValues,
final Serializable[] collectionKeys final Serializable[] collectionKeys) {
) { this( positionalParameterTypes, postionalParameterValues, null, collectionKeys );
this(
positionalParameterTypes,
postionalParameterValues,
null,
collectionKeys
);
} }
public QueryParameters( public QueryParameters(
final Type[] positionalParameterTypes, final Type[] positionalParameterTypes,
final Object[] postionalParameterValues, final Object[] postionalParameterValues,
final Map namedParameters, final Map namedParameters,
final Serializable[] collectionKeys final Serializable[] collectionKeys) {
) { this(
this(
positionalParameterTypes, positionalParameterTypes,
postionalParameterValues, postionalParameterValues,
namedParameters, namedParameters,
@ -119,37 +100,36 @@ public final class QueryParameters {
null, null,
false, false,
false, false,
null, null,
null, null,
collectionKeys, collectionKeys,
null null
); );
} }
public QueryParameters( public QueryParameters(
final Type[] positionalParameterTypes, final Type[] positionalParameterTypes,
final Object[] positionalParameterValues, final Object[] positionalParameterValues,
final Map lockModes, final Map lockModes,
final RowSelection rowSelection, final RowSelection rowSelection,
final boolean cacheable, final boolean cacheable,
final String cacheRegion, final String cacheRegion,
//final boolean forceCacheRefresh, //final boolean forceCacheRefresh,
final String comment, final String comment,
final boolean isLookupByNaturalKey, final boolean isLookupByNaturalKey,
final ResultTransformer transformer final ResultTransformer transformer) {
) {
this( this(
positionalParameterTypes, positionalParameterTypes,
positionalParameterValues, positionalParameterValues,
null, null,
lockModes, lockModes,
rowSelection, rowSelection,
false, false,
cacheable, cacheable,
cacheRegion, cacheRegion,
comment, comment,
null, null,
transformer transformer
); );
isNaturalKeyLookup = isLookupByNaturalKey; isNaturalKeyLookup = isLookupByNaturalKey;
} }
@ -166,8 +146,7 @@ public final class QueryParameters {
//final boolean forceCacheRefresh, //final boolean forceCacheRefresh,
final String comment, final String comment,
final Serializable[] collectionKeys, final Serializable[] collectionKeys,
ResultTransformer transformer ResultTransformer transformer) {
) {
this.positionalParameterTypes = positionalParameterTypes; this.positionalParameterTypes = positionalParameterTypes;
this.positionalParameterValues = positionalParameterValues; this.positionalParameterValues = positionalParameterValues;
this.namedParameters = namedParameters; this.namedParameters = namedParameters;
@ -181,36 +160,35 @@ public final class QueryParameters {
this.readOnly = readOnly; this.readOnly = readOnly;
this.resultTransformer = transformer; this.resultTransformer = transformer;
} }
public QueryParameters( public QueryParameters(
final Type[] positionalParameterTypes, final Type[] positionalParameterTypes,
final Object[] positionalParameterValues, final Object[] positionalParameterValues,
final Map namedParameters, final Map namedParameters,
final Map lockModes, final Map lockModes,
final RowSelection rowSelection, final RowSelection rowSelection,
final boolean readOnly, final boolean readOnly,
final boolean cacheable, final boolean cacheable,
final String cacheRegion, final String cacheRegion,
//final boolean forceCacheRefresh, //final boolean forceCacheRefresh,
final String comment, final String comment,
final Serializable[] collectionKeys, final Serializable[] collectionKeys,
final Object optionalObject, final Object optionalObject,
final String optionalEntityName, final String optionalEntityName,
final Serializable optionalId, final Serializable optionalId,
final ResultTransformer transformer final ResultTransformer transformer) {
) {
this( this(
positionalParameterTypes, positionalParameterTypes,
positionalParameterValues, positionalParameterValues,
namedParameters, namedParameters,
lockModes, lockModes,
rowSelection, rowSelection,
readOnly, readOnly,
cacheable, cacheable,
cacheRegion, cacheRegion,
comment, comment,
collectionKeys, collectionKeys,
transformer transformer
); );
this.optionalEntityName = optionalEntityName; this.optionalEntityName = optionalEntityName;
this.optionalId = optionalId; this.optionalId = optionalId;
@ -218,7 +196,7 @@ public final class QueryParameters {
} }
public boolean hasRowSelection() { public boolean hasRowSelection() {
return rowSelection!=null; return rowSelection != null;
} }
public Map getNamedParameters() { public Map getNamedParameters() {
@ -236,7 +214,7 @@ public final class QueryParameters {
public RowSelection getRowSelection() { public RowSelection getRowSelection() {
return rowSelection; return rowSelection;
} }
public ResultTransformer getResultTransformer() { public ResultTransformer getResultTransformer() {
return resultTransformer; return resultTransformer;
} }
@ -266,15 +244,15 @@ public final class QueryParameters {
} }
public void traceParameters(SessionFactoryImplementor factory) throws HibernateException { public void traceParameters(SessionFactoryImplementor factory) throws HibernateException {
Printer print = new Printer(factory); Printer print = new Printer( factory );
if (positionalParameterValues.length!=0) { if ( positionalParameterValues.length != 0 ) {
log.trace( log.trace(
"parameters: " + "parameters: " +
print.toString(positionalParameterTypes, positionalParameterValues) print.toString( positionalParameterTypes, positionalParameterValues )
); );
} }
if (namedParameters!=null) { if ( namedParameters != null ) {
log.trace( "named parameters: " + print.toString(namedParameters) ); log.trace( "named parameters: " + print.toString( namedParameters ) );
} }
} }
@ -295,13 +273,13 @@ public final class QueryParameters {
} }
public void validateParameters() throws QueryException { public void validateParameters() throws QueryException {
int types = positionalParameterTypes==null ? 0 : positionalParameterTypes.length; int types = positionalParameterTypes == null ? 0 : positionalParameterTypes.length;
int values = positionalParameterValues==null ? 0 : positionalParameterValues.length; int values = positionalParameterValues == null ? 0 : positionalParameterValues.length;
if (types!=values) { if ( types != values ) {
throw new QueryException( throw new QueryException(
"Number of positional parameter types:" + types + "Number of positional parameter types:" + types +
" does not match number of positional parameters: " + values " does not match number of positional parameters: " + values
); );
} }
} }
@ -362,44 +340,49 @@ public final class QueryParameters {
} }
public void setCallable(boolean callable) { public void setCallable(boolean callable) {
this.callable = callable; this.callable = callable;
} }
public boolean isCallable() { public boolean isCallable() {
return callable; return callable;
} }
public boolean hasAutoDiscoverScalarTypes() { public boolean hasAutoDiscoverScalarTypes() {
return autodiscovertypes; return autodiscovertypes;
} }
public void processFilters(String sql, SessionImplementor session) { public void processFilters(String sql, SessionImplementor session) {
processFilters( sql, session.getEnabledFilters(), session.getFactory() );
if ( session.getEnabledFilters().size()==0 || sql.indexOf(ParserHelper.HQL_VARIABLE_PREFIX)<0 ) { }
public void processFilters(String sql, Map filters, SessionFactoryImplementor factory) {
if ( filters.size() == 0 || sql.indexOf( ParserHelper.HQL_VARIABLE_PREFIX ) < 0 ) {
// HELLA IMPORTANT OPTIMIZATION!!! // HELLA IMPORTANT OPTIMIZATION!!!
processedPositionalParameterValues = getPositionalParameterValues(); processedPositionalParameterValues = getPositionalParameterValues();
processedPositionalParameterTypes = getPositionalParameterTypes(); processedPositionalParameterTypes = getPositionalParameterTypes();
processedSQL = sql; processedSQL = sql;
} }
else { else {
final Dialect dialect = factory.getDialect();
Dialect dialect = session.getFactory().getDialect();
String symbols = new StringBuffer().append( ParserHelper.HQL_SEPARATORS ) String symbols = new StringBuffer().append( ParserHelper.HQL_SEPARATORS )
.append( dialect.openQuote() ) .append( dialect.openQuote() )
.append( dialect.closeQuote() ) .append( dialect.closeQuote() )
.toString(); .toString();
StringTokenizer tokens = new StringTokenizer( sql, symbols, true ); StringTokenizer tokens = new StringTokenizer( sql, symbols, true );
StringBuffer result = new StringBuffer(); StringBuffer result = new StringBuffer();
List parameters = new ArrayList(); List parameters = new ArrayList();
List parameterTypes = new ArrayList(); List parameterTypes = new ArrayList();
int positionalIndex = 0;
while ( tokens.hasMoreTokens() ) { while ( tokens.hasMoreTokens() ) {
final String token = tokens.nextToken(); final String token = tokens.nextToken();
if ( token.startsWith( ParserHelper.HQL_VARIABLE_PREFIX ) ) { if ( token.startsWith( ParserHelper.HQL_VARIABLE_PREFIX ) ) {
String filterParameterName = token.substring( 1 ); final String filterParameterName = token.substring( 1 );
Object value = session.getFilterParameterValue( filterParameterName ); final String[] parts = parseFilterParameterName( filterParameterName );
Type type = session.getFilterParameterType( filterParameterName ); final FilterImpl filter = ( FilterImpl ) filters.get( parts[0] );
final Object value = filter.getParameter( parts[1] );
final Type type = filter.getFilterDefinition().getParameterType( parts[1] );
if ( value != null && Collection.class.isAssignableFrom( value.getClass() ) ) { if ( value != null && Collection.class.isAssignableFrom( value.getClass() ) ) {
Iterator itr = ( ( Collection ) value ).iterator(); Iterator itr = ( ( Collection ) value ).iterator();
while ( itr.hasNext() ) { while ( itr.hasNext() ) {
@ -419,15 +402,17 @@ public final class QueryParameters {
} }
} }
else { else {
if ( "?".equals( token ) && positionalIndex < getPositionalParameterValues().length ) {
parameters.add( getPositionalParameterValues()[positionalIndex] );
parameterTypes.add( getPositionalParameterTypes()[positionalIndex] );
positionalIndex++;
}
result.append( token ); result.append( token );
} }
} }
parameters.addAll( Arrays.asList( getPositionalParameterValues() ) );
parameterTypes.addAll( Arrays.asList( getPositionalParameterTypes() ) );
processedPositionalParameterValues = parameters.toArray(); processedPositionalParameterValues = parameters.toArray();
processedPositionalParameterTypes = ( Type[] ) parameterTypes.toArray( new Type[0] ); processedPositionalParameterTypes = ( Type[] ) parameterTypes.toArray( new Type[parameterTypes.size()] );
processedSQL = result.toString(); processedSQL = result.toString();
} }
} }
@ -458,16 +443,16 @@ public final class QueryParameters {
public QueryParameters createCopyUsing(RowSelection selection) { public QueryParameters createCopyUsing(RowSelection selection) {
QueryParameters copy = new QueryParameters( QueryParameters copy = new QueryParameters(
this.positionalParameterTypes, this.positionalParameterTypes,
this.positionalParameterValues, this.positionalParameterValues,
this.namedParameters, this.namedParameters,
this.lockModes, this.lockModes,
selection, selection,
this.readOnly, this.readOnly,
this.cacheable, this.cacheable,
this.cacheRegion, this.cacheRegion,
this.comment, this.comment,
this.collectionKeys, this.collectionKeys,
this.optionalObject, this.optionalObject,
this.optionalEntityName, this.optionalEntityName,
this.optionalId, this.optionalId,
this.resultTransformer this.resultTransformer
@ -478,5 +463,13 @@ public final class QueryParameters {
return copy; return copy;
} }
public static String[] parseFilterParameterName(String filterParameterName) {
int dot = filterParameterName.indexOf( '.' );
if ( dot <= 0 ) {
throw new IllegalArgumentException( "Invalid filter-parameter name format" );
}
String filterName = filterParameterName.substring( 0, dot );
String parameterName = filterParameterName.substring( dot + 1 );
return new String[] { filterName, parameterName };
}
} }

View File

@ -209,6 +209,10 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
return collectionFilterRole != null; return collectionFilterRole != null;
} }
public String getCollectionFilterRole() {
return collectionFilterRole;
}
public SessionFactoryHelper getSessionFactoryHelper() { public SessionFactoryHelper getSessionFactoryHelper() {
return sessionFactoryHelper; return sessionFactoryHelper;
} }
@ -531,8 +535,8 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
// After that, process the JOINs. // After that, process the JOINs.
// Invoke a delegate to do the work, as this is farily complex. // Invoke a delegate to do the work, as this is farily complex.
JoinProcessor joinProcessor = new JoinProcessor( astFactory, queryTranslatorImpl ); JoinProcessor joinProcessor = new JoinProcessor( this );
joinProcessor.processJoins( qn, isSubQuery() ); joinProcessor.processJoins( qn );
// Attach any mapping-defined "ORDER BY" fragments // Attach any mapping-defined "ORDER BY" fragments
Iterator itr = qn.getFromClause().getProjectionList().iterator(); Iterator itr = qn.getFromClause().getProjectionList().iterator();
@ -570,13 +574,21 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
// Make #@%$^#^&# sure no alias is applied to the table name // Make #@%$^#^&# sure no alias is applied to the table name
fromElement.setText( persister.getTableName() ); fromElement.setText( persister.getTableName() );
// append any filter fragments; the EMPTY_MAP is used under the assumption that // // append any filter fragments; the EMPTY_MAP is used under the assumption that
// currently enabled filters should not affect this process // // currently enabled filters should not affect this process
if ( persister.getDiscriminatorType() != null ) { // if ( persister.getDiscriminatorType() != null ) {
new SyntheticAndFactory( getASTFactory() ).addDiscriminatorWhereFragment( // new SyntheticAndFactory( getASTFactory() ).addDiscriminatorWhereFragment(
// statement,
// persister,
// java.util.Collections.EMPTY_MAP,
// fromElement.getTableAlias()
// );
// }
if ( persister.getDiscriminatorType() != null || ! queryTranslatorImpl.getEnabledFilters().isEmpty() ) {
new SyntheticAndFactory( this ).addDiscriminatorWhereFragment(
statement, statement,
persister, persister,
java.util.Collections.EMPTY_MAP, queryTranslatorImpl.getEnabledFilters(),
fromElement.getTableAlias() fromElement.getTableAlias()
); );
} }

View File

@ -74,6 +74,8 @@ public class QueryTranslatorImpl implements FilterTranslator {
private String sql; private String sql;
private ParameterTranslations paramTranslations; private ParameterTranslations paramTranslations;
private List collectedParameterSpecifications;
/** /**
* Creates a new AST-based query translator. * Creates a new AST-based query translator.
@ -217,6 +219,7 @@ public class QueryTranslatorImpl implements FilterTranslator {
log.debug( "SQL: " + sql ); log.debug( "SQL: " + sql );
} }
gen.getParseErrorHandler().throwQueryException(); gen.getParseErrorHandler().throwQueryException();
collectedParameterSpecifications = gen.getCollectedParameters();
} }
} }
@ -540,10 +543,15 @@ public class QueryTranslatorImpl implements FilterTranslator {
public ParameterTranslations getParameterTranslations() { public ParameterTranslations getParameterTranslations() {
if ( paramTranslations == null ) { if ( paramTranslations == null ) {
paramTranslations = new ParameterTranslationsImpl( getWalker().getParameters() ); paramTranslations = new ParameterTranslationsImpl( getWalker().getParameters() );
// paramTranslations = new ParameterTranslationsImpl( collectedParameterSpecifications );
} }
return paramTranslations; return paramTranslations;
} }
public List getCollectedParameterSpecifications() {
return collectedParameterSpecifications;
}
public static class JavaConstantConverter implements NodeTraverser.VisitationStrategy { public static class JavaConstantConverter implements NodeTraverser.VisitationStrategy {
private AST dotRoot; private AST dotRoot;
public void visit(AST node) { public void visit(AST node) {

View File

@ -4,16 +4,20 @@ package org.hibernate.hql.ast;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Arrays;
import antlr.RecognitionException; import antlr.RecognitionException;
import antlr.collections.AST; import antlr.collections.AST;
import org.hibernate.QueryException; import org.hibernate.QueryException;
import org.hibernate.param.ParameterSpecification;
import org.hibernate.dialect.function.SQLFunction; import org.hibernate.dialect.function.SQLFunction;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.hql.antlr.SqlGeneratorBase; import org.hibernate.hql.antlr.SqlGeneratorBase;
import org.hibernate.hql.ast.tree.MethodNode; import org.hibernate.hql.ast.tree.MethodNode;
import org.hibernate.hql.ast.tree.FromElement; import org.hibernate.hql.ast.tree.FromElement;
import org.hibernate.hql.ast.tree.Node; import org.hibernate.hql.ast.tree.Node;
import org.hibernate.hql.ast.tree.ParameterNode;
import org.hibernate.hql.ast.tree.ParameterContainer;
/** /**
* Generates SQL by overriding callback methods in the base class, which does * Generates SQL by overriding callback methods in the base class, which does
@ -41,6 +45,12 @@ public class SqlGenerator extends SqlGeneratorBase implements ErrorReporter {
private LinkedList outputStack = new LinkedList(); private LinkedList outputStack = new LinkedList();
private List collectedParameters = new ArrayList();
public List getCollectedParameters() {
return collectedParameters;
}
protected void out(String s) { protected void out(String s) {
writer.clause( s ); writer.clause( s );
} }
@ -52,6 +62,18 @@ public class SqlGenerator extends SqlGeneratorBase implements ErrorReporter {
else { else {
super.out( n ); super.out( n );
} }
if ( n instanceof ParameterNode ) {
collectedParameters.add( ( ( ParameterNode ) n ).getHqlParameterSpecification() );
}
else if ( n instanceof ParameterContainer ) {
if ( ( ( ParameterContainer ) n ).hasEmbeddedParameters() ) {
ParameterSpecification[] specifications = ( ( ParameterContainer ) n ).getEmbeddedParameters();
if ( specifications != null ) {
collectedParameters.addAll( Arrays.asList( specifications ) );
}
}
}
} }
protected void commaBetweenParameters(String comma) { protected void commaBetweenParameters(String comma) {

View File

@ -4,6 +4,8 @@ package org.hibernate.hql.ast.exec;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.Connection; import java.sql.Connection;
import java.sql.Statement; import java.sql.Statement;
import java.util.Collections;
import java.util.List;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.action.BulkOperationCleanupAction; import org.hibernate.action.BulkOperationCleanupAction;
@ -34,6 +36,7 @@ public abstract class AbstractStatementExecutor implements StatementExecutor {
private final Log log; private final Log log;
private final HqlSqlWalker walker; private final HqlSqlWalker walker;
private List idSelectParameterSpecifications = Collections.EMPTY_LIST;
public AbstractStatementExecutor(HqlSqlWalker walker, Log log) { public AbstractStatementExecutor(HqlSqlWalker walker, Log log) {
this.walker = walker; this.walker = walker;
@ -48,6 +51,10 @@ public abstract class AbstractStatementExecutor implements StatementExecutor {
return walker.getSessionFactoryHelper().getFactory(); return walker.getSessionFactoryHelper().getFactory();
} }
protected List getIdSelectParameterSpecifications() {
return idSelectParameterSpecifications;
}
protected abstract Queryable[] getAffectedQueryables(); protected abstract Queryable[] getAffectedQueryables();
protected String generateIdInsertSelect(Queryable persister, String tableAlias, AST whereClause) { protected String generateIdInsertSelect(Queryable persister, String tableAlias, AST whereClause) {
@ -80,6 +87,7 @@ public abstract class AbstractStatementExecutor implements StatementExecutor {
SqlGenerator sqlGenerator = new SqlGenerator( getFactory() ); SqlGenerator sqlGenerator = new SqlGenerator( getFactory() );
sqlGenerator.whereClause( whereClause ); sqlGenerator.whereClause( whereClause );
userWhereClause = sqlGenerator.getSQL().substring( 7 ); // strip the " where " userWhereClause = sqlGenerator.getSQL().substring( 7 ); // strip the " where "
idSelectParameterSpecifications = sqlGenerator.getCollectedParameters();
} }
catch ( RecognitionException e ) { catch ( RecognitionException e ) {
throw new HibernateException( "Unable to generate id select for DML operation", e ); throw new HibernateException( "Unable to generate id select for DML operation", e );

View File

@ -4,6 +4,7 @@ package org.hibernate.hql.ast.exec;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.engine.QueryParameters; import org.hibernate.engine.QueryParameters;
@ -31,6 +32,7 @@ public class BasicExecutor extends AbstractStatementExecutor {
private final Queryable persister; private final Queryable persister;
private final String sql; private final String sql;
private final List parameterSpecifications;
public BasicExecutor(HqlSqlWalker walker, Queryable persister) { public BasicExecutor(HqlSqlWalker walker, Queryable persister) {
super( walker, log ); super( walker, log );
@ -40,6 +42,7 @@ public class BasicExecutor extends AbstractStatementExecutor {
gen.statement( walker.getAST() ); gen.statement( walker.getAST() );
sql = gen.getSQL(); sql = gen.getSQL();
gen.getParseErrorHandler().throwQueryException(); gen.getParseErrorHandler().throwQueryException();
parameterSpecifications = gen.getCollectedParameters();
} }
catch ( RecognitionException e ) { catch ( RecognitionException e ) {
throw QuerySyntaxException.convert( e ); throw QuerySyntaxException.convert( e );
@ -60,10 +63,10 @@ public class BasicExecutor extends AbstractStatementExecutor {
try { try {
try { try {
st = session.getBatcher().prepareStatement( sql ); st = session.getBatcher().prepareStatement( sql );
Iterator paramSpecifications = getWalker().getParameters().iterator(); Iterator parameterSpecifications = this.parameterSpecifications.iterator();
int pos = 1; int pos = 1;
while ( paramSpecifications.hasNext() ) { while ( parameterSpecifications.hasNext() ) {
final ParameterSpecification paramSpec = ( ParameterSpecification ) paramSpecifications.next(); final ParameterSpecification paramSpec = ( ParameterSpecification ) parameterSpecifications.next();
pos += paramSpec.bind( st, parameters, session, pos ); pos += paramSpec.bind( st, parameters, session, pos );
} }
if ( selection != null ) { if ( selection != null ) {

View File

@ -84,7 +84,7 @@ public class MultiTableDeleteExecutor extends AbstractStatementExecutor {
try { try {
try { try {
ps = session.getBatcher().prepareStatement( idInsertSelect ); ps = session.getBatcher().prepareStatement( idInsertSelect );
Iterator paramSpecifications = getWalker().getParameters().iterator(); Iterator paramSpecifications = getIdSelectParameterSpecifications().iterator();
int pos = 1; int pos = 1;
while ( paramSpecifications.hasNext() ) { while ( paramSpecifications.hasNext() ) {
final ParameterSpecification paramSpec = ( ParameterSpecification ) paramSpecifications.next(); final ParameterSpecification paramSpec = ( ParameterSpecification ) paramSpecifications.next();

View File

@ -109,7 +109,7 @@ public class MultiTableUpdateExecutor extends AbstractStatementExecutor {
try { try {
ps = session.getBatcher().prepareStatement( idInsertSelect ); ps = session.getBatcher().prepareStatement( idInsertSelect );
int parameterStart = getWalker().getNumberOfParametersInSetClause(); int parameterStart = getWalker().getNumberOfParametersInSetClause();
List allParams = getWalker().getParameters(); List allParams = getIdSelectParameterSpecifications();
Iterator whereParams = allParams.subList( parameterStart, allParams.size() ).iterator(); Iterator whereParams = allParams.subList( parameterStart, allParams.size() ).iterator();
int sum = 1; // jdbc params are 1-based int sum = 1; // jdbc params are 1-based
while ( whereParams.hasNext() ) { while ( whereParams.hasNext() ) {

View File

@ -3,8 +3,10 @@ package org.hibernate.hql.ast.tree;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.ArrayList;
import org.hibernate.QueryException; import org.hibernate.QueryException;
import org.hibernate.param.ParameterSpecification;
import org.hibernate.engine.JoinSequence; import org.hibernate.engine.JoinSequence;
import org.hibernate.hql.QueryTranslator; import org.hibernate.hql.QueryTranslator;
import org.hibernate.hql.CollectionProperties; import org.hibernate.hql.CollectionProperties;
@ -36,7 +38,7 @@ import org.apache.commons.logging.LogFactory;
* Date: Dec 6, 2003<br> * Date: Dec 6, 2003<br>
* Time: 10:28:17 AM<br> * Time: 10:28:17 AM<br>
*/ */
public class FromElement extends HqlSqlWalkerNode implements DisplayableNode { public class FromElement extends HqlSqlWalkerNode implements DisplayableNode, ParameterContainer {
private static final Log log = LogFactory.getLog( FromElement.class ); private static final Log log = LogFactory.getLog( FromElement.class );
private String className; private String className;
@ -548,4 +550,23 @@ public class FromElement extends HqlSqlWalkerNode implements DisplayableNode {
public boolean isDereferencedBySubclassProperty() { public boolean isDereferencedBySubclassProperty() {
return dereferencedBySubclassProperty; return dereferencedBySubclassProperty;
} }
// ParameterContainer impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private List embeddedParameters;
public void addEmbeddedParameter(ParameterSpecification specification) {
if ( embeddedParameters == null ) {
embeddedParameters = new ArrayList();
}
embeddedParameters.add( specification );
}
public boolean hasEmbeddedParameters() {
return embeddedParameters != null && ! embeddedParameters.isEmpty();
}
public ParameterSpecification[] getEmbeddedParameters() {
return ( ParameterSpecification[] ) embeddedParameters.toArray( new ParameterSpecification[ embeddedParameters.size() ] );
}
} }

View File

@ -0,0 +1,77 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.hql.ast.tree;
import org.hibernate.param.ParameterSpecification;
/**
* Currently this is needed in order to deal with {@link FromElement FromElements} which
* conatin "hidden" JDBC parameters from applying filters.
* <p/>
* Would love for this to go away, but that would require that Hibernate's
* internal {@link org.hibernate.engine.JoinSequence join handling} be able to either:<ul>
* <li>render the same AST structures</li>
* <li>render structures capable of being converted to these AST structures</li>
* </ul>
* <p/>
* In the interim, this allows us to at least treat these "hidden" parameters properly which is
* the most pressing need.
*
* @deprecated
* @author Steve Ebersole
*/
public interface ParameterContainer {
/**
* Set the renderable text of this node.
*
* @param text The renderable text
*/
public void setText(String text);
/**
* Adds a parameter specification for a parameter encountered within this node. We use the term 'embedded' here
* because of the fact that the parameter was simply encountered as part of the node's text; it does not exist
* as part of a subtree as it might in a true AST.
*
* @param specification The generated specification.
*/
public void addEmbeddedParameter(ParameterSpecification specification);
/**
* Determine whether this node contans embedded parameters. The implication is that
* {@link #getEmbeddedParameters()} is allowed to return null if this method returns false.
*
* @return True if this node contains embedded parameters; false otherwise.
*/
public boolean hasEmbeddedParameters();
/**
* Retrieve all embedded parameter specifications.
*
* @return All embedded parameter specifications; may return null.
* @see #hasEmbeddedParameters()
*/
public ParameterSpecification[] getEmbeddedParameters();
}

View File

@ -1,14 +1,41 @@
// $Id$ /*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.hql.ast.tree; package org.hibernate.hql.ast.tree;
import java.util.List;
import java.util.ArrayList;
import org.hibernate.sql.JoinFragment; import org.hibernate.sql.JoinFragment;
import org.hibernate.param.ParameterSpecification;
/** /**
* Represents an SQL fragment in the AST. * Represents an SQL fragment in the AST.
* *
* @author josh Dec 5, 2004 9:01:52 AM * @author josh
*/ */
public class SqlFragment extends Node { public class SqlFragment extends Node implements ParameterContainer {
private JoinFragment joinFragment; private JoinFragment joinFragment;
private FromElement fromElement; private FromElement fromElement;
@ -27,4 +54,23 @@ public class SqlFragment extends Node {
public FromElement getFromElement() { public FromElement getFromElement() {
return fromElement; return fromElement;
} }
// ParameterContainer impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private List embeddedParameters;
public void addEmbeddedParameter(ParameterSpecification specification) {
if ( embeddedParameters == null ) {
embeddedParameters = new ArrayList();
}
embeddedParameters.add( specification );
}
public boolean hasEmbeddedParameters() {
return embeddedParameters != null && ! embeddedParameters.isEmpty();
}
public ParameterSpecification[] getEmbeddedParameters() {
return ( ParameterSpecification[] ) embeddedParameters.toArray( new ParameterSpecification[ embeddedParameters.size() ] );
}
} }

View File

@ -4,21 +4,28 @@ package org.hibernate.hql.ast.util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.StringTokenizer;
import java.util.Collection;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.param.DynamicFilterParameterSpecification;
import org.hibernate.type.Type;
import org.hibernate.impl.FilterImpl;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.JoinSequence; import org.hibernate.engine.JoinSequence;
import org.hibernate.engine.QueryParameters;
import org.hibernate.hql.antlr.SqlTokenTypes; import org.hibernate.hql.antlr.SqlTokenTypes;
import org.hibernate.hql.ast.QueryTranslatorImpl; import org.hibernate.hql.ast.HqlSqlWalker;
import org.hibernate.hql.ast.tree.FromClause; import org.hibernate.hql.ast.tree.FromClause;
import org.hibernate.hql.ast.tree.FromElement; import org.hibernate.hql.ast.tree.FromElement;
import org.hibernate.hql.ast.tree.QueryNode; import org.hibernate.hql.ast.tree.QueryNode;
import org.hibernate.hql.ast.tree.DotNode; import org.hibernate.hql.ast.tree.DotNode;
import org.hibernate.hql.ast.tree.ParameterContainer;
import org.hibernate.hql.classic.ParserHelper;
import org.hibernate.sql.JoinFragment; import org.hibernate.sql.JoinFragment;
import org.hibernate.util.StringHelper; import org.hibernate.util.StringHelper;
import org.hibernate.util.ArrayHelper;
import antlr.ASTFactory;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -34,18 +41,17 @@ public class JoinProcessor implements SqlTokenTypes {
private static final Log log = LogFactory.getLog( JoinProcessor.class ); private static final Log log = LogFactory.getLog( JoinProcessor.class );
private QueryTranslatorImpl queryTranslatorImpl; private final HqlSqlWalker walker;
private SyntheticAndFactory andFactory; private final SyntheticAndFactory syntheticAndFactory;
/** /**
* Constructs a new JoinProcessor. * Constructs a new JoinProcessor.
* *
* @param astFactory The factory for AST node creation. * @param walker The walker to which we are bound, giving us access to needed resources.
* @param queryTranslatorImpl The query translator.
*/ */
public JoinProcessor(ASTFactory astFactory, QueryTranslatorImpl queryTranslatorImpl) { public JoinProcessor(HqlSqlWalker walker) {
this.andFactory = new SyntheticAndFactory( astFactory ); this.walker = walker;
this.queryTranslatorImpl = queryTranslatorImpl; this.syntheticAndFactory = new SyntheticAndFactory( walker );
} }
/** /**
@ -69,7 +75,7 @@ public class JoinProcessor implements SqlTokenTypes {
} }
} }
public void processJoins(QueryNode query, boolean inSubquery) { public void processJoins(QueryNode query) {
final FromClause fromClause = query.getFromClause(); final FromClause fromClause = query.getFromClause();
final List fromElements; final List fromElements;
@ -108,22 +114,21 @@ public class JoinProcessor implements SqlTokenTypes {
log.trace( "forcing inclusion of extra joins [alias=" + alias + ", containsTableAlias=" + containsTableAlias + "]" ); log.trace( "forcing inclusion of extra joins [alias=" + alias + ", containsTableAlias=" + containsTableAlias + "]" );
return true; return true;
} }
boolean shallowQuery = queryTranslatorImpl.isShallowQuery(); boolean shallowQuery = walker.isShallowQuery();
boolean includeSubclasses = fromElement.isIncludeSubclasses(); boolean includeSubclasses = fromElement.isIncludeSubclasses();
boolean subQuery = fromClause.isSubQuery(); boolean subQuery = fromClause.isSubQuery();
return includeSubclasses && containsTableAlias && !subQuery && !shallowQuery; return includeSubclasses && containsTableAlias && !subQuery && !shallowQuery;
} }
} }
); );
addJoinNodes( query, join, fromElement, inSubquery ); addJoinNodes( query, join, fromElement );
} }
} }
private void addJoinNodes(QueryNode query, JoinSequence join, FromElement fromElement, boolean inSubquery) { private void addJoinNodes(QueryNode query, JoinSequence join, FromElement fromElement) {
// Generate FROM and WHERE fragments for the from element.
JoinFragment joinFragment = join.toJoinFragment( JoinFragment joinFragment = join.toJoinFragment(
inSubquery ? Collections.EMPTY_MAP : queryTranslatorImpl.getEnabledFilters(), walker.getEnabledFilters(),
fromElement.useFromFragment() || fromElement.isDereferencedBySuperclassOrSubclassProperty(), fromElement.useFromFragment() || fromElement.isDereferencedBySuperclassOrSubclassProperty(),
fromElement.getWithClauseFragment(), fromElement.getWithClauseFragment(),
fromElement.getWithClauseJoinAlias() fromElement.getWithClauseJoinAlias()
@ -143,13 +148,24 @@ public class JoinProcessor implements SqlTokenTypes {
// If there is a FROM fragment and the FROM element is an explicit, then add the from part. // If there is a FROM fragment and the FROM element is an explicit, then add the from part.
if ( fromElement.useFromFragment() /*&& StringHelper.isNotEmpty( frag )*/ ) { if ( fromElement.useFromFragment() /*&& StringHelper.isNotEmpty( frag )*/ ) {
String fromFragment = processFromFragment( frag, join ); String fromFragment = processFromFragment( frag, join ).trim();
if ( log.isDebugEnabled() ) { if ( log.isDebugEnabled() ) {
log.debug( "Using FROM fragment [" + fromFragment + "]" ); log.debug( "Using FROM fragment [" + fromFragment + "]" );
} }
fromElement.setText( fromFragment.trim() ); // Set the text of the fromElement. processDynamicFilterParameters(
fromFragment,
fromElement,
walker
);
} }
andFactory.addWhereFragment( joinFragment, whereFrag, query, fromElement );
syntheticAndFactory.addWhereFragment(
joinFragment,
whereFrag,
query,
fromElement,
walker
);
} }
private String processFromFragment(String frag, JoinSequence join) { private String processFromFragment(String frag, JoinSequence join) {
@ -161,4 +177,56 @@ public class JoinProcessor implements SqlTokenTypes {
return fromFragment; return fromFragment;
} }
public static void processDynamicFilterParameters(
final String sqlFragment,
final ParameterContainer container,
final HqlSqlWalker walker) {
if ( walker.getEnabledFilters().isEmpty()
&& ( ! hasDynamicFilterParam( sqlFragment ) )
&& ( ! ( hasCollectionFilterParam( sqlFragment ) ) ) ) {
return;
}
Dialect dialect = walker.getSessionFactoryHelper().getFactory().getDialect();
String symbols = new StringBuffer().append( ParserHelper.HQL_SEPARATORS )
.append( dialect.openQuote() )
.append( dialect.closeQuote() )
.toString();
StringTokenizer tokens = new StringTokenizer( sqlFragment, symbols, true );
StringBuffer result = new StringBuffer();
while ( tokens.hasMoreTokens() ) {
final String token = tokens.nextToken();
if ( token.startsWith( ParserHelper.HQL_VARIABLE_PREFIX ) ) {
final String filterParameterName = token.substring( 1 );
final String[] parts = QueryParameters.parseFilterParameterName( filterParameterName );
final FilterImpl filter = ( FilterImpl ) walker.getEnabledFilters().get( parts[0] );
final Object value = filter.getParameter( parts[1] );
final Type type = filter.getFilterDefinition().getParameterType( parts[1] );
final String typeBindFragment = StringHelper.join(
",",
ArrayHelper.fillArray( "?", type.getColumnSpan( walker.getSessionFactoryHelper().getFactory() ) )
);
final String bindFragment = ( value != null && Collection.class.isInstance( value ) )
? StringHelper.join( ",", ArrayHelper.fillArray( typeBindFragment, ( ( Collection ) value ).size() ) )
: typeBindFragment;
result.append( bindFragment );
container.addEmbeddedParameter( new DynamicFilterParameterSpecification( parts[0], parts[1], type ) );
}
else {
result.append( token );
}
}
container.setText( result.toString() );
}
private static boolean hasDynamicFilterParam(String sqlFragment) {
return sqlFragment.indexOf( ParserHelper.HQL_VARIABLE_PREFIX ) < 0;
}
private static boolean hasCollectionFilterParam(String sqlFragment) {
return sqlFragment.indexOf( "?" ) < 0;
}
} }

View File

@ -2,18 +2,20 @@
package org.hibernate.hql.ast.util; package org.hibernate.hql.ast.util;
import java.util.Map; import java.util.Map;
import java.util.StringTokenizer;
import org.hibernate.hql.antlr.HqlSqlTokenTypes; import org.hibernate.hql.antlr.HqlSqlTokenTypes;
import org.hibernate.hql.ast.tree.FromElement; import org.hibernate.hql.ast.tree.FromElement;
import org.hibernate.hql.ast.tree.QueryNode; import org.hibernate.hql.ast.tree.QueryNode;
import org.hibernate.hql.ast.tree.RestrictableStatement; import org.hibernate.hql.ast.tree.RestrictableStatement;
import org.hibernate.hql.ast.tree.SqlFragment; import org.hibernate.hql.ast.tree.SqlFragment;
import org.hibernate.hql.ast.tree.Node;
import org.hibernate.hql.ast.HqlSqlWalker;
import org.hibernate.persister.entity.Queryable; import org.hibernate.persister.entity.Queryable;
import org.hibernate.sql.JoinFragment; import org.hibernate.sql.JoinFragment;
import org.hibernate.util.StringHelper; import org.hibernate.util.StringHelper;
import org.hibernate.type.Type;
import org.hibernate.param.CollectionFilterKeyParameterSpecification;
import antlr.ASTFactory;
import antlr.collections.AST; import antlr.collections.AST;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@ -27,27 +29,36 @@ import org.apache.commons.logging.LogFactory;
public class SyntheticAndFactory implements HqlSqlTokenTypes { public class SyntheticAndFactory implements HqlSqlTokenTypes {
private static final Log log = LogFactory.getLog( SyntheticAndFactory.class ); private static final Log log = LogFactory.getLog( SyntheticAndFactory.class );
private ASTFactory astFactory; private HqlSqlWalker hqlSqlWalker;
private AST thetaJoins; private AST thetaJoins;
private AST filters; private AST filters;
public SyntheticAndFactory(ASTFactory astFactory) { public SyntheticAndFactory(HqlSqlWalker hqlSqlWalker) {
this.astFactory = astFactory; this.hqlSqlWalker = hqlSqlWalker;
} }
public void addWhereFragment(JoinFragment joinFragment, String whereFragment, QueryNode query, FromElement fromElement) { private Node create(int tokenType, String text) {
return ( Node ) ASTUtil.create( hqlSqlWalker.getASTFactory(), tokenType, text );
}
public void addWhereFragment(
JoinFragment joinFragment,
String whereFragment,
QueryNode query,
FromElement fromElement,
HqlSqlWalker hqlSqlWalker) {
if ( whereFragment == null ) { if ( whereFragment == null ) {
return; return;
} }
if ( !fromElement.useWhereFragment() && !joinFragment.hasThetaJoins() ) {
return;
}
whereFragment = whereFragment.trim(); whereFragment = whereFragment.trim();
if ( StringHelper.isEmpty( whereFragment ) ) { if ( StringHelper.isEmpty( whereFragment ) ) {
return; return;
} }
else if ( !fromElement.useWhereFragment() && !joinFragment.hasThetaJoins() ) {
return;
}
// Forcefully remove leading ands from where fragments; the grammar will // Forcefully remove leading ands from where fragments; the grammar will
// handle adding them // handle adding them
@ -55,12 +66,36 @@ public class SyntheticAndFactory implements HqlSqlTokenTypes {
whereFragment = whereFragment.substring( 4 ); whereFragment = whereFragment.substring( 4 );
} }
if ( log.isDebugEnabled() ) log.debug( "Using WHERE fragment [" + whereFragment + "]" ); if ( log.isDebugEnabled() ) {
log.debug( "Using unprocessed WHERE-fragment [" + whereFragment + "]");
}
SqlFragment fragment = ( SqlFragment ) ASTUtil.create( astFactory, SQL_TOKEN, whereFragment ); SqlFragment fragment = ( SqlFragment ) create( SQL_TOKEN, whereFragment );
fragment.setJoinFragment( joinFragment ); fragment.setJoinFragment( joinFragment );
fragment.setFromElement( fromElement ); fragment.setFromElement( fromElement );
if ( hqlSqlWalker.isFilter() ) {
if ( whereFragment.indexOf( '?' ) >= 0 ) {
Type collectionFilterKeyType = hqlSqlWalker.getSessionFactoryHelper()
.requireQueryableCollection( hqlSqlWalker.getCollectionFilterRole() )
.getKeyType();
CollectionFilterKeyParameterSpecification paramSpec = new CollectionFilterKeyParameterSpecification(
hqlSqlWalker.getCollectionFilterRole(),
collectionFilterKeyType,
0
);
fragment.addEmbeddedParameter( paramSpec );
}
}
JoinProcessor.processDynamicFilterParameters(
whereFragment,
fragment,
hqlSqlWalker
);
log.debug( "Using processed WHERE-fragment [" + fragment.getText() + "]" );
// Filter conditions need to be inserted before the HQL where condition and the // Filter conditions need to be inserted before the HQL where condition and the
// theta join node. This is because org.hibernate.loader.Loader binds the filter parameters first, // theta join node. This is because org.hibernate.loader.Loader binds the filter parameters first,
// then it binds all the HQL query parameters, see org.hibernate.loader.Loader.processFilterParameters(). // then it binds all the HQL query parameters, see org.hibernate.loader.Loader.processFilterParameters().
@ -69,11 +104,11 @@ public class SyntheticAndFactory implements HqlSqlTokenTypes {
// Find or create the WHERE clause // Find or create the WHERE clause
AST where = query.getWhereClause(); AST where = query.getWhereClause();
// Create a new FILTERS node as a parent of all filters // Create a new FILTERS node as a parent of all filters
filters = astFactory.create( FILTERS, "{filter conditions}" ); filters = create( FILTERS, "{filter conditions}" );
// Put the FILTERS node before the HQL condition and theta joins // Put the FILTERS node before the HQL condition and theta joins
ASTUtil.insertChild( where, filters ); ASTUtil.insertChild( where, filters );
} }
// add the current fragment to the FILTERS node // add the current fragment to the FILTERS node
filters.addChild( fragment ); filters.addChild( fragment );
} }
@ -82,7 +117,7 @@ public class SyntheticAndFactory implements HqlSqlTokenTypes {
// Find or create the WHERE clause // Find or create the WHERE clause
AST where = query.getWhereClause(); AST where = query.getWhereClause();
// Create a new THETA_JOINS node as a parent of all filters // Create a new THETA_JOINS node as a parent of all filters
thetaJoins = astFactory.create( THETA_JOINS, "{theta joins}" ); thetaJoins = create( THETA_JOINS, "{theta joins}" );
// Put the THETA_JOINS node before the HQL condition, after the filters. // Put the THETA_JOINS node before the HQL condition, after the filters.
if (filters==null) { if (filters==null) {
ASTUtil.insertChild( where, thetaJoins ); ASTUtil.insertChild( where, thetaJoins );
@ -91,14 +126,18 @@ public class SyntheticAndFactory implements HqlSqlTokenTypes {
ASTUtil.insertSibling( thetaJoins, filters ); ASTUtil.insertSibling( thetaJoins, filters );
} }
} }
// add the current fragment to the THETA_JOINS node // add the current fragment to the THETA_JOINS node
thetaJoins.addChild(fragment); thetaJoins.addChild(fragment);
} }
} }
public void addDiscriminatorWhereFragment(RestrictableStatement statement, Queryable persister, Map enabledFilters, String alias) { public void addDiscriminatorWhereFragment(
RestrictableStatement statement,
Queryable persister,
Map enabledFilters,
String alias) {
String whereFragment = persister.filterFragment( alias, enabledFilters ).trim(); String whereFragment = persister.filterFragment( alias, enabledFilters ).trim();
if ( "".equals( whereFragment ) ) { if ( "".equals( whereFragment ) ) {
return; return;
@ -118,13 +157,19 @@ public class SyntheticAndFactory implements HqlSqlTokenTypes {
// At some point we probably want to apply an additional grammar to // At some point we probably want to apply an additional grammar to
// properly tokenize this where fragment into constituent parts // properly tokenize this where fragment into constituent parts
// focused on the operators embedded within the fragment. // focused on the operators embedded within the fragment.
AST discrimNode = astFactory.create( SQL_TOKEN, whereFragment ); SqlFragment discrimNode = ( SqlFragment ) create( SQL_TOKEN, whereFragment );
JoinProcessor.processDynamicFilterParameters(
whereFragment,
discrimNode,
hqlSqlWalker
);
if ( statement.getWhereClause().getNumberOfChildren() == 0 ) { if ( statement.getWhereClause().getNumberOfChildren() == 0 ) {
statement.getWhereClause().setFirstChild( discrimNode ); statement.getWhereClause().setFirstChild( discrimNode );
} }
else { else {
AST and = astFactory.create( AND, "{and}" ); AST and = create( AND, "{and}" );
AST currentFirstChild = statement.getWhereClause().getFirstChild(); AST currentFirstChild = statement.getWhereClause().getFirstChild();
and.setFirstChild( discrimNode ); and.setFirstChild( discrimNode );
and.addChild( currentFirstChild ); and.addChild( currentFirstChild );

View File

@ -483,8 +483,8 @@ public class QueryLoader extends BasicLoader {
final QueryParameters queryParameters, final QueryParameters queryParameters,
final int startIndex, final int startIndex,
final SessionImplementor session) throws SQLException { final SessionImplementor session) throws SQLException {
int position = bindFilterParameterValues( statement, queryParameters, startIndex, session ); int position = startIndex;
List parameterSpecs = queryTranslator.getSqlAST().getWalker().getParameters(); List parameterSpecs = queryTranslator.getCollectedParameterSpecifications();
Iterator itr = parameterSpecs.iterator(); Iterator itr = parameterSpecs.iterator();
while ( itr.hasNext() ) { while ( itr.hasNext() ) {
ParameterSpecification spec = ( ParameterSpecification ) itr.next(); ParameterSpecification spec = ( ParameterSpecification ) itr.next();

View File

@ -8,13 +8,12 @@ import org.hibernate.engine.SessionImplementor;
import org.hibernate.type.Type; import org.hibernate.type.Type;
/** /**
* A specialized ParameterSpecification impl for dealing with a collection-key * A specialized ParameterSpecification impl for dealing with a collection-key as part of a collection filter
* as part of a collection filter compilation. * compilation.
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class CollectionFilterKeyParameterSpecification implements ParameterSpecification { public class CollectionFilterKeyParameterSpecification implements ParameterSpecification {
private final String collectionRole; private final String collectionRole;
private final Type keyType; private final Type keyType;
private final int queryParameterPosition; private final int queryParameterPosition;
@ -34,6 +33,9 @@ public class CollectionFilterKeyParameterSpecification implements ParameterSpeci
this.queryParameterPosition = queryParameterPosition; this.queryParameterPosition = queryParameterPosition;
} }
/**
* {@inheritDoc}
*/
public int bind( public int bind(
PreparedStatement statement, PreparedStatement statement,
QueryParameters qp, QueryParameters qp,
@ -44,14 +46,23 @@ public class CollectionFilterKeyParameterSpecification implements ParameterSpeci
return keyType.getColumnSpan( session.getFactory() ); return keyType.getColumnSpan( session.getFactory() );
} }
/**
* {@inheritDoc}
*/
public Type getExpectedType() { public Type getExpectedType() {
return keyType; return keyType;
} }
/**
* {@inheritDoc}
*/
public void setExpectedType(Type expectedType) { public void setExpectedType(Type expectedType) {
// todo : throw exception? // todo : throw exception?
} }
/**
* {@inheritDoc}
*/
public String renderDisplayInfo() { public String renderDisplayInfo() {
return "collection-filter-key=" + collectionRole; return "collection-filter-key=" + collectionRole;
} }

View File

@ -2,20 +2,17 @@ package org.hibernate.param;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Collection;
import java.util.Iterator;
import org.hibernate.engine.QueryParameters; import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.SessionImplementor; import org.hibernate.engine.SessionImplementor;
import org.hibernate.type.Type; import org.hibernate.type.Type;
/** /**
* A specialized ParameterSpecification impl for dealing with a dynamic filter * A specialized ParameterSpecification impl for dealing with a dynamic filter parameters.
* parameters. *
* <p/> * @see org.hibernate.Session#enableFilter(String)
* Note: this class is currently not used. The ideal way to deal with dynamic filter
* parameters for HQL would be to track them just as we do with other parameters
* in the translator. However, the problem with that is that we currently do not
* know the filters which actually apply to the query; we know the active/enabled ones,
* but not the ones that actually "make it into" the resulting query.
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@ -23,37 +20,65 @@ public class DynamicFilterParameterSpecification implements ParameterSpecificati
private final String filterName; private final String filterName;
private final String parameterName; private final String parameterName;
private final Type definedParameterType; private final Type definedParameterType;
private final int queryParameterPosition;
/**
* Constructs a parameter specification for a particular filter parameter.
*
* @param filterName The name of the filter
* @param parameterName The name of the parameter
* @param definedParameterType The paremeter type specified on the filter metadata
*/
public DynamicFilterParameterSpecification( public DynamicFilterParameterSpecification(
String filterName, String filterName,
String parameterName, String parameterName,
Type definedParameterType, Type definedParameterType) {
int queryParameterPosition) {
this.filterName = filterName; this.filterName = filterName;
this.parameterName = parameterName; this.parameterName = parameterName;
this.definedParameterType = definedParameterType; this.definedParameterType = definedParameterType;
this.queryParameterPosition = queryParameterPosition;
} }
/**
* {@inheritDoc}
*/
public int bind( public int bind(
PreparedStatement statement, PreparedStatement statement,
QueryParameters qp, QueryParameters qp,
SessionImplementor session, SessionImplementor session,
int position) throws SQLException { int start) throws SQLException {
Object value = qp.getFilteredPositionalParameterValues()[queryParameterPosition]; final int columnSpan = definedParameterType.getColumnSpan( session.getFactory() );
definedParameterType.nullSafeSet( statement, value, position, session ); final Object value = session.getFilterParameterValue( filterName + '.' + parameterName );
return definedParameterType.getColumnSpan( session.getFactory() ); if ( Collection.class.isInstance( value ) ) {
int positions = 0;
Iterator itr = ( ( Collection ) value ).iterator();
while ( itr.hasNext() ) {
definedParameterType.nullSafeSet( statement, itr.next(), start + positions, session );
positions += columnSpan;
}
return positions;
}
else {
definedParameterType.nullSafeSet( statement, value, start, session );
return columnSpan;
}
} }
/**
* {@inheritDoc}
*/
public Type getExpectedType() { public Type getExpectedType() {
return definedParameterType; return definedParameterType;
} }
/**
* {@inheritDoc}
*/
public void setExpectedType(Type expectedType) { public void setExpectedType(Type expectedType) {
// todo : throw exception? // todo : throw exception? maybe warn if not the same?
} }
/**
* {@inheritDoc}
*/
public String renderDisplayInfo() { public String renderDisplayInfo() {
return "dynamic-filter={filterName=" + filterName + ",paramName=" + parameterName + "}"; return "dynamic-filter={filterName=" + filterName + ",paramName=" + parameterName + "}";
} }

View File

@ -9,14 +9,20 @@ import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
/** /**
* Relates to an explicit query named-parameter. * Parameter bind specification for an explicit named parameter.
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class NamedParameterSpecification extends AbstractExplicitParameterSpecification implements ParameterSpecification { public class NamedParameterSpecification extends AbstractExplicitParameterSpecification implements ParameterSpecification {
private final String name; private final String name;
/**
* Constructs a named parameter bind specification.
*
* @param sourceLine See {@link #getSourceLine()}
* @param sourceColumn See {@link #getSourceColumn()}
* @param name The named parameter name.
*/
public NamedParameterSpecification(int sourceLine, int sourceColumn, String name) { public NamedParameterSpecification(int sourceLine, int sourceColumn, String name) {
super( sourceLine, sourceColumn ); super( sourceLine, sourceColumn );
this.name = name; this.name = name;
@ -39,10 +45,18 @@ public class NamedParameterSpecification extends AbstractExplicitParameterSpecif
return typedValue.getType().getColumnSpan( session.getFactory() ); return typedValue.getType().getColumnSpan( session.getFactory() );
} }
/**
* {@inheritDoc}
*/
public String renderDisplayInfo() { public String renderDisplayInfo() {
return "name=" + name + ", expectedType=" + getExpectedType(); return "name=" + name + ", expectedType=" + getExpectedType();
} }
/**
* Getter for property 'name'.
*
* @return Value for property 'name'.
*/
public String getName() { public String getName() {
return name; return name;
} }

View File

@ -9,14 +9,20 @@ import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
/** /**
* Relates to an explicit query positional (or ordinal) parameter. * Parameter bind specification for an explicit positional (or ordinal) parameter.
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class PositionalParameterSpecification extends AbstractExplicitParameterSpecification implements ParameterSpecification { public class PositionalParameterSpecification extends AbstractExplicitParameterSpecification implements ParameterSpecification {
private final int hqlPosition; private final int hqlPosition;
/**
* Constructs a position/ordinal parameter bind specification.
*
* @param sourceLine See {@link #getSourceLine()}
* @param sourceColumn See {@link #getSourceColumn()}
* @param hqlPosition The position in the source query, relative to the other source positional parameters.
*/
public PositionalParameterSpecification(int sourceLine, int sourceColumn, int hqlPosition) { public PositionalParameterSpecification(int sourceLine, int sourceColumn, int hqlPosition) {
super( sourceLine, sourceColumn ); super( sourceLine, sourceColumn );
this.hqlPosition = hqlPosition; this.hqlPosition = hqlPosition;
@ -40,10 +46,18 @@ public class PositionalParameterSpecification extends AbstractExplicitParameterS
return type.getColumnSpan( session.getFactory() ); return type.getColumnSpan( session.getFactory() );
} }
/**
* {@inheritDoc}
*/
public String renderDisplayInfo() { public String renderDisplayInfo() {
return "ordinal=" + hqlPosition + ", expectedType=" + getExpectedType(); return "ordinal=" + hqlPosition + ", expectedType=" + getExpectedType();
} }
/**
* Getter for property 'hqlPosition'.
*
* @return Value for property 'hqlPosition'.
*/
public int getHqlPosition() { public int getHqlPosition() {
return hqlPosition; return hqlPosition;
} }

View File

@ -11,20 +11,24 @@ import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
/** /**
* Implementation of VersionTypeSeedParameterSpecification. * Parameter bind specification used for optimisitc lock version seeding (from insert statements).
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class VersionTypeSeedParameterSpecification implements ParameterSpecification { public class VersionTypeSeedParameterSpecification implements ParameterSpecification {
private VersionType type; private VersionType type;
/**
* Constructs a version seed parameter bind specification.
*
* @param type The version type.
*/
public VersionTypeSeedParameterSpecification(VersionType type) { public VersionTypeSeedParameterSpecification(VersionType type) {
this.type = type; this.type = type;
} }
/** /**
* @see org.hibernate.param.ParameterSpecification#bind * {@inheritDoc}
*/ */
public int bind(PreparedStatement statement, QueryParameters qp, SessionImplementor session, int position) public int bind(PreparedStatement statement, QueryParameters qp, SessionImplementor session, int position)
throws SQLException { throws SQLException {
@ -32,14 +36,23 @@ public class VersionTypeSeedParameterSpecification implements ParameterSpecifica
return 1; return 1;
} }
/**
* {@inheritDoc}
*/
public Type getExpectedType() { public Type getExpectedType() {
return type; return type;
} }
/**
* {@inheritDoc}
*/
public void setExpectedType(Type expectedType) { public void setExpectedType(Type expectedType) {
// expected type is intrinsic here... // expected type is intrinsic here...
} }
/**
* {@inheritDoc}
*/
public String renderDisplayInfo() { public String renderDisplayInfo() {
return "version-seed, type=" + type; return "version-seed, type=" + type;
} }

View File

@ -10,26 +10,26 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import junit.framework.Test; import junit.framework.Test;
import junit.framework.TestSuite;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.EntityMode; import org.hibernate.EntityMode;
import org.hibernate.FetchMode; import org.hibernate.FetchMode;
import org.hibernate.Hibernate; import org.hibernate.Hibernate;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.Transaction; import org.hibernate.Transaction;
import org.hibernate.junit.functional.FunctionalTestCase; import org.hibernate.Criteria;
import org.hibernate.junit.functional.FunctionalTestClassTestSuite; import org.hibernate.impl.SessionFactoryImpl;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.cache.CacheKey; import org.hibernate.cache.CacheKey;
import org.hibernate.cache.entry.CollectionCacheEntry; import org.hibernate.cache.entry.CollectionCacheEntry;
import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment; import org.hibernate.cfg.Environment;
import org.hibernate.criterion.Expression; import org.hibernate.criterion.Restrictions;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.impl.SessionFactoryImpl; import org.hibernate.criterion.Property;
import org.hibernate.criterion.Subqueries;
import org.hibernate.junit.functional.FunctionalTestCase;
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.test.TestCase;
import org.hibernate.transform.DistinctRootEntityResultTransformer; import org.hibernate.transform.DistinctRootEntityResultTransformer;
/** /**
@ -39,8 +39,6 @@ import org.hibernate.transform.DistinctRootEntityResultTransformer;
*/ */
public class DynamicFilterTest extends FunctionalTestCase { public class DynamicFilterTest extends FunctionalTestCase {
private Log log = LogFactory.getLog( DynamicFilterTest.class );
public DynamicFilterTest(String testName) { public DynamicFilterTest(String testName) {
super( testName ); super( testName );
} }
@ -79,6 +77,7 @@ public class DynamicFilterTest extends FunctionalTestCase {
testData.prepare(); testData.prepare();
Session session = openSession(); Session session = openSession();
long ts = ( ( SessionImplementor ) session ).getTimestamp();
// Force a collection into the second level cache, with its non-filtered elements // Force a collection into the second level cache, with its non-filtered elements
Salesperson sp = ( Salesperson ) session.load( Salesperson.class, testData.steveId ); Salesperson sp = ( Salesperson ) session.load( Salesperson.class, testData.steveId );
@ -93,6 +92,7 @@ public class DynamicFilterTest extends FunctionalTestCase {
session.close(); session.close();
session = openSession(); session = openSession();
ts = ( ( SessionImplementor ) session ).getTimestamp();
session.enableFilter( "fulfilledOrders" ).setParameter( "asOfDate", testData.lastMonth.getTime() ); session.enableFilter( "fulfilledOrders" ).setParameter( "asOfDate", testData.lastMonth.getTime() );
sp = ( Salesperson ) session.createQuery( "from Salesperson as s where s.id = :id" ) sp = ( Salesperson ) session.createQuery( "from Salesperson as s where s.id = :id" )
.setLong( "id", testData.steveId.longValue() ) .setLong( "id", testData.steveId.longValue() )
@ -152,7 +152,6 @@ public class DynamicFilterTest extends FunctionalTestCase {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HQL test // HQL test
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
log.info( "Starting HQL filter tests" );
TestData testData = new TestData(); TestData testData = new TestData();
testData.prepare(); testData.prepare();
@ -162,13 +161,11 @@ public class DynamicFilterTest extends FunctionalTestCase {
session.enableFilter( "effectiveDate" ) session.enableFilter( "effectiveDate" )
.setParameter( "asOfDate", testData.lastMonth.getTime() ); .setParameter( "asOfDate", testData.lastMonth.getTime() );
log.info( "HQL against Salesperson..." );
List results = session.createQuery( "select s from Salesperson as s left join fetch s.orders" ).list(); List results = session.createQuery( "select s from Salesperson as s left join fetch s.orders" ).list();
assertTrue( "Incorrect filtered HQL result count [" + results.size() + "]", results.size() == 1 ); assertTrue( "Incorrect filtered HQL result count [" + results.size() + "]", results.size() == 1 );
Salesperson result = ( Salesperson ) results.get( 0 ); Salesperson result = ( Salesperson ) results.get( 0 );
assertTrue( "Incorrect collectionfilter count", result.getOrders().size() == 1 ); assertTrue( "Incorrect collectionfilter count", result.getOrders().size() == 1 );
log.info( "HQL against Product..." );
results = session.createQuery( "from Product as p where p.stockNumber = ?" ).setInteger( 0, 124 ).list(); results = session.createQuery( "from Product as p where p.stockNumber = ?" ).setInteger( 0, 124 ).list();
assertTrue( results.size() == 1 ); assertTrue( results.size() == 1 );
@ -180,7 +177,6 @@ public class DynamicFilterTest extends FunctionalTestCase {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Criteria-query test // Criteria-query test
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
log.info( "Starting Criteria-query filter tests" );
TestData testData = new TestData(); TestData testData = new TestData();
testData.prepare(); testData.prepare();
@ -193,16 +189,14 @@ public class DynamicFilterTest extends FunctionalTestCase {
session.enableFilter( "effectiveDate" ) session.enableFilter( "effectiveDate" )
.setParameter( "asOfDate", testData.lastMonth.getTime() ); .setParameter( "asOfDate", testData.lastMonth.getTime() );
log.info( "Criteria query against Salesperson..." );
List salespersons = session.createCriteria( Salesperson.class ) List salespersons = session.createCriteria( Salesperson.class )
.setFetchMode( "orders", FetchMode.JOIN ) .setFetchMode( "orders", FetchMode.JOIN )
.list(); .list();
assertEquals( "Incorrect salesperson count", 1, salespersons.size() ); assertEquals( "Incorrect salesperson count", 1, salespersons.size() );
assertEquals( "Incorrect order count", 1, ( ( Salesperson ) salespersons.get( 0 ) ).getOrders().size() ); assertEquals( "Incorrect order count", 1, ( ( Salesperson ) salespersons.get( 0 ) ).getOrders().size() );
log.info( "Criteria query against Product..." );
List products = session.createCriteria( Product.class ) List products = session.createCriteria( Product.class )
.add( Expression.eq( "stockNumber", new Integer( 124 ) ) ) .add( Restrictions.eq( "stockNumber", new Integer( 124 ) ) )
.list(); .list();
assertEquals( "Incorrect product count", 1, products.size() ); assertEquals( "Incorrect product count", 1, products.size() );
@ -210,18 +204,292 @@ public class DynamicFilterTest extends FunctionalTestCase {
testData.release(); testData.release();
} }
public void testCriteriaControl() {
TestData testData = new TestData();
testData.prepare();
// the subquery...
DetachedCriteria subquery = DetachedCriteria.forClass( Salesperson.class )
.setProjection( Property.forName( "name" ) );
Session session = openSession();
session.beginTransaction();
session.enableFilter( "fulfilledOrders" ).setParameter( "asOfDate", testData.lastMonth.getTime() );
session.enableFilter( "regionlist" ).setParameterList( "regions", new String[] { "APAC" } );
List result = session.createCriteria( Order.class )
.add( Subqueries.in( "steve", subquery ) )
.list();
assertEquals( 1, result.size() );
session.getTransaction().commit();
session.close();
testData.release();
}
public void testCriteriaSubqueryWithFilters() {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Criteria-subquery test
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TestData testData = new TestData();
testData.prepare();
Session session = openSession();
session.enableFilter("region").setParameter("region", "APAC");
DetachedCriteria salespersonSubquery = DetachedCriteria.forClass(Salesperson.class)
.add(Restrictions.eq("name", "steve"))
.setProjection(Property.forName("department"));
Criteria departmentsQuery = session.createCriteria(Department.class).add(Subqueries.propertyIn("id", salespersonSubquery));
List departments = departmentsQuery.list();
assertEquals("Incorrect department count", 1, departments.size());
session.enableFilter("region").setParameter("region", "Foobar");
departments = departmentsQuery.list();
assertEquals("Incorrect department count", 0, departments.size());
session.enableFilter("region").setParameter("region", "APAC");
DetachedCriteria lineItemSubquery = DetachedCriteria.forClass(LineItem.class)
.add(Restrictions.ge("quantity", 1L))
.createCriteria("product")
.add(Restrictions.eq("name", "Acme Hair Gel"))
.setProjection(Property.forName("id"));
List orders = session.createCriteria(Order.class)
.add(Subqueries.exists(lineItemSubquery))
.add(Restrictions.eq("buyer", "gavin"))
.list();
assertEquals("Incorrect orders count", 1, orders.size());
session.enableFilter("region").setParameter("region", "APAC");
session.enableFilter("effectiveDate").setParameter("asOfDate", testData.lastMonth.getTime());
DetachedCriteria productSubquery = DetachedCriteria.forClass(Product.class)
.add(Restrictions.eq("name", "Acme Hair Gel"))
.setProjection(Property.forName("id"));
lineItemSubquery = DetachedCriteria.forClass(LineItem.class)
.add(Restrictions.ge("quantity", 1L))
.createCriteria("product")
.add(Subqueries.propertyIn("id", productSubquery))
.setProjection(Property.forName("id"));
orders = session.createCriteria(Order.class)
.add(Subqueries.exists(lineItemSubquery))
.add(Restrictions.eq("buyer", "gavin"))
.list();
assertEquals("Incorrect orders count", 1, orders.size());
session.enableFilter("region").setParameter("region", "APAC");
session.enableFilter("effectiveDate").setParameter("asOfDate", testData.fourMonthsAgo.getTime());
orders = session.createCriteria(Order.class)
.add(Subqueries.exists(lineItemSubquery))
.add(Restrictions.eq("buyer", "gavin"))
.list();
assertEquals("Incorrect orders count", 0, orders.size());
session.close();
testData.release();
}
public void testHQLSubqueryWithFilters() {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HQL subquery with filters test
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TestData testData = new TestData();
testData.prepare();
Session session = openSession();
session.enableFilter("region").setParameter("region", "APAC");
List departments = session.createQuery("select d from Department as d where d.id in (select s.department from Salesperson s where s.name = ?)").setString(0, "steve").list();
assertEquals("Incorrect department count", 1, departments.size());
session.enableFilter("region").setParameter("region", "Foobar");
departments = session.createQuery("select d from Department as d where d.id in (select s.department from Salesperson s where s.name = ?)").setString(0, "steve").list();
assertEquals("Incorrect department count", 0, departments.size());
session.enableFilter("region").setParameter("region", "APAC");
List orders = session.createQuery("select o from Order as o where exists (select li.id from LineItem li, Product as p where p.id = li.product and li.quantity >= ? and p.name = ?) and o.buyer = ?")
.setLong(0, 1L).setString(1, "Acme Hair Gel").setString(2, "gavin").list();
assertEquals("Incorrect orders count", 1, orders.size());
session.enableFilter("region").setParameter("region", "APAC");
session.enableFilter("effectiveDate").setParameter("asOfDate", testData.lastMonth.getTime());
orders = session.createQuery("select o from Order as o where exists (select li.id from LineItem li where li.quantity >= ? and li.product in (select p.id from Product p where p.name = ?)) and o.buyer = ?")
.setLong(0, 1L).setString(1, "Acme Hair Gel").setString(2, "gavin").list();
assertEquals("Incorrect orders count", 1, orders.size());
session.enableFilter("region").setParameter("region", "APAC");
session.enableFilter("effectiveDate").setParameter("asOfDate", testData.fourMonthsAgo.getTime());
orders = session.createQuery("select o from Order as o where exists (select li.id from LineItem li where li.quantity >= ? and li.product in (select p.id from Product p where p.name = ?)) and o.buyer = ?")
.setLong(0, 1L).setString(1, "Acme Hair Gel").setString(2, "gavin").list();
assertEquals("Incorrect orders count", 0, orders.size());
session.enableFilter("region").setParameter("region", "APAC");
session.enableFilter("effectiveDate").setParameter("asOfDate", testData.lastMonth.getTime());
orders = session.createQuery("select o from Order as o where exists (select li.id from LineItem li where li.quantity >= :quantity and li.product in (select p.id from Product p where p.name = :name)) and o.buyer = :buyer")
.setLong("quantity", 1L).setString("name", "Acme Hair Gel").setString("buyer", "gavin").list();
assertEquals("Incorrect orders count", 1, orders.size());
session.enableFilter("region").setParameter("region", "APAC");
session.enableFilter("effectiveDate").setParameter("asOfDate", testData.lastMonth.getTime());
orders = session.createQuery("select o from Order as o where exists (select li.id from LineItem li where li.quantity >= ? and li.product in (select p.id from Product p where p.name = ?)) and o.buyer = :buyer")
.setLong(0, 1L).setString(1, "Acme Hair Gel").setString("buyer", "gavin").list();
assertEquals("Incorrect orders count", 1, orders.size());
session.close();
testData.release();
}
public void testFilterApplicationOnHqlQueryWithImplicitSubqueryContainingPositionalParameter() {
TestData testData = new TestData();
testData.prepare();
Session session = openSession();
session.beginTransaction();
final String queryString = "from Order o where ? in ( select sp.name from Salesperson sp )";
// first a control-group query
List result = session.createQuery( queryString ).setParameter( 0, "steve" ).list();
assertEquals( 2, result.size() );
// now lets enable filters on Order...
session.enableFilter( "fulfilledOrders" ).setParameter( "asOfDate", testData.lastMonth.getTime() );
result = session.createQuery( queryString ).setParameter( 0, "steve" ).list();
assertEquals( 1, result.size() );
// now, lets additionally enable filter on Salesperson. First a valid one...
session.enableFilter( "regionlist" ).setParameterList( "regions", new String[] { "APAC" } );
result = session.createQuery( queryString ).setParameter( 0, "steve" ).list();
assertEquals( 1, result.size() );
// ... then a silly one...
session.enableFilter( "regionlist" ).setParameterList( "regions", new String[] { "gamma quadrant" } );
result = session.createQuery( queryString ).setParameter( 0, "steve" ).list();
assertEquals( 0, result.size() );
session.getTransaction().commit();
session.close();
testData.release();
}
public void testFilterApplicationOnHqlQueryWithImplicitSubqueryContainingNamedParameter() {
TestData testData = new TestData();
testData.prepare();
Session session = openSession();
session.beginTransaction();
final String queryString = "from Order o where :salesPersonName in ( select sp.name from Salesperson sp )";
// first a control-group query
List result = session.createQuery( queryString ).setParameter( "salesPersonName", "steve" ).list();
assertEquals( 2, result.size() );
// now lets enable filters on Order...
session.enableFilter( "fulfilledOrders" ).setParameter( "asOfDate", testData.lastMonth.getTime() );
result = session.createQuery( queryString ).setParameter( "salesPersonName", "steve" ).list();
assertEquals( 1, result.size() );
// now, lets additionally enable filter on Salesperson. First a valid one...
session.enableFilter( "regionlist" ).setParameterList( "regions", new String[] { "APAC" } );
result = session.createQuery( queryString ).setParameter( "salesPersonName", "steve" ).list();
assertEquals( 1, result.size() );
// ... then a silly one...
session.enableFilter( "regionlist" ).setParameterList( "regions", new String[] { "gamma quadrant" } );
result = session.createQuery( queryString ).setParameter( "salesPersonName", "steve" ).list();
assertEquals( 0, result.size() );
session.getTransaction().commit();
session.close();
testData.release();
}
public void testFiltersOnSimpleHqlDelete() {
Session session = openSession();
session.beginTransaction();
Salesperson sp = new Salesperson();
sp.setName( "steve" );
sp.setRegion( "NA" );
session.persist( sp );
Salesperson sp2 = new Salesperson();
sp2.setName( "john" );
sp2.setRegion( "APAC" );
session.persist( sp2 );
session.getTransaction().commit();
session.close();
session = openSession();
session.beginTransaction();
session.enableFilter( "region" ).setParameter( "region", "NA" );
int count = session.createQuery( "delete from Salesperson" ).executeUpdate();
assertEquals( 1, count );
session.delete( sp2 );
session.getTransaction().commit();
session.close();
}
public void testFiltersOnMultiTableHqlDelete() {
Session session = openSession();
session.beginTransaction();
Salesperson sp = new Salesperson();
sp.setName( "steve" );
sp.setRegion( "NA" );
session.persist( sp );
Salesperson sp2 = new Salesperson();
sp2.setName( "john" );
sp2.setRegion( "APAC" );
session.persist( sp2 );
session.getTransaction().commit();
session.close();
session = openSession();
session.beginTransaction();
session.enableFilter( "region" ).setParameter( "region", "NA" );
int count = session.createQuery( "delete from Salesperson" ).executeUpdate();
assertEquals( 1, count );
session.delete( sp2 );
session.getTransaction().commit();
session.close();
}
public void testGetFilters() { public void testGetFilters() {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Get() test // Get() test
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
log.info( "Starting get() filter tests (eager assoc. fetching)." );
TestData testData = new TestData(); TestData testData = new TestData();
testData.prepare(); testData.prepare();
Session session = openSession(); Session session = openSession();
session.enableFilter( "region" ).setParameter( "region", "APAC" ); session.enableFilter( "region" ).setParameter( "region", "APAC" );
log.info( "Performing get()..." );
Salesperson salesperson = ( Salesperson ) session.get( Salesperson.class, testData.steveId ); Salesperson salesperson = ( Salesperson ) session.get( Salesperson.class, testData.steveId );
assertNotNull( salesperson ); assertNotNull( salesperson );
assertEquals( "Incorrect order count", 1, salesperson.getOrders().size() ); assertEquals( "Incorrect order count", 1, salesperson.getOrders().size() );
@ -234,7 +502,6 @@ public class DynamicFilterTest extends FunctionalTestCase {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// one-to-many loading tests // one-to-many loading tests
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
log.info( "Starting one-to-many collection loader filter tests." );
TestData testData = new TestData(); TestData testData = new TestData();
testData.prepare(); testData.prepare();
@ -242,7 +509,6 @@ public class DynamicFilterTest extends FunctionalTestCase {
session.enableFilter( "seniorSalespersons" ) session.enableFilter( "seniorSalespersons" )
.setParameter( "asOfDate", testData.lastMonth.getTime() ); .setParameter( "asOfDate", testData.lastMonth.getTime() );
log.info( "Performing load of Department..." );
Department department = ( Department ) session.load( Department.class, testData.deptId ); Department department = ( Department ) session.load( Department.class, testData.deptId );
Set salespersons = department.getSalespersons(); Set salespersons = department.getSalespersons();
assertEquals( "Incorrect salesperson count", 1, salespersons.size() ); assertEquals( "Incorrect salesperson count", 1, salespersons.size() );
@ -255,7 +521,6 @@ public class DynamicFilterTest extends FunctionalTestCase {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// one-to-many loading tests // one-to-many loading tests
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
log.info( "Starting one-to-many collection loader filter tests." );
TestData testData = new TestData(); TestData testData = new TestData();
testData.prepare(); testData.prepare();
@ -263,7 +528,6 @@ public class DynamicFilterTest extends FunctionalTestCase {
session.enableFilter( "regionlist" ) session.enableFilter( "regionlist" )
.setParameterList( "regions", new String[]{"LA", "APAC"} ); .setParameterList( "regions", new String[]{"LA", "APAC"} );
log.debug( "Performing query of Salespersons" );
List salespersons = session.createQuery( "from Salesperson" ).list(); List salespersons = session.createQuery( "from Salesperson" ).list();
assertEquals( "Incorrect salesperson count", 1, salespersons.size() ); assertEquals( "Incorrect salesperson count", 1, salespersons.size() );
@ -280,7 +544,7 @@ public class DynamicFilterTest extends FunctionalTestCase {
Product prod = ( Product ) session.createCriteria( Product.class ) Product prod = ( Product ) session.createCriteria( Product.class )
.setResultTransformer( new DistinctRootEntityResultTransformer() ) .setResultTransformer( new DistinctRootEntityResultTransformer() )
.add( Expression.eq( "id", testData.prod1Id ) ) .add( Restrictions.eq( "id", testData.prod1Id ) )
.uniqueResult(); .uniqueResult();
assertNotNull( prod ); assertNotNull( prod );
@ -420,7 +684,7 @@ public class DynamicFilterTest extends FunctionalTestCase {
Session session = openSession(); Session session = openSession();
List result = session.createCriteria( Product.class ) List result = session.createCriteria( Product.class )
.add( Expression.eq( "id", testData.prod1Id ) ) .add( Restrictions.eq( "id", testData.prod1Id ) )
.list(); .list();
Product prod = ( Product ) result.get( 0 ); Product prod = ( Product ) result.get( 0 );

View File

@ -0,0 +1,40 @@
<?xml version="1.0"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Middleware LLC.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
~
-->
<!DOCTYPE hibernate-mapping
SYSTEM
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="org.hibernate.test.filter.hql">
<class name="Person" table="FILTER_HQL_PERSON">
<id column="ID" name="id" type="long">
<generator class="increment"/>
</id>
<property name="name" type="string"/>
<property name="sex" column="SEX_CODE" type="char"/>
<filter name="sex"/>
</class>
</hibernate-mapping>

View File

@ -0,0 +1,93 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.test.filter.hql;
import org.hibernate.junit.functional.FunctionalTestCase;
import org.hibernate.Session;
/**
* Tests for application of filters
*
* @author Steve Ebersole
*/
public class BasicFilteredBulkManipulationTest extends FunctionalTestCase {
public BasicFilteredBulkManipulationTest(String string) {
super( string );
}
public String[] getMappings() {
return new String[]{
"filter/hql/filter-defs.hbm.xml",
"filter/hql/Basic.hbm.xml"
};
}
public void testBasicFilteredHqlDelete() {
Session s = openSession();
s.beginTransaction();
s.save( new Person( "Steve", 'M' ) );
s.save( new Person( "Emmanuel", 'M' ) );
s.save( new Person( "Gail", 'F' ) );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.enableFilter( "sex" ).setParameter( "sexCode", new Character( 'M' ) );
int count = s.createQuery( "delete Person" ).executeUpdate();
assertEquals( 2, count );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.createQuery( "delete Person" ).executeUpdate();
s.getTransaction().commit();
s.close();
}
public void testBasicFilteredHqlUpdate() {
Session s = openSession();
s.beginTransaction();
s.save( new Person( "Shawn", 'M' ) );
s.save( new Person( "Sally", 'F' ) );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.enableFilter( "sex" ).setParameter( "sexCode", new Character( 'M' ) );
int count = s.createQuery( "update Person p set p.name = 'Shawn'" ).executeUpdate();
assertEquals( 1, count );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.createQuery( "delete Person" ).executeUpdate();
s.getTransaction().commit();
s.close();
}
}

View File

@ -0,0 +1,51 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.test.filter.hql;
/**
* Leaf subclass
*
* @author Steve Ebersole
*/
public class Customer extends User {
private String company;
protected Customer() {
super();
}
public Customer(String name, char sex, String username, String company) {
super( name, sex, username );
this.company = company;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
}

View File

@ -0,0 +1,53 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.test.filter.hql;
import java.util.Date;
/**
* Leaf subclass
*
* @author Steve Ebersole
*/
public class Employee extends User {
private Date hireDate;
protected Employee() {
super();
}
public Employee(String name, char sex, String username, Date hireDate) {
super( name, sex, username );
this.hireDate = hireDate;
}
public Date getHireDate() {
return hireDate;
}
public void setHireDate(Date hireDate) {
this.hireDate = hireDate;
}
}

View File

@ -0,0 +1,52 @@
<?xml version="1.0"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Middleware LLC.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
~
-->
<!DOCTYPE hibernate-mapping
SYSTEM
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="org.hibernate.test.filter.hql">
<class name="Person" table="FILTER_HQL_JOINED_PERSON">
<id column="ID" name="id" type="long">
<generator class="increment"/>
</id>
<property name="name" type="string"/>
<property name="sex" column="SEX_CODE" type="char"/>
<joined-subclass name="User" table="FILTER_HQL_JOINED_USER">
<key column="USER_ID"/>
<property name="username" type="string"/>
<joined-subclass name="Employee" table="FILTER_HQL_JOINED_EMP">
<key column="EMP_ID"/>
<property name="hireDate" type="date"/>
</joined-subclass>
<joined-subclass name="Customer" table="FILTER_HQL_JOINED_CUST">
<key column="CUST_ID"/>
<property name="company" type="string"/>
</joined-subclass>
</joined-subclass>
<filter name="sex"/>
</class>
</hibernate-mapping>

View File

@ -0,0 +1,201 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.test.filter.hql;
import java.util.Date;
import org.hibernate.junit.functional.FunctionalTestCase;
import org.hibernate.Session;
/**
* TODO : javadoc
*
* @author Steve Ebersole
*/
public class JoinedFilteredBulkManipulationTest extends FunctionalTestCase {
public JoinedFilteredBulkManipulationTest(String string) {
super( string );
}
public String[] getMappings() {
return new String[]{
"filter/hql/filter-defs.hbm.xml",
"filter/hql/Joined.hbm.xml"
};
}
public void testFilteredJoinedSubclassHqlDeleteRoot() {
Session s = openSession();
s.beginTransaction();
s.save( new Employee( "John", 'M', "john", new Date() ) );
s.save( new Employee( "Jane", 'F', "jane", new Date() ) );
s.save( new Customer( "Charlie", 'M', "charlie", "Acme" ) );
s.save( new Customer( "Wanda", 'F', "wanda", "ABC" ) );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.enableFilter( "sex" ).setParameter( "sexCode", new Character('M' ) );
int count = s.createQuery( "delete Person" ).executeUpdate();
assertEquals( 2, count );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.createQuery( "delete Person" ).executeUpdate();
s.getTransaction().commit();
s.close();
}
public void testFilteredJoinedSubclassHqlDeleteNonLeaf() {
Session s = openSession();
s.beginTransaction();
s.save( new Employee( "John", 'M', "john", new Date() ) );
s.save( new Employee( "Jane", 'F', "jane", new Date() ) );
s.save( new Customer( "Charlie", 'M', "charlie", "Acme" ) );
s.save( new Customer( "Wanda", 'F', "wanda", "ABC" ) );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.enableFilter( "sex" ).setParameter( "sexCode", new Character('M' ) );
int count = s.createQuery( "delete User" ).executeUpdate();
assertEquals( 2, count );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.createQuery( "delete Person" ).executeUpdate();
s.getTransaction().commit();
s.close();
}
public void testFilteredJoinedSubclassHqlDeleteLeaf() {
Session s = openSession();
s.beginTransaction();
s.save( new Employee( "John", 'M', "john", new Date() ) );
s.save( new Employee( "Jane", 'F', "jane", new Date() ) );
s.save( new Customer( "Charlie", 'M', "charlie", "Acme" ) );
s.save( new Customer( "Wanda", 'F', "wanda", "ABC" ) );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.enableFilter( "sex" ).setParameter( "sexCode", new Character('M' ) );
int count = s.createQuery( "delete Employee" ).executeUpdate();
assertEquals( 1, count );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.createQuery( "delete Person" ).executeUpdate();
s.getTransaction().commit();
s.close();
}
public void testFilteredJoinedSubclassHqlUpdateRoot() {
Session s = openSession();
s.beginTransaction();
s.save( new Employee( "John", 'M', "john", new Date() ) );
s.save( new Employee( "Jane", 'F', "jane", new Date() ) );
s.save( new Customer( "Charlie", 'M', "charlie", "Acme" ) );
s.save( new Customer( "Wanda", 'F', "wanda", "ABC" ) );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.enableFilter( "sex" ).setParameter( "sexCode", new Character('M' ) );
int count = s.createQuery( "update Person p set p.name = '<male>'" ).executeUpdate();
assertEquals( 2, count );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.createQuery( "delete Person" ).executeUpdate();
s.getTransaction().commit();
s.close();
}
public void testFilteredJoinedSubclassHqlUpdateNonLeaf() {
Session s = openSession();
s.beginTransaction();
s.save( new Employee( "John", 'M', "john", new Date() ) );
s.save( new Employee( "Jane", 'F', "jane", new Date() ) );
s.save( new Customer( "Charlie", 'M', "charlie", "Acme" ) );
s.save( new Customer( "Wanda", 'F', "wanda", "ABC" ) );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.enableFilter( "sex" ).setParameter( "sexCode", new Character('M' ) );
int count = s.createQuery( "update User u set u.username = :un where u.name = :n" )
.setString( "un", "charlie" )
.setString( "n", "Wanda" )
.executeUpdate();
assertEquals( 0, count );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.createQuery( "delete Person" ).executeUpdate();
s.getTransaction().commit();
s.close();
}
public void testFilteredJoinedSubclassHqlUpdateLeaf() {
Session s = openSession();
s.beginTransaction();
s.save( new Employee( "John", 'M', "john", new Date() ) );
s.save( new Employee( "Jane", 'F', "jane", new Date() ) );
s.save( new Customer( "Charlie", 'M', "charlie", "Acme" ) );
s.save( new Customer( "Wanda", 'F', "wanda", "ABC" ) );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.enableFilter( "sex" ).setParameter( "sexCode", new Character('M' ) );
int count = s.createQuery( "update Customer c set c.company = 'XYZ'" ).executeUpdate();
assertEquals( 1, count );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.createQuery( "delete Person" ).executeUpdate();
s.getTransaction().commit();
s.close();
}
}

View File

@ -0,0 +1,71 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.test.filter.hql;
/**
* Base of inheritence hierarchy
*
* @author Steve Ebersole
*/
public class Person {
private Long id;
private String name;
private char sex;
/**
* Used by persistence
*/
protected Person() {
}
public Person(String name, char sex) {
this.name = name;
this.sex = sex;
}
public Long getId() {
return id;
}
private void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
}

View File

@ -0,0 +1,51 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.test.filter.hql;
/**
* Non-leaf subclass
*
* @author Steve Ebersole
*/
public class User extends Person {
private String username;
protected User() {
super();
}
public User(String name, char sex, String username) {
super( name, sex );
this.username = username;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}

View File

@ -0,0 +1,35 @@
<?xml version="1.0"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Middleware LLC.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
~
-->
<!DOCTYPE hibernate-mapping
SYSTEM
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="org.hibernate.test.filter.hql">
<filter-def name="sex" condition="SEX_CODE = :sexCode">
<filter-param name="sexCode" type="char"/>
</filter-def>
</hibernate-mapping>