From 41161f9fa9e1d760995c462c78cbd19ef8e7b082 Mon Sep 17 00:00:00 2001 From: Nathan Xu Date: Fri, 28 Aug 2020 13:35:46 -0400 Subject: [PATCH 1/4] HHH-13908 fix the issue MySQL's 'time' function issue in Criteria --- .../org/hibernate/dialect/MySQLDialect.java | 2 +- .../query/criteria/internal/hhh13908/Foo.java | 13 +++++ .../internal/hhh13908/HHH13908Test.java | 48 +++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh13908/Foo.java create mode 100644 hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh13908/HHH13908Test.java diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java index b671118133..8eb757667e 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java @@ -194,7 +194,7 @@ public class MySQLDialect extends Dialect { registerFunction( "second", new StandardSQLFunction( "second", StandardBasicTypes.INTEGER ) ); registerFunction( "sec_to_time", new StandardSQLFunction( "sec_to_time", StandardBasicTypes.TIME ) ); registerFunction( "sysdate", new NoArgSQLFunction( "sysdate", StandardBasicTypes.TIMESTAMP ) ); - registerFunction( "time", new StandardSQLFunction( "time", StandardBasicTypes.TIME ) ); + registerFunction( "time", new StandardSQLFunction( "time", StandardBasicTypes.STRING ) ); registerFunction( "timestamp", new StandardSQLFunction( "timestamp", StandardBasicTypes.TIMESTAMP ) ); registerFunction( "time_to_sec", new StandardSQLFunction( "time_to_sec", StandardBasicTypes.INTEGER ) ); registerFunction( "to_days", new StandardSQLFunction( "to_days", StandardBasicTypes.LONG ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh13908/Foo.java b/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh13908/Foo.java new file mode 100644 index 0000000000..f82cf14294 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh13908/Foo.java @@ -0,0 +1,13 @@ +package org.hibernate.query.criteria.internal.hhh13908; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity(name = "Foo") +@Table(name = "Foo") +public class Foo { + @Id + Long id; + String startTime; +} diff --git a/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh13908/HHH13908Test.java b/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh13908/HHH13908Test.java new file mode 100644 index 0000000000..42ade2e68b --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh13908/HHH13908Test.java @@ -0,0 +1,48 @@ +package org.hibernate.query.criteria.internal.hhh13908; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +import org.hibernate.dialect.MySQLDialect; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.TestForIssue; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; + +/** + * @author Archie Cobbs + * @author Nathan Xu + */ +@RequiresDialect( MySQLDialect.class ) +public class HHH13908Test extends BaseEntityManagerFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { Foo.class }; + } + + @Test + @TestForIssue( jiraKey = "HHH-13908" ) + public void testTimeFunctionNotThrowException() { + doInJPA( this::entityManagerFactory, entityManager -> { + final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + final CriteriaQuery cq = cb.createQuery( Foo.class ); + final Root foo = cq.from( Foo.class ); + cq.select( foo ) + .where( + cb.lessThanOrEqualTo( + cb.function( "TIME", String.class, foo.get( Foo_.startTime ) ), + "17:00:00" + ) + ); + // without fixing, the following exception will be thrown: + // Parameter value [17:00:00] did not match expected type [java.util.Date (n/a)] + //java.lang.IllegalArgumentException: Parameter value [17:00:00] did not match expected type [java.util.Date (n/a)] + entityManager.createQuery( cq ).getResultList(); + } ); + } +} From e1ff70519a6e8941c3e580dd423892b62ef19810 Mon Sep 17 00:00:00 2001 From: Nathan Xu Date: Sun, 23 Aug 2020 22:40:22 -0400 Subject: [PATCH 2/4] HHH-14178 Fix the issue collections visiting could be skipped (e.g., versioned entity) in AbstractSaveEventListener --- .../collection/spi/PersistentCollection.java | 8 + .../hibernate/engine/internal/Cascade.java | 3 +- .../internal/AbstractSaveEventListener.java | 2 +- ...antiatdCollectionSkipDeleteOrphanTest.java | 665 ++++++++++++++++++ 4 files changed, 676 insertions(+), 2 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/event/service/internal/NewlyInstantiatdCollectionSkipDeleteOrphanTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentCollection.java b/hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentCollection.java index 24032cee22..0a98641c38 100644 --- a/hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentCollection.java +++ b/hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentCollection.java @@ -460,4 +460,12 @@ public interface PersistentCollection { */ Collection getOrphans(Serializable snapshot, String entityName); + /** + * Is the collection newly instantiated? + * + * @return {@code true} if the collection is newly instantiated + */ + default boolean isNewlyInstantiated() { + return getKey() == null && !isDirty(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/Cascade.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/Cascade.java index eba00aebf3..f8788c0af4 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/Cascade.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/Cascade.java @@ -545,8 +545,9 @@ public final class Cascade { final boolean deleteOrphans = style.hasOrphanDelete() && action.deleteOrphans() && elemType.isEntityType() + && child instanceof PersistentCollection // a newly instantiated collection can't have orphans - && child instanceof PersistentCollection; + && ! ( (PersistentCollection) child ).isNewlyInstantiated(); if ( deleteOrphans ) { final boolean traceEnabled = LOG.isTraceEnabled(); diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java index 78c9d9025b..35b16972b3 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java @@ -269,7 +269,7 @@ public abstract class AbstractSaveEventListener boolean substitute = substituteValuesIfNecessary( entity, id, values, persister, source ); if ( persister.hasCollections() ) { - substitute = substitute || visitCollectionsBeforeSave( entity, id, values, types, source ); + substitute = visitCollectionsBeforeSave( entity, id, values, types, source ) || substitute; } if ( substitute ) { diff --git a/hibernate-core/src/test/java/org/hibernate/event/service/internal/NewlyInstantiatdCollectionSkipDeleteOrphanTest.java b/hibernate-core/src/test/java/org/hibernate/event/service/internal/NewlyInstantiatdCollectionSkipDeleteOrphanTest.java new file mode 100644 index 0000000000..59e72494e5 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/event/service/internal/NewlyInstantiatdCollectionSkipDeleteOrphanTest.java @@ -0,0 +1,665 @@ +package org.hibernate.event.service.internal; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import javax.persistence.Column; +import javax.persistence.Embeddable; +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.MapsId; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.Transient; +import javax.persistence.Version; + +import org.hibernate.FlushMode; +import org.hibernate.Transaction; +import org.hibernate.annotations.Cascade; +import org.hibernate.annotations.DynamicUpdate; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * @author Artem K. + * @author Nathan Xu + */ +@TestForIssue( jiraKey = "HHH-14178" ) +public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunctionalTestCase { + + private UnversionedParent up; + private VersionedParent vp; + private Child c; + private VersionedMappingUnversionedParent vmup; + private VersionedMappingVersionedParent vmvp; + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + VersionedParent.class, + UnversionedParent.class, + Child.class, + VersionedMappingUnversionedParent.class, + VersionedMappingVersionedParent.class + }; + } + + @Before + public void setup() { + + up = new UnversionedParent(); + + vp = new VersionedParent(); + + c = new Child(); + + vmup = new VersionedMappingUnversionedParent(); + vmup.addChild( c ); + + vmvp = new VersionedMappingVersionedParent(); + vmvp.addChild( c ); + + } + + @After + public void cleanup() { + inTransaction( s -> { + if (up.getId() != null) { + s.delete( up ); + } + if (vp.getId() != null) { + s.delete( vp ); + } + if (c.getId() != null) { + s.delete( c ); + } + } ); + } + + @Test + public void VersionedMappingVersionedParentSaveUpdate() { + inSession( s -> { + s.setHibernateFlushMode( FlushMode.MANUAL ); + + Transaction trx = s.beginTransaction(); + try { + // Associate the mapping to parent + vp.addChild( vmvp ); + + // Persist Child associated with versioned parent + s.saveOrUpdate( c ); + Assert.assertNotEquals( Integer.valueOf(0), c.getId() ); + + // Persist VersionParent + s.saveOrUpdate( vp ); + Assert.assertNotEquals( Integer.valueOf(0), vp.getId() ); + + // Persist versioned mapping now that parent id is generated + s.saveOrUpdate( vmvp ); + Assert.assertNotNull( vmvp.getId() ); + Assert.assertNotEquals( Integer.valueOf(0), vmvp.getId().getParentId() ); + Assert.assertNotEquals( Integer.valueOf(0), vmvp.getId().getChildId() ); + + s.flush(); + trx.commit(); + } catch (RuntimeException e) { + // Transaction is rolled back so we do not want delete code in cleanup to execute. + // Reset any possible ID assignments + vp.setId( null ); + c.setId( null ); + + if (trx.isActive()) { + trx.rollback(); + } + throw e; + } + } ); + } + + @Test + public void VersionedMappingUnversionedParentSaveUpdate() { + inSession( s -> { + s.setHibernateFlushMode( FlushMode.MANUAL ); + + Transaction trx = s.beginTransaction(); + try { + // Associate the mapping to parent + up.addVersionedMappings( vmup ); + + // Persist child associated with versioned mapping of unversioned parent + s.saveOrUpdate( c ); + Assert.assertNotEquals( Integer.valueOf(0), c.getId() ); + + // Persist unversioned parent + s.saveOrUpdate( up ); + Assert.assertNotEquals( Integer.valueOf(0), up.getId() ); + + // Persist versioned mapping + s.saveOrUpdate( vmup ); + Assert.assertNotNull( vmup.getId() ); + Assert.assertNotEquals( Integer.valueOf(0), vmup.getId().getParentId() ); + Assert.assertNotEquals( Integer.valueOf(0), vmup.getId().getChildId() ); + + s.flush(); + trx.commit(); + } catch (RuntimeException e) { + // Transaction is rolled back so we do not want delete code in cleanup to execute. + // Reset any possible ID assignments + up.setId( null ); + c.setId( null ); + + if (trx.isActive()) { + trx.rollback(); + } + throw e; + } + } ); + } + + @Entity(name = "Child") + @Table(name = "Child") + @DynamicUpdate + public static class Child { + private Integer id; + private Long version; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "Id", nullable = false) + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + @Version + @Column(name = "Version", nullable = false) + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } + + @Override + public int hashCode() { + return 31; + } + + @Override + public boolean equals(Object obj) { + if ( this == obj ) { + return true; + } + if ( !( obj instanceof Child ) ) { + return false; + } + Child other = (Child) obj; + return Objects.equals( getId(), other.getId() ); + } + } + + @Embeddable + public static class MappingId implements Serializable { + private static final long serialVersionUID = -4896032953810358940L; + + private Integer parentId; + private Integer childId; + + @Column(name="ParentId", nullable=false) + public Integer getParentId() { + return parentId; + } + + public void setParentId(Integer parentId) { + this.parentId = parentId; + } + + @Column(name="ChildId", nullable=false) + public Integer getChildId() { + return childId; + } + + public void setChildId(Integer childId) { + this.childId = childId; + } + + @Override + public int hashCode() { + return Objects.hash(getParentId(), getChildId()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof MappingId)) { + return false; + } + MappingId other = (MappingId) obj; + return Objects.equals(getParentId(), other.getParentId()) && Objects.equals(getChildId(), other.getChildId()); + } + + @Override + public String toString() { + return "[" + getParentId() + " | " + getChildId() + "]"; + } + } + + @Entity(name = "UnversionedParent") + @Table(name = "UnversionedParent") + @DynamicUpdate + public static class UnversionedParent { + private Integer id; + private Set versionedMappings; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name="Id", nullable=false) + public Integer getId() { + return id; + } + + public void setId(Integer id) { + if (!Objects.equals(id, getId())) { + this.id = id; + + getVersionedMappings().forEach(c -> { + if (c.getId() == null) { + c.setId(new MappingId()); + } + c.getId().setParentId(id); + }); + } + } + + @OneToMany(mappedBy="parent", cascade={ javax.persistence.CascadeType.DETACH, javax.persistence.CascadeType.MERGE, javax.persistence.CascadeType.REFRESH, javax.persistence.CascadeType.REMOVE }, orphanRemoval=true) + @Cascade({ org.hibernate.annotations.CascadeType.DELETE, org.hibernate.annotations.CascadeType.LOCK, org.hibernate.annotations.CascadeType.REPLICATE }) + protected Set getVersionedMappings() { + if (versionedMappings == null) { + versionedMappings = new HashSet<>(); + } + return this.versionedMappings; + } + + protected void setVersionedMappings(Set value) { + if (value == null && this.versionedMappings != null) { + this.versionedMappings.clear(); + } else { + this.versionedMappings = value; + } + } + + @Transient + public Collection getVersionedMappingsCollection() { + return new ArrayList<>(getVersionedMappings()); + } + + public void addVersionedMappings(VersionedMappingUnversionedParent addValue) { + if (addValue != null && !this.getVersionedMappings().contains(addValue)) { + this.versionedMappings.add(addValue); + addValue.addParent(this); + } + } + + public void removeVersionedMappings(VersionedMappingUnversionedParent removeValue) { + if (this.versionedMappings != null && this.versionedMappings.contains(removeValue)) { + this.versionedMappings.remove(removeValue); + removeValue.removeParent(); + } + } + + @Override + public int hashCode() { + return 17; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof UnversionedParent)) { + return false; + } + UnversionedParent other = (UnversionedParent) obj; + return Objects.equals(getId(), other.getId()); + } + } + + @Entity(name = "VersionedParent") + @Table(name = "VersionedParent") + @DynamicUpdate + public static class VersionedParent { + private Integer id; + private Long version; + private Set children; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name="Id", nullable=false) + public Integer getId() { + return id; + } + + public void setId(Integer id) { + if (!Objects.equals(id, getId())) { + this.id = id; + + getChildren().forEach(c -> { + if (c.getId() == null) { + c.setId(new MappingId()); + } + c.getId().setParentId(id); + }); + } + } + + @Version + @Column(name="Version", nullable=false) + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } + + @OneToMany(mappedBy="parent", cascade={ javax.persistence.CascadeType.DETACH, javax.persistence.CascadeType.MERGE, javax.persistence.CascadeType.REFRESH, javax.persistence.CascadeType.REMOVE }, orphanRemoval=true) + @Cascade({ org.hibernate.annotations.CascadeType.DELETE, org.hibernate.annotations.CascadeType.LOCK, org.hibernate.annotations.CascadeType.REPLICATE }) + protected Set getChildren() { + if (children == null) { + children = new HashSet<>(); + } + return this.children; + } + + protected void setChildren(Set value) { + if (value == null && this.children != null) { + this.children.clear(); + } else { + this.children = value; + } + } + + @Transient + public Collection getChildrenCollection() { + return new ArrayList<>(getChildren()); + } + + public void addChild(VersionedMappingVersionedParent addValue) { + if (addValue != null && !this.getChildren().contains(addValue)) { + this.children.add(addValue); + addValue.addParent(this); + } + } + + public void removeChild(VersionedMappingVersionedParent removeValue) { + if (this.children != null && this.children.contains(removeValue)) { + this.children.remove(removeValue); + removeValue.removeParent(); + } + } + + @Override + public int hashCode() { + return 31; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof VersionedParent)) { + return false; + } + VersionedParent other = (VersionedParent) obj; + return Objects.equals(getId(), other.getId()); + } + } + + @Entity(name = "VersionedMappingUnversionedParent") + @Table(name = "VersionedMappingUnversionedParent") + @DynamicUpdate + public static class VersionedMappingUnversionedParent { + private MappingId id; + private Child child; + private Long version; + + @EmbeddedId + public MappingId getId() { + return this.id; + } + + public void setId(MappingId id) { + this.id = id; + } + + @Version + @Column(name="Version", nullable=false) + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } + + protected UnversionedParent parent; + + @ManyToOne(optional=false, fetch=FetchType.LAZY) + @MapsId("parentId") + @JoinColumn(name="ParentId", nullable=false) + public UnversionedParent getParent() { + return this.parent; + } + + protected void setParent(UnversionedParent value) { + this.parent = value; + } + + public void addParent(UnversionedParent value) { + UnversionedParent oldParent = getParent(); + if (!Objects.equals(value, oldParent)) { + if (oldParent != null) { + setParent(null); + oldParent.removeVersionedMappings(this); + } + + if (value != null) { + setParent(value); + if (getId() == null) { + setId(new MappingId()); + } + getId().setParentId(value.getId()); + value.addVersionedMappings(this); + } + } + } + + public void removeParent() { + addParent(null); + } + + @ManyToOne(optional=false, fetch=FetchType.LAZY) + @MapsId("childId") + @JoinColumn(name="ChildId", nullable=false) + public Child getChild() { + return child; + } + + protected void setChild(Child child) { + this.child = child; + } + + public void addChild(Child value) { + Child oldChild = getChild(); + if (!Objects.equals(value, oldChild)) { + if (oldChild != null) { + setChild(null); + } + + if (value != null) { + setChild(value); + if (getId() == null) { + setId(new MappingId()); + } + getId().setChildId(value.getId()); + } + } + } + + public void removeChild() { + addChild(null); + } + + @Override + public int hashCode() { + return 17; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof VersionedMappingUnversionedParent)) { + return false; + } + VersionedMappingUnversionedParent other = (VersionedMappingUnversionedParent) obj; + return Objects.equals(getId(), other.getId()); + } + } + + @Entity(name = "VersionedMappingVersionedParent") + @Table(name = "VersionedMappingVersionedParent") + @DynamicUpdate + public static class VersionedMappingVersionedParent { + private MappingId id; + private Child child; + private Long version; + + @EmbeddedId + public MappingId getId() { + return this.id; + } + + public void setId(MappingId id) { + this.id = id; + } + + @Version + @Column(name="Version", nullable=false) + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } + + protected VersionedParent parent; + + @ManyToOne(optional=false, fetch=FetchType.LAZY) + @MapsId("parentId") + @JoinColumn(name="ParentId", nullable=false) + public VersionedParent getParent() { + return this.parent; + } + + protected void setParent(VersionedParent value) { + this.parent = value; + } + + public void addParent(VersionedParent value) { + VersionedParent oldParent = getParent(); + if (!Objects.equals(value, oldParent)) { + if (oldParent != null) { + setParent(null); + oldParent.removeChild(this); + } + + if (value != null) { + setParent(value); + if (getId() == null) { + setId(new MappingId()); + } + getId().setParentId(value.getId()); + value.addChild(this); + } + } + } + + public void removeParent() { + addParent(null); + } + + @ManyToOne(optional=false, fetch=FetchType.LAZY) + @MapsId("childId") + @JoinColumn(name="ChildId", nullable=false) + public Child getChild() { + return child; + } + + protected void setChild(Child child) { + this.child = child; + } + + public void addChild(Child value) { + Child oldChild = getChild(); + if (!Objects.equals(value, oldChild)) { + if (oldChild != null) { + setChild(null); + } + + if (value != null) { + setChild(value); + if (getId() == null) { + setId(new MappingId()); + } + getId().setChildId(value.getId()); + } + } + } + + public void removeChild() { + addChild(null); + } + + @Override + public int hashCode() { + return 17; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof VersionedMappingVersionedParent)) { + return false; + } + VersionedMappingVersionedParent other = (VersionedMappingVersionedParent) obj; + return Objects.equals(getId(), other.getId()); + } + } +} From 90be61210c189dc7799f81a7a3a4dbea57280174 Mon Sep 17 00:00:00 2001 From: Nathan Xu Date: Tue, 25 Aug 2020 10:16:12 -0400 Subject: [PATCH 3/4] HHH-11877 wrap CompoundPredicate's expression list --- .../internal/predicate/CompoundPredicate.java | 5 ++- .../query/criteria/internal/hhh11877/Foo.java | 31 +++++++++++++ .../internal/hhh11877/HHH111877Test.java | 44 +++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh11877/Foo.java create mode 100644 hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh11877/HHH111877Test.java diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/predicate/CompoundPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/predicate/CompoundPredicate.java index 00840a7c47..212680ca95 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/predicate/CompoundPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/predicate/CompoundPredicate.java @@ -80,7 +80,10 @@ public class CompoundPredicate private void applyExpressions(List> expressions) { this.expressions.clear(); - this.expressions.addAll( expressions ); + final CriteriaBuilderImpl criteriaBuilder = criteriaBuilder(); + for ( Expression expression : expressions ) { + this.expressions.add( criteriaBuilder.wrap( expression ) ); + } } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh11877/Foo.java b/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh11877/Foo.java new file mode 100644 index 0000000000..efaeff9231 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh11877/Foo.java @@ -0,0 +1,31 @@ +package org.hibernate.query.criteria.internal.hhh11877; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class Foo { + + private long id; + private boolean bar; + + @Column(nullable = false) + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Id + public long getId() { + return this.id; + } + public void setId(final long id) { + this.id = id; + } + + public boolean isBar() { + return this.bar; + } + public void setBar(final boolean bar) { + this.bar = bar; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh11877/HHH111877Test.java b/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh11877/HHH111877Test.java new file mode 100644 index 0000000000..e5af10a0b9 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh11877/HHH111877Test.java @@ -0,0 +1,44 @@ +package org.hibernate.query.criteria.internal.hhh11877; + +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.hibernate.testing.TestForIssue; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; + +/** + * @author Archie Cobbs + * @author Nathan Xu + */ +@TestForIssue( jiraKey = "HHH-11877" ) +public class HHH111877Test extends BaseEntityManagerFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { Foo.class }; + } + + @Test + public void testNoExceptionThrow() { + doInJPA( this::entityManagerFactory, entityManager -> { + final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + + final CriteriaQuery cq = cb.createQuery( Foo.class ); + final Root foo = cq.from( Foo.class ); + + cq.select( foo ).where( cb.and( cb.and(), foo.get( Foo_.bar ) ) ); + + final TypedQuery tq = entityManager.createQuery( cq ); + + // without fixing, the statement below will throw exception: + // java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected AST node: . near line 1, column 106 [select generatedAlias0 from org.hibernate.bugs.Foo as generatedAlias0 where ( 1=1 ) and ( generatedAlias0.bar )] + tq.getResultList(); + } ); + } +} From 517a0b963977b5044b82593f519cd77154c0ed03 Mon Sep 17 00:00:00 2001 From: Nathan Xu Date: Fri, 28 Aug 2020 12:57:17 -0400 Subject: [PATCH 4/4] HHH-14199 fix the error when running 'setDataBase' gradle task --- gradle/java-module.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/java-module.gradle b/gradle/java-module.gradle index e5a2700fa8..895042178b 100644 --- a/gradle/java-module.gradle +++ b/gradle/java-module.gradle @@ -306,8 +306,8 @@ task copyResourcesToIntelliJOutFolder { task setDataBase { inputs.property( "db", db ) doLast { - processTestResources.execute() - copyResourcesToIntelliJOutFolder.execute() + processTestResources + copyResourcesToIntelliJOutFolder println( 'Setting current database to ' + db ) }