Skip to content

Commit

Permalink
[HHH-17416] Add new inheritor JavaObjectType for specifying unresolve…
Browse files Browse the repository at this point in the history
…d query parameter
  • Loading branch information
The-Huginn authored and sebersole committed Dec 14, 2023
1 parent 71c95f1 commit 67cdd0b
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.hibernate.query.sqm.tree.expression.SqmLiteralNull;
import org.hibernate.type.BasicPluralType;
import org.hibernate.type.BasicType;
import org.hibernate.type.QueryParameterJavaObjectType;
import org.hibernate.type.descriptor.jdbc.JdbcType;

import java.time.temporal.Temporal;
Expand Down Expand Up @@ -107,6 +108,12 @@ public static boolean areTypesComparable(
return true;
}

// for query with parameters we are unable to resolve the correct JavaType, especially for tuple of parameters

if ( lhsType instanceof QueryParameterJavaObjectType || rhsType instanceof QueryParameterJavaObjectType) {
return true;
}

// since we can't so anything meaningful here, just allow
// any comparison with multivalued parameters

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.type;

public class QueryParameterJavaObjectType extends JavaObjectType {

public static final QueryParameterJavaObjectType INSTANCE = new QueryParameterJavaObjectType();

public QueryParameterJavaObjectType() {
super();
}

@Override
public String getName() {
return "QUERY_PARAMETER_JAVA_OBJECT";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,14 @@
import org.hibernate.query.sqm.IntervalType;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.resource.beans.internal.FallbackBeanInstanceProducer;
import org.hibernate.resource.beans.spi.ManagedBean;
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.BasicType;
import org.hibernate.type.BasicTypeRegistry;
import org.hibernate.type.QueryParameterJavaObjectType;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.JavaType;
Expand Down Expand Up @@ -591,10 +593,17 @@ private Class<?> entityClassForEntityName(String entityName) {
public SqmExpressible<?> resolveTupleType(List<? extends SqmTypedNode<?>> typedNodes) {
final SqmExpressible<?>[] components = new SqmExpressible<?>[typedNodes.size()];
for ( int i = 0; i < typedNodes.size(); i++ ) {
final SqmExpressible<?> sqmExpressible = typedNodes.get( i ).getNodeType();
components[i] = sqmExpressible != null
? sqmExpressible
: getBasicTypeForJavaType( Object.class );
SqmTypedNode<?> tupleElement = typedNodes.get(i);
final SqmExpressible<?> sqmExpressible = tupleElement.getNodeType();
// keep null value for Named Parameters
if (tupleElement instanceof SqmParameter<?> && sqmExpressible == null) {
components[i] = QueryParameterJavaObjectType.INSTANCE;
}
else {
components[i] = sqmExpressible != null
? sqmExpressible
: getBasicTypeForJavaType( Object.class );
}
}
return arrayTuples.computeIfAbsent(
new ArrayCacheKey( components ),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package org.hibernate.orm.test.query.hql;

import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import org.hibernate.orm.test.query.sqm.domain.Person;
import org.hibernate.orm.test.query.sqm.domain.Person_;
import org.hibernate.query.SelectionQuery;
import org.hibernate.query.SemanticException;
import org.hibernate.testing.orm.junit.BaseSessionFactoryFunctionalTest;
import org.hibernate.testing.orm.junit.JiraKey;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

@JiraKey(value = "HHH-17416")
public class HHH17416Test extends BaseSessionFactoryFunctionalTest {

private static final Person person = new Person();
static {
person.setPk(7);
person.setNickName("Tadpole");
}

@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {Person.class};
}

@BeforeEach
public void setup() {
inTransaction(session -> session.persist(person));
}

@AfterEach
public void teardown() {
inTransaction(session -> session.createMutationQuery("delete from Person").executeUpdate());
}

@Test
public void testWhereClauseWithTuple() {
sessionFactoryScope().inTransaction(
entityManager -> {
SelectionQuery<Person> selectionQuery = entityManager.createSelectionQuery("from Person p where (p.id, p.nickName) = (:val1, :val2)", Person.class);
selectionQuery = selectionQuery.setParameter("val1", person.getPk()).setParameter("val2", person.getNickName());
Person retrievedPerson = selectionQuery.getSingleResult();
Assertions.assertEquals(person.getPk(), retrievedPerson.getPk());
Assertions.assertEquals(person.getNickName(), retrievedPerson.getNickName());
}
);
}

@Test
public void testWhereClauseWithInvalidObjectType() {
sessionFactoryScope().inTransaction(
entityManager -> {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();

CriteriaQuery<Person> criteria = builder.createQuery(Person.class);
Root<Person> root = criteria.from(Person.class);
criteria.select(root);

try {
criteria.where(builder.equal(root.get(Person_.nickName), builder.literal(new Object())));
TypedQuery<Person> ignored = entityManager.createQuery(criteria);
Assertions.fail("Should have failed with 'Cannot compare left expression of type' of type `org.hibernate.query.SemanticException'");
}
catch (Exception e) {
Assertions.assertTrue(e instanceof SemanticException);
Assertions.assertTrue(e.getMessage().startsWith("Cannot compare left expression of type"));
}
}
);
}
}

0 comments on commit 67cdd0b

Please sign in to comment.