/*
* 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>.
*/
//$Id$
package org.hibernate.test.subquery;
import org.hibernate.QueryException;
import org.hibernate.Session;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.function.SQLFunction;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.hibernate.type.Type;
import org.junit.Test;
import javax.persistence.Query;
import java.util.List;
import java.util.function.Consumer;
/**
* Test some subquery scenarios.
*
* @author Christian Beikov
*/
@RequiresDialect(H2Dialect.class)
public class SubqueryTest extends BaseCoreFunctionalTestCase {
private static final SQLFunction LIMIT_FUNCTION = new SQLFunction() {
public boolean hasArguments() {
return true;
}
public boolean hasParenthesesIfNoArguments() {
return true;
}
public Type getReturnType(Type type, Mapping mpng) throws QueryException {
return type;
}
public String render(Type type, List list, SessionFactoryImplementor sfi) throws QueryException {
String subquery = list.get(0).toString();
return subquery.substring(0, subquery.length() - 1) + " limit " + list.get(1) + ")";
}
};
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[]{
EntityA.class
};
}
@Test
public void testNestedOrderBySubqueryInFunction() {
withLimit(s -> {
Query q = s.createQuery(
"SELECT a.id FROM EntityA a " +
"ORDER BY CASE WHEN (" +
"SELECT 1 FROM EntityA s1 " +
"WHERE s1.id IN(" +
"LIMIT(" +
"(" +
"SELECT 1 FROM EntityA sub " +
"ORDER BY " +
"CASE WHEN sub.name IS NULL THEN 1 ELSE 0 END, " +
"sub.name DESC, " +
"CASE WHEN sub.id IS NULL THEN 1 ELSE 0 END, " +
"sub.id DESC" +
")," +
"1)" +
")" +
") = 1 THEN 1 ELSE 0 END"
);
q.getResultList();
});
}
private void withLimit(Consumer<Session> consumer) {
rebuildSessionFactory( c -> c.addSqlFunction( "limit", LIMIT_FUNCTION ) );
try {
Session s = openSession();
consumer.accept( s );
} finally {
// Rebuild to remove the function
rebuildSessionFactory();
}
}
}