HHH-530 : filters + subqueries;

HHH-3506 : filters + HQL update/delete

git-svn-id: https://svn.jboss.org/repos/hibernate/core/branches/Branch_3_3@15241 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Steve Ebersole 2008-10-01 19:42:55 +00:00
parent 542c0a966a
commit 8c40442282
37 changed files with 1686 additions and 280 deletions

View File

@ -24,14 +24,13 @@
*/ */
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;
@ -53,49 +52,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];
@ -106,12 +123,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

@ -393,4 +393,9 @@ public class DB2Dialect extends Dialect {
public boolean supportsLobValueChangePropogation() { public boolean supportsLobValueChangePropogation() {
return false; return false;
} }
public boolean doesReadCommittedCauseWritersToBlockReaders() {
return true;
}
} }

View File

@ -26,7 +26,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;
@ -39,6 +38,7 @@ import org.slf4j.LoggerFactory;
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;
@ -50,7 +50,7 @@ import org.hibernate.util.ArrayHelper;
* @author Gavin King * @author Gavin King
*/ */
public final class QueryParameters { public final class QueryParameters {
private static final Logger log = LoggerFactory.getLogger(QueryParameters.class); private static final Logger log = LoggerFactory.getLogger( QueryParameters.class );
private Type[] positionalParameterTypes; private Type[] positionalParameterTypes;
private Object[] positionalParameterValues; private Object[] positionalParameterValues;
@ -69,29 +69,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;
@ -99,42 +98,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,
@ -142,37 +123,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;
} }
@ -189,8 +169,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;
@ -204,36 +183,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;
@ -241,7 +219,7 @@ public final class QueryParameters {
} }
public boolean hasRowSelection() { public boolean hasRowSelection() {
return rowSelection!=null; return rowSelection != null;
} }
public Map getNamedParameters() { public Map getNamedParameters() {
@ -259,7 +237,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;
} }
@ -289,15 +267,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 ) );
} }
} }
@ -318,13 +296,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
); );
} }
} }
@ -385,44 +363,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() ) {
@ -442,15 +425,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();
} }
} }
@ -481,16 +466,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
@ -501,5 +486,14 @@ 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

@ -231,6 +231,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;
} }
@ -553,8 +557,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();
@ -592,13 +596,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

@ -97,6 +97,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.
@ -240,6 +242,7 @@ public class QueryTranslatorImpl implements FilterTranslator {
log.debug( "SQL: " + sql ); log.debug( "SQL: " + sql );
} }
gen.getParseErrorHandler().throwQueryException(); gen.getParseErrorHandler().throwQueryException();
collectedParameterSpecifications = gen.getCollectedParameters();
} }
} }
@ -563,10 +566,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

@ -27,16 +27,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
@ -64,6 +68,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 );
} }
@ -75,6 +85,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

@ -27,6 +27,9 @@ 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.List;
import java.util.Iterator;
import java.util.Collections;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.action.BulkOperationCleanupAction; import org.hibernate.action.BulkOperationCleanupAction;
@ -42,6 +45,7 @@ import org.hibernate.sql.InsertSelect;
import org.hibernate.sql.Select; import org.hibernate.sql.Select;
import org.hibernate.sql.SelectFragment; import org.hibernate.sql.SelectFragment;
import org.hibernate.util.StringHelper; import org.hibernate.util.StringHelper;
import org.hibernate.util.EmptyIterator;
import antlr.RecognitionException; import antlr.RecognitionException;
import antlr.collections.AST; import antlr.collections.AST;
@ -57,6 +61,7 @@ public abstract class AbstractStatementExecutor implements StatementExecutor {
private final Logger log; private final Logger log;
private final HqlSqlWalker walker; private final HqlSqlWalker walker;
private List idSelectParameterSpecifications = Collections.EMPTY_LIST;
public AbstractStatementExecutor(HqlSqlWalker walker, Logger log) { public AbstractStatementExecutor(HqlSqlWalker walker, Logger log) {
this.walker = walker; this.walker = walker;
@ -71,6 +76,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) {
@ -103,6 +112,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

@ -27,6 +27,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;
@ -54,6 +55,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 );
@ -63,6 +65,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 );
@ -83,10 +86,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

@ -107,7 +107,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

@ -132,7 +132,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

@ -26,8 +26,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;
@ -57,7 +59,7 @@ import org.slf4j.LoggerFactory;
* *
* @author josh * @author josh
*/ */
public class FromElement extends HqlSqlWalkerNode implements DisplayableNode { public class FromElement extends HqlSqlWalkerNode implements DisplayableNode, ParameterContainer {
private static final Logger log = LoggerFactory.getLogger( FromElement.class ); private static final Logger log = LoggerFactory.getLogger( FromElement.class );
private String className; private String className;
@ -569,4 +571,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

@ -24,14 +24,18 @@
*/ */
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 * @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;
@ -50,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

@ -27,21 +27,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.dialect.Dialect;
import org.hibernate.impl.FilterImpl;
import org.hibernate.type.Type;
import org.hibernate.param.DynamicFilterParameterSpecification;
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.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -57,18 +64,17 @@ public class JoinProcessor implements SqlTokenTypes {
private static final Logger log = LoggerFactory.getLogger( JoinProcessor.class ); private static final Logger log = LoggerFactory.getLogger( 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 );
} }
/** /**
@ -92,7 +98,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;
@ -131,22 +137,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()
@ -166,13 +171,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) {
@ -184,4 +200,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

@ -31,9 +31,14 @@ 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.engine.SessionFactoryImplementor;
import org.hibernate.type.Type;
import org.hibernate.param.CollectionFilterKeyParameterSpecification;
import antlr.ASTFactory; import antlr.ASTFactory;
import antlr.collections.AST; import antlr.collections.AST;
@ -49,27 +54,36 @@ import org.slf4j.LoggerFactory;
public class SyntheticAndFactory implements HqlSqlTokenTypes { public class SyntheticAndFactory implements HqlSqlTokenTypes {
private static final Logger log = LoggerFactory.getLogger( SyntheticAndFactory.class ); private static final Logger log = LoggerFactory.getLogger( 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
@ -77,12 +91,34 @@ public class SyntheticAndFactory implements HqlSqlTokenTypes {
whereFragment = whereFragment.substring( 4 ); whereFragment = whereFragment.substring( 4 );
} }
if ( log.isDebugEnabled() ) log.debug( "Using WHERE fragment [" + whereFragment + "]" ); 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().
@ -91,7 +127,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 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 );
} }
@ -104,7 +140,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 );
@ -120,7 +156,11 @@ public class SyntheticAndFactory implements HqlSqlTokenTypes {
} }
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;
@ -140,13 +180,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

@ -506,8 +506,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

@ -32,28 +32,45 @@ import org.hibernate.type.Type;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public abstract class AbstractExplicitParameterSpecification implements ExplicitParameterSpecification { public abstract class AbstractExplicitParameterSpecification implements ExplicitParameterSpecification {
private final int sourceLine; private final int sourceLine;
private final int sourceColumn; private final int sourceColumn;
private Type expectedType; private Type expectedType;
/**
* Constructs an AbstractExplicitParameterSpecification.
*
* @param sourceLine See {@link #getSourceLine()}
* @param sourceColumn See {@link #getSourceColumn()}
*/
protected AbstractExplicitParameterSpecification(int sourceLine, int sourceColumn) { protected AbstractExplicitParameterSpecification(int sourceLine, int sourceColumn) {
this.sourceLine = sourceLine; this.sourceLine = sourceLine;
this.sourceColumn = sourceColumn; this.sourceColumn = sourceColumn;
} }
/**
* {@inheritDoc}
*/
public int getSourceLine() { public int getSourceLine() {
return sourceLine; return sourceLine;
} }
/**
* {@inheritDoc}
*/
public int getSourceColumn() { public int getSourceColumn() {
return sourceColumn; return sourceColumn;
} }
/**
* {@inheritDoc}
*/
public Type getExpectedType() { public Type getExpectedType() {
return expectedType; return expectedType;
} }
/**
* {@inheritDoc}
*/
public void setExpectedType(Type expectedType) { public void setExpectedType(Type expectedType) {
this.expectedType = expectedType; this.expectedType = expectedType;
} }

View File

@ -32,13 +32,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;
@ -57,6 +56,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,
@ -67,14 +69,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

@ -26,20 +26,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
*/ */
@ -47,37 +44,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

@ -25,13 +25,23 @@
package org.hibernate.param; package org.hibernate.param;
/** /**
* An additional contract for parameters which originate from * An additional contract for parameters which originate from parameters explicitly encountered in the source statement
* parameters explicitly encountered in the source statement
* (HQL or native-SQL). * (HQL or native-SQL).
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface ExplicitParameterSpecification extends ParameterSpecification { public interface ExplicitParameterSpecification extends ParameterSpecification {
/**
* Retrieves the line number on which this parameter occurs in the source query.
*
* @return The line number.
*/
public int getSourceLine(); public int getSourceLine();
/**
* Retrieves the column number (within the {@link #getSourceLine()}) where this parameter occurs.
*
* @return The column number.
*/
public int getSourceColumn(); public int getSourceColumn();
} }

View File

@ -32,14 +32,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;
@ -62,10 +68,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

@ -32,14 +32,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;
@ -63,10 +69,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

@ -33,20 +33,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 {
@ -54,14 +58,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

@ -18,13 +18,17 @@ 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.Criteria;
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.Restrictions; import org.hibernate.criterion.Restrictions;
import org.hibernate.engine.SessionImplementor; 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.FunctionalTestCase;
import org.hibernate.junit.functional.FunctionalTestClassTestSuite; import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
@ -210,6 +214,305 @@ 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
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
log.info("Starting Criteria-subquery filter tests");
TestData testData = new TestData();
testData.prepare();
Session session = openSession();
session.enableFilter("region").setParameter("region", "APAC");
log.info("Criteria query against Department with a subquery on Salesperson in the APAC reqion...");
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());
log.info("Criteria query against Department with a subquery on Salesperson in the FooBar reqion...");
session.enableFilter("region").setParameter("region", "Foobar");
departments = departmentsQuery.list();
assertEquals("Incorrect department count", 0, departments.size());
log.info("Criteria query against Order with a subquery for line items with a subquery on product and sold by a given sales person...");
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());
log.info("query against Order with a subquery for line items with a subquery line items where the product name is Acme Hair Gel and the quantity is greater than 1 in a given region and the product is effective as of last month");
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());
log.info("query against Order with a subquery for line items with a subquery line items where the product name is Acme Hair Gel and the quantity is greater than 1 in a given region and the product is effective as of 4 months ago");
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
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
log.info("Starting HQL subquery with filters tests");
TestData testData = new TestData();
testData.prepare();
Session session = openSession();
session.enableFilter("region").setParameter("region", "APAC");
log.info("query against Department with a subquery on Salesperson in the APAC reqion...");
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());
log.info("query against Department with a subquery on Salesperson in the FooBar reqion...");
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());
log.info("query against Order with a subquery for line items with a subquery line items where the product name is Acme Hair Gel and the quantity is greater than 1 in a given region for a given buyer");
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());
log.info("query against Order with a subquery for line items with a subquery line items where the product name is Acme Hair Gel and the quantity is greater than 1 in a given region and the product is effective as of last month");
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());
log.info("query against Order with a subquery for line items with a subquery line items where the product name is Acme Hair Gel and the quantity is greater than 1 in a given region and the product is effective as of 4 months ago");
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());
log.info("query against Order with a subquery for line items with a subquery line items where the product name is Acme Hair Gel and the quantity is greater than 1 in a given region and the product is effective as of last month with named types");
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());
log.info("query against Order with a subquery for line items with a subquery line items where the product name is Acme Hair Gel and the quantity is greater than 1 in a given region and the product is effective as of last month with mixed types");
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

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>

View File

@ -126,7 +126,13 @@ public class ASTParserLoadingTest extends FunctionalTestCase {
assertEquals( 1, results.size() ); assertEquals( 1, results.size() );
results = s.createQuery( "from Human where name is not null" ).list(); results = s.createQuery( "from Human where name is not null" ).list();
assertEquals( 3, results.size() ); assertEquals( 3, results.size() );
s.createQuery( "from Human where ? is null" ).setParameter( 0, null ).list(); String query =
getDialect() instanceof DB2Dialect ?
"from Human where cast(? as string) is null" :
"from Human where ? is null"
;
s.createQuery( query ).setParameter( 0, null ).list();
s.getTransaction().commit(); s.getTransaction().commit();
s.close(); s.close();
@ -203,13 +209,29 @@ public class ASTParserLoadingTest extends FunctionalTestCase {
s.beginTransaction(); s.beginTransaction();
s.createQuery( "from Animal a where abs(a.bodyWeight-:param) < 2.0" ).setLong( "param", 1 ).list(); s.createQuery( "from Animal a where abs(a.bodyWeight-:param) < 2.0" ).setLong( "param", 1 ).list();
s.createQuery( "from Animal a where abs(:param - a.bodyWeight) < 2.0" ).setLong( "param", 1 ).list(); s.createQuery( "from Animal a where abs(:param - a.bodyWeight) < 2.0" ).setLong( "param", 1 ).list();
if ( ! ( getDialect() instanceof HSQLDialect ) ) { if ( ( getDialect() instanceof HSQLDialect ) || ( getDialect() instanceof DB2Dialect ) ) {
// HSQLDB does not like the abs(? - ?) syntax... // HSQLDB and DB2 don't like the abs(? - ?) syntax. bit work if at least one parameter is typed...
s.createQuery( "from Animal where abs(cast(:x as long) - :y) < 2.0" ).setLong( "x", 1 ).setLong( "y", 1 ).list();
s.createQuery( "from Animal where abs(:x - cast(:y as long)) < 2.0" ).setLong( "x", 1 ).setLong( "y", 1 ).list();
s.createQuery( "from Animal where abs(cast(:x as long) - cast(:y as long)) < 2.0" ).setLong( "x", 1 ).setLong( "y", 1 ).list();
}
else {
s.createQuery( "from Animal where abs(:x - :y) < 2.0" ).setLong( "x", 1 ).setLong( "y", 1 ).list(); s.createQuery( "from Animal where abs(:x - :y) < 2.0" ).setLong( "x", 1 ).setLong( "y", 1 ).list();
} }
s.createQuery( "from Animal where lower(upper(:foo)) like 'f%'" ).setString( "foo", "foo" ).list();
if ( getDialect() instanceof DB2Dialect ) {
s.createQuery( "from Animal where lower(upper(cast(:foo as string))) like 'f%'" ).setString( "foo", "foo" ).list();
}
else {
s.createQuery( "from Animal where lower(upper(:foo)) like 'f%'" ).setString( "foo", "foo" ).list();
}
s.createQuery( "from Animal a where abs(abs(a.bodyWeight - 1.0 + :param) * abs(length('ffobar')-3)) = 3.0" ).setLong( "param", 1 ).list(); s.createQuery( "from Animal a where abs(abs(a.bodyWeight - 1.0 + :param) * abs(length('ffobar')-3)) = 3.0" ).setLong( "param", 1 ).list();
s.createQuery( "from Animal where lower(upper('foo') || upper(:bar)) like 'f%'" ).setString( "bar", "xyz" ).list(); if ( getDialect() instanceof DB2Dialect ) {
s.createQuery( "from Animal where lower(upper('foo') || upper(cast(:bar as string))) like 'f%'" ).setString( "bar", "xyz" ).list();
}
else {
s.createQuery( "from Animal where lower(upper('foo') || upper(:bar)) like 'f%'" ).setString( "bar", "xyz" ).list();
}
if ( ! ( getDialect() instanceof PostgreSQLDialect || getDialect() instanceof MySQLDialect ) ) { if ( ! ( getDialect() instanceof PostgreSQLDialect || getDialect() instanceof MySQLDialect ) ) {
s.createQuery( "from Animal where abs(cast(1 as float) - cast(:param as float)) = 1.0" ).setLong( "param", 1 ).list(); s.createQuery( "from Animal where abs(cast(1 as float) - cast(:param as float)) = 1.0" ).setLong( "param", 1 ).list();
} }

View File

@ -31,7 +31,7 @@ public class InstrumentTest extends UnitTestCase {
return new TestSuite( InstrumentTest.class ); return new TestSuite( InstrumentTest.class );
} }
public void testDirtyCheck() { public void testDirtyCheck() throws Exception {
execute( new TestDirtyCheckExecutable() ); execute( new TestDirtyCheckExecutable() );
} }
@ -43,31 +43,31 @@ public class InstrumentTest extends UnitTestCase {
execute( new TestLazyExecutable() ); execute( new TestLazyExecutable() );
} }
public void testLazyManyToOne() { public void testLazyManyToOne() throws Exception {
execute( new TestLazyManyToOneExecutable() ); execute( new TestLazyManyToOneExecutable() );
} }
public void testSetFieldInterceptor() { public void testSetFieldInterceptor() throws Exception {
execute( new TestInjectFieldInterceptorExecutable() ); execute( new TestInjectFieldInterceptorExecutable() );
} }
public void testPropertyInitialized() { public void testPropertyInitialized() throws Exception {
execute( new TestIsPropertyInitializedExecutable() ); execute( new TestIsPropertyInitializedExecutable() );
} }
public void testManyToOneProxy() { public void testManyToOneProxy() throws Exception {
execute( new TestManyToOneProxyExecutable() ); execute( new TestManyToOneProxyExecutable() );
} }
public void testLazyPropertyCustomTypeExecutable() { public void testLazyPropertyCustomTypeExecutable() throws Exception {
execute( new TestLazyPropertyCustomTypeExecutable() ); execute( new TestLazyPropertyCustomTypeExecutable() );
} }
public void testSharedPKOneToOne() { public void testSharedPKOneToOne() throws Exception {
execute( new TestSharedPKOneToOneExecutable() ); execute( new TestSharedPKOneToOneExecutable() );
} }
private void execute(Executable executable) { private void execute(Executable executable) throws Exception {
executable.prepare(); executable.prepare();
try { try {
executable.execute(); executable.execute();

View File

@ -5,6 +5,6 @@ package org.hibernate.test.instrument.cases;
*/ */
public interface Executable { public interface Executable {
public void prepare(); public void prepare();
public void execute(); public void execute() throws Exception;
public void complete(); public void complete();
} }

View File

@ -19,39 +19,63 @@ public class TestLazyPropertyCustomTypeExecutable extends AbstractExecutable {
return new String[] { "org/hibernate/test/instrument/domain/Problematic.hbm.xml" }; return new String[] { "org/hibernate/test/instrument/domain/Problematic.hbm.xml" };
} }
public void execute() { public void execute() throws Exception {
Session s = getFactory().openSession(); Session s = getFactory().openSession();
s.beginTransaction();
Problematic p = new Problematic(); Problematic p = new Problematic();
p.setName( "whatever" ); try {
p.setBytes( new byte[] { 1, 0, 1, 1, 0 } ); s.beginTransaction();
s.save( p ); p.setName( "whatever" );
s.getTransaction().commit(); p.setBytes( new byte[] { 1, 0, 1, 1, 0 } );
s.close(); s.save( p );
s.getTransaction().commit();
} catch (Exception e) {
s.getTransaction().rollback();
throw e;
} finally {
s.close();
}
// this access should be ok because p1 is not a lazy proxy // this access should be ok because p1 is not a lazy proxy
s = getFactory().openSession(); s = getFactory().openSession();
s.beginTransaction(); try {
Problematic p1 = (Problematic) s.get( Problematic.class, p.getId() ); s.beginTransaction();
Assert.assertTrue( FieldInterceptionHelper.isInstrumented( p1 ) ); Problematic p1 = (Problematic) s.get( Problematic.class, p.getId() );
p1.getRepresentation(); Assert.assertTrue( FieldInterceptionHelper.isInstrumented( p1 ) );
s.getTransaction().commit(); p1.getRepresentation();
s.close(); s.getTransaction().commit();
} catch (Exception e) {
s.getTransaction().rollback();
throw e;
} finally {
s.close();
}
s = getFactory().openSession(); s = getFactory().openSession();
s.beginTransaction(); try {
p1 = (Problematic) s.createQuery( "from Problematic" ).setReadOnly(true ).list().get( 0 ); s.beginTransaction();
p1.getRepresentation(); Problematic p1 = (Problematic) s.createQuery( "from Problematic" ).setReadOnly(true ).list().get( 0 );
s.getTransaction().commit(); p1.getRepresentation();
s.close(); s.getTransaction().commit();
} catch (Exception e) {
s.getTransaction().rollback();
throw e;
} finally {
s.close();
}
s = getFactory().openSession(); s = getFactory().openSession();
s.beginTransaction(); try {
p1 = (Problematic) s.load( Problematic.class, p.getId() ); s.beginTransaction();
Assert.assertFalse( FieldInterceptionHelper.isInstrumented( p1 ) ); Problematic p1 = (Problematic) s.load( Problematic.class, p.getId() );
p1.setRepresentation( p.getRepresentation() ); Assert.assertFalse( FieldInterceptionHelper.isInstrumented( p1 ) );
s.getTransaction().commit(); p1.setRepresentation( p.getRepresentation() );
s.close(); s.getTransaction().commit();
} catch (Exception e) {
s.getTransaction().rollback();
throw e;
} finally {
s.close();
}
} }
protected void cleanup() { protected void cleanup() {