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;
@ -62,13 +61,13 @@ public abstract class SubqueryExpression implements Criterion {
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,
@ -76,19 +75,37 @@ public abstract class SubqueryExpression implements Criterion {
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(' '); }
if ( quantifier != null ) {
buf.append( quantifier ).append( ' ' );
}
return buf.append( '(' ).append( sql ).append( ')' ) return buf.append( '(' ).append( sql ).append( ')' )
.toString(); .toString();
} }
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) 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
@ -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;
@ -89,8 +89,7 @@ public final class QueryParameters {
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;
@ -100,40 +99,22 @@ 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,
@ -159,8 +140,7 @@ public final class QueryParameters {
//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,
@ -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;
@ -220,8 +199,7 @@ public final class QueryParameters {
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,
@ -397,16 +375,18 @@ public final class QueryParameters {
} }
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() )
@ -417,12 +397,15 @@ public final class QueryParameters {
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();
} }
} }
@ -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();
} }
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 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();
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(); 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,40 +19,64 @@ 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();
try {
s.beginTransaction();
p.setName( "whatever" ); p.setName( "whatever" );
p.setBytes( new byte[] { 1, 0, 1, 1, 0 } ); p.setBytes( new byte[] { 1, 0, 1, 1, 0 } );
s.save( p ); s.save( p );
s.getTransaction().commit(); s.getTransaction().commit();
} catch (Exception e) {
s.getTransaction().rollback();
throw e;
} finally {
s.close(); 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();
try {
s.beginTransaction(); s.beginTransaction();
Problematic p1 = (Problematic) s.get( Problematic.class, p.getId() ); Problematic p1 = (Problematic) s.get( Problematic.class, p.getId() );
Assert.assertTrue( FieldInterceptionHelper.isInstrumented( p1 ) ); Assert.assertTrue( FieldInterceptionHelper.isInstrumented( p1 ) );
p1.getRepresentation(); p1.getRepresentation();
s.getTransaction().commit(); s.getTransaction().commit();
} catch (Exception e) {
s.getTransaction().rollback();
throw e;
} finally {
s.close(); s.close();
}
s = getFactory().openSession(); s = getFactory().openSession();
try {
s.beginTransaction(); s.beginTransaction();
p1 = (Problematic) s.createQuery( "from Problematic" ).setReadOnly(true ).list().get( 0 ); Problematic p1 = (Problematic) s.createQuery( "from Problematic" ).setReadOnly(true ).list().get( 0 );
p1.getRepresentation(); p1.getRepresentation();
s.getTransaction().commit(); s.getTransaction().commit();
} catch (Exception e) {
s.getTransaction().rollback();
throw e;
} finally {
s.close(); s.close();
}
s = getFactory().openSession(); s = getFactory().openSession();
try {
s.beginTransaction(); s.beginTransaction();
p1 = (Problematic) s.load( Problematic.class, p.getId() ); Problematic p1 = (Problematic) s.load( Problematic.class, p.getId() );
Assert.assertFalse( FieldInterceptionHelper.isInstrumented( p1 ) ); Assert.assertFalse( FieldInterceptionHelper.isInstrumented( p1 ) );
p1.setRepresentation( p.getRepresentation() ); p1.setRepresentation( p.getRepresentation() );
s.getTransaction().commit(); s.getTransaction().commit();
} catch (Exception e) {
s.getTransaction().rollback();
throw e;
} finally {
s.close(); s.close();
} }
}
protected void cleanup() { protected void cleanup() {
Session s = getFactory().openSession(); Session s = getFactory().openSession();