HHH-8901 replace "in ()" SQL with "in (null)" in QueryParameterBindingsImpl

This commit is contained in:
Nathan Xu 2019-11-26 22:28:34 -05:00 committed by Sanne Grinovero
parent 4e449dfafa
commit ab9ae43185
7 changed files with 118 additions and 38 deletions

View File

@ -46,13 +46,17 @@ public String toSqlString( Criteria criteria, CriteriaQuery criteriaQuery ) {
if ( columns.length > 1 ) { if ( columns.length > 1 ) {
singleValueParam = '(' + singleValueParam + ')'; singleValueParam = '(' + singleValueParam + ')';
} }
final String params = values.length > 0 String params = values.length > 0
? StringHelper.repeat( singleValueParam + ", ", values.length - 1 ) + singleValueParam ? StringHelper.repeat( singleValueParam + ", ", values.length - 1 ) + singleValueParam
: ""; : "";
String cols = String.join( ", ", columns ); String cols = String.join( ", ", columns );
if ( columns.length > 1 ) { if ( columns.length > 1 ) {
cols = '(' + cols + ')'; cols = '(' + cols + ')';
} }
// HHH-8901
if ( ! criteriaQuery.getFactory().getDialect().supportsEmptyInList() && params.isEmpty() ) {
params = "null";
}
return cols + " in (" + params + ')'; return cols + " in (" + params + ')';
} }
else { else {

View File

@ -194,6 +194,10 @@ public String render(boolean isNegated, RenderingContext renderingContext) {
.append( ( (Renderable) value ).render( renderingContext ) ); .append( ( (Renderable) value ).render( renderingContext ) );
sep = ", "; sep = ", ";
} }
// HHH-8901
if ( ! renderingContext.getDialect().supportsEmptyInList() && getValues().isEmpty() ) {
buffer.append( "null" );
}
buffer.append( ')' ); buffer.append( ')' );
} }
return buffer.toString(); return buffer.toString();

View File

@ -637,6 +637,11 @@ public String expandListValuedParameters(String queryString, SharedSessionContra
parameterBindingMap.put( syntheticParam, syntheticBinding ); parameterBindingMap.put( syntheticParam, syntheticBinding );
} }
// HHH-8901
if ( ! dialect.supportsEmptyInList() && expansionList.length() == 0 ) {
expansionList.append( "null" );
}
queryString = StringHelper.replace( queryString = StringHelper.replace(
beforePlaceholder, beforePlaceholder,
afterPlaceholder, afterPlaceholder,

View File

@ -8,26 +8,22 @@
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.util.List; import java.util.List;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path; import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root; import javax.persistence.criteria.Root;
import org.hibernate.dialect.Oracle12cDialect; import org.hibernate.dialect.Oracle12cDialect;
import org.hibernate.dialect.Oracle8iDialect;
import org.hibernate.dialect.Oracle9Dialect;
import org.hibernate.dialect.OracleDialect;
import org.hibernate.jpa.test.metamodel.AbstractMetamodelSpecificTest; import org.hibernate.jpa.test.metamodel.AbstractMetamodelSpecificTest;
import org.hibernate.jpa.test.metamodel.CreditCard; import org.hibernate.jpa.test.metamodel.CreditCard;
import org.hibernate.jpa.test.metamodel.CreditCard_; import org.hibernate.jpa.test.metamodel.CreditCard_;
import org.hibernate.jpa.test.metamodel.Customer_; import org.hibernate.jpa.test.metamodel.Customer_;
import org.hibernate.jpa.test.metamodel.Order; import org.hibernate.jpa.test.metamodel.Order;
import org.hibernate.jpa.test.metamodel.Order_; import org.hibernate.jpa.test.metamodel.Order_;
import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.SkipForDialect; import org.hibernate.testing.SkipForDialect;
import org.hibernate.testing.TestForIssue; import org.hibernate.testing.TestForIssue;
import org.junit.Before; import org.junit.Before;
@ -297,4 +293,21 @@ public void testExplicitBuilderBooleanHandling() {
em.getTransaction().commit(); em.getTransaction().commit();
em.close(); em.close();
} }
@Test
@TestForIssue( jiraKey = "HHH-8901" )
@RequiresDialectFeature( DialectChecks.NotSupportsEmptyInListCheck.class )
public void testEmptyInPredicate() {
EntityManager em = getOrCreateEntityManager();
em.getTransaction().begin();
CriteriaQuery<Order> orderCriteria = builder.createQuery( Order.class );
Root<Order> orderRoot = orderCriteria.from( Order.class );
orderCriteria.select( orderRoot );
orderCriteria.where( builder.in( orderRoot.get("totalPrice") ) );
List<Order> orders = em.createQuery( orderCriteria ).getResultList();
assertTrue( orders.isEmpty() );
em.getTransaction().commit();
em.close();
}
} }

View File

@ -8,11 +8,15 @@
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.Transaction; import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions; import org.hibernate.criterion.Restrictions;
import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test; import org.junit.Test;
@ -42,4 +46,24 @@ public void testIn() {
tx.rollback(); tx.rollback();
session.close(); session.close();
} }
@Test
@TestForIssue( jiraKey = "HHH-8901" )
@RequiresDialectFeature(DialectChecks.NotSupportsEmptyInListCheck.class)
public void testEmptyInListForDialectNotSupportsEmptyInList() {
Session session = openSession();
Transaction tx = session.beginTransaction();
session.save( new Woman() );
session.save( new Man() );
session.flush();
tx.commit();
session.close();
session = openSession();
tx = session.beginTransaction();
List persons = session.createCriteria( Person.class ).add(
Restrictions.in( "name", Collections.emptySet() ) ).list();
assertEquals( 0, persons.size() );
tx.rollback();
session.close();
}
} }

View File

@ -6,6 +6,18 @@
*/ */
package org.hibernate.test.hql; package org.hibernate.test.hql;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hibernate.testing.junit4.ExtraAssertions.assertClassAssignability;
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
import java.sql.Date; import java.sql.Date;
@ -13,11 +25,11 @@
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.hibernate.Hibernate; import org.hibernate.Hibernate;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.Query; import org.hibernate.Query;
@ -53,19 +65,6 @@
import org.hibernate.loader.MultipleBagFetchException; import org.hibernate.loader.MultipleBagFetchException;
import org.hibernate.persister.entity.DiscriminatorType; import org.hibernate.persister.entity.DiscriminatorType;
import org.hibernate.stat.QueryStatistics; import org.hibernate.stat.QueryStatistics;
import org.hibernate.transform.DistinctRootEntityResultTransformer;
import org.hibernate.transform.Transformers;
import org.hibernate.type.ComponentType;
import org.hibernate.type.ManyToOneType;
import org.hibernate.type.Type;
import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.FailureExpected;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.SkipForDialect;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.hibernate.test.any.IntegerPropertyValue; import org.hibernate.test.any.IntegerPropertyValue;
import org.hibernate.test.any.PropertySet; import org.hibernate.test.any.PropertySet;
import org.hibernate.test.any.PropertyValue; import org.hibernate.test.any.PropertyValue;
@ -75,24 +74,20 @@
import org.hibernate.test.cid.LineItem.Id; import org.hibernate.test.cid.LineItem.Id;
import org.hibernate.test.cid.Order; import org.hibernate.test.cid.Order;
import org.hibernate.test.cid.Product; import org.hibernate.test.cid.Product;
import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.FailureExpected;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.SkipForDialect;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.hibernate.transform.DistinctRootEntityResultTransformer;
import org.hibernate.transform.Transformers;
import org.hibernate.type.ComponentType;
import org.hibernate.type.ManyToOneType;
import org.hibernate.type.Type;
import org.junit.Test; import org.junit.Test;
import org.jboss.logging.Logger;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hibernate.testing.junit4.ExtraAssertions.assertClassAssignability;
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
import static org.hibernate.testing.transaction.TransactionUtil2.inTransaction;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/** /**
* Tests the integration of the new AST parser into the loading of query results using * Tests the integration of the new AST parser into the loading of query results using
* the Hibernate persisters and loaders. * the Hibernate persisters and loaders.
@ -663,6 +658,35 @@ public void testEmptyInList() {
session.close(); session.close();
} }
@Test
@TestForIssue( jiraKey = "HHH-8901" )
@RequiresDialectFeature(DialectChecks.NotSupportsEmptyInListCheck.class)
public void testEmptyInListForDialectsNotSupportsEmptyInList() {
Session session = openSession();
session.beginTransaction();
Human human = new Human();
human.setName( new Name( "Lukasz", null, "Antoniak" ) );
human.setNickName( "NONE" );
session.save( human );
session.getTransaction().commit();
session.close();
session = openSession();
session.beginTransaction();
List results = session.createQuery( "from Human h where h.nickName in (:nickNames)" )
.setParameter("nickNames", Collections.emptySet() )
.list();
assertEquals( 0, results.size() );
session.getTransaction().commit();
session.close();
session = openSession();
session.beginTransaction();
session.delete( human );
session.getTransaction().commit();
session.close();
}
@Test @Test
@TestForIssue( jiraKey = "HHH-2851") @TestForIssue( jiraKey = "HHH-2851")
public void testMultipleRefsToSameParam() { public void testMultipleRefsToSameParam() {

View File

@ -55,6 +55,12 @@ public boolean isMatch(Dialect dialect) {
} }
} }
public static class NotSupportsEmptyInListCheck implements DialectCheck {
public boolean isMatch(Dialect dialect) {
return !dialect.supportsEmptyInList();
}
}
public static class CaseSensitiveCheck implements DialectCheck { public static class CaseSensitiveCheck implements DialectCheck {
public boolean isMatch(Dialect dialect) { public boolean isMatch(Dialect dialect) {
return dialect.areStringComparisonsCaseInsensitive(); return dialect.areStringComparisonsCaseInsensitive();