HHH-15654 Fix SQL errors for some DBs + documentation for new interfaces
This commit is contained in:
parent
6d9c448db2
commit
5feb44026c
|
@ -12,18 +12,68 @@ import jakarta.persistence.criteria.Expression;
|
|||
import jakarta.persistence.criteria.Order;
|
||||
|
||||
/**
|
||||
* Common contract for window parts used in window and aggregate functions.
|
||||
*
|
||||
* @author Marco Belladelli
|
||||
*/
|
||||
public interface JpaWindow {
|
||||
/**
|
||||
* Add partition by expressions to the window.
|
||||
*
|
||||
* @param expressions the partition by expressions
|
||||
*
|
||||
* @return the modified window
|
||||
*/
|
||||
JpaWindow partitionBy(Expression<?>... expressions);
|
||||
|
||||
/**
|
||||
* Add order by expressions to the window.
|
||||
*
|
||||
* @param expressions the order by expressions
|
||||
*
|
||||
* @return the modified window
|
||||
*/
|
||||
JpaWindow orderBy(Order... expressions);
|
||||
|
||||
/**
|
||||
* Add a {@code ROWS} frame clause to the window and define
|
||||
* start and end {@link JpaWindowFrame} specifications.
|
||||
*
|
||||
* @param startFrame the start frame
|
||||
* @param endFrame the optional end frame
|
||||
*
|
||||
* @return the modified window
|
||||
*/
|
||||
JpaWindow frameRows(JpaWindowFrame startFrame, JpaWindowFrame endFrame);
|
||||
|
||||
/**
|
||||
* Add a {@code RANGE} frame clause to the window and define
|
||||
* start and end {@link JpaWindowFrame} specifications.
|
||||
*
|
||||
* @param startFrame the start frame
|
||||
* @param endFrame the optional end frame
|
||||
*
|
||||
* @return the modified window
|
||||
*/
|
||||
JpaWindow frameRange(JpaWindowFrame startFrame, JpaWindowFrame endFrame);
|
||||
|
||||
/**
|
||||
* Add a {@code GROUPS} frame clause to the window and define
|
||||
* start and end {@link JpaWindowFrame} specifications.
|
||||
*
|
||||
* @param startFrame the start frame
|
||||
* @param endFrame the optional end frame
|
||||
*
|
||||
* @return the modified window
|
||||
*/
|
||||
JpaWindow frameGroups(JpaWindowFrame startFrame, JpaWindowFrame endFrame);
|
||||
|
||||
/**
|
||||
* Set a {@link FrameExclusion} for this window's frame.
|
||||
*
|
||||
* @param frameExclusion the frame exclusion
|
||||
*
|
||||
* @return the modified window
|
||||
*/
|
||||
JpaWindow frameExclude(FrameExclusion frameExclusion);
|
||||
}
|
||||
|
|
|
@ -11,10 +11,22 @@ import org.hibernate.query.sqm.FrameKind;
|
|||
import jakarta.persistence.criteria.Expression;
|
||||
|
||||
/**
|
||||
* Common contract for a {@link JpaWindow} frame specification.
|
||||
*
|
||||
* @author Marco Belladelli
|
||||
*/
|
||||
public interface JpaWindowFrame {
|
||||
/**
|
||||
* Get the {@link FrameKind} of this window frame.
|
||||
*
|
||||
* @return the window frame kind
|
||||
*/
|
||||
FrameKind getKind();
|
||||
|
||||
/**
|
||||
* Get the {@link Expression} of this window frame.
|
||||
*
|
||||
* @return the window frame expression
|
||||
*/
|
||||
Expression<?> getExpression();
|
||||
}
|
||||
|
|
|
@ -2643,7 +2643,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
|
||||
@Override
|
||||
public <T> SqmExpression<T> nthValue(Expression<T> argument, int n, JpaWindow window) {
|
||||
return nthValue( argument, value( n ), window );
|
||||
return nthValue( argument, literal( n ), window );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -10,8 +10,11 @@ import java.util.Arrays;
|
|||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.dialect.DB2Dialect;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.dialect.PostgreSQLDialect;
|
||||
import org.hibernate.dialect.PostgresPlusDialect;
|
||||
import org.hibernate.dialect.SQLServerDialect;
|
||||
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
|
||||
import org.hibernate.query.criteria.JpaExpression;
|
||||
import org.hibernate.query.criteria.JpaWindow;
|
||||
|
@ -46,7 +49,6 @@ import static org.junit.jupiter.api.Assertions.assertNull;
|
|||
@DomainModel(standardModels = StandardDomainModel.GAMBIT)
|
||||
@SessionFactory
|
||||
public class CriteriaOrderedSetAggregateTest {
|
||||
|
||||
@BeforeEach
|
||||
public void prepareData(SessionFactoryScope scope) {
|
||||
scope.inTransaction( em -> {
|
||||
|
@ -104,7 +106,7 @@ public class CriteriaOrderedSetAggregateTest {
|
|||
|
||||
@AfterEach
|
||||
public void tearDown(SessionFactoryScope scope) {
|
||||
scope.inTransaction( session -> session.createQuery( "delete from EntityOfBasics" ).executeUpdate() );
|
||||
scope.inTransaction( session -> session.createMutationQuery( "delete from EntityOfBasics" ).executeUpdate() );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -229,7 +231,7 @@ public class CriteriaOrderedSetAggregateTest {
|
|||
cb.literal( 0.5 ),
|
||||
root.get( "theInt" ),
|
||||
SortOrder.ASCENDING,
|
||||
NullPrecedence.FIRST
|
||||
NullPrecedence.NONE
|
||||
);
|
||||
|
||||
cr.select( function );
|
||||
|
@ -242,8 +244,9 @@ public class CriteriaOrderedSetAggregateTest {
|
|||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsInverseDistributionFunctions.class)
|
||||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsWindowFunctions.class)
|
||||
@SkipForDialect(dialectClass = PostgreSQLDialect.class)
|
||||
@SkipForDialect(dialectClass = PostgresPlusDialect.class)
|
||||
public void testInverseDistributionWithWindow(SessionFactoryScope scope) {
|
||||
// note : PostgreSQL currently does not support ordered-set aggregate functions with OVER clause
|
||||
// note : PostgreSQL and EDB currently does not support ordered-set aggregate functions with OVER clause
|
||||
scope.inTransaction( session -> {
|
||||
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
|
||||
CriteriaQuery<Integer> cr = cb.createQuery( Integer.class );
|
||||
|
@ -255,7 +258,7 @@ public class CriteriaOrderedSetAggregateTest {
|
|||
window,
|
||||
root.get( "theInt" ),
|
||||
SortOrder.ASCENDING,
|
||||
NullPrecedence.FIRST
|
||||
NullPrecedence.NONE
|
||||
);
|
||||
|
||||
cr.select( function ).orderBy( cb.asc( cb.literal( 1 ) ) );
|
||||
|
@ -301,9 +304,12 @@ public class CriteriaOrderedSetAggregateTest {
|
|||
} );
|
||||
}
|
||||
|
||||
// @Test
|
||||
@Test
|
||||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsHypotheticalSetFunctions.class)
|
||||
@SkipForDialect(dialectClass = SQLServerDialect.class)
|
||||
@SkipForDialect(dialectClass = DB2Dialect.class)
|
||||
public void testHypotheticalSetRankWithGroupByHavingOrderByLimit(SessionFactoryScope scope) {
|
||||
// note : this query is not translated correctly for SQLServer and DB2, skip for now
|
||||
scope.inTransaction( session -> {
|
||||
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
|
||||
CriteriaQuery<Tuple> cr = cb.createQuery( Tuple.class );
|
||||
|
@ -316,11 +322,6 @@ public class CriteriaOrderedSetAggregateTest {
|
|||
.groupBy( root2.get( "id" ) ).having( cb.gt( root2.get( "id" ), cb.literal( 1 ) ) )
|
||||
.orderBy( cb.asc( cb.literal( 1 ) ), cb.asc( cb.literal( 2 ) ) );
|
||||
|
||||
// todo marco : this test causes problems but only with mssql and db2, the sql obtained is not correct.
|
||||
// we are trying to get something like this query:
|
||||
// select eob2.id, rank(5) within group (order by eob.theInt asc) from EntityOfBasics eob
|
||||
// cross join EntityOfBasics eob2 group by eob2.id having eob2.id > 1 order by 1,2 offset 1
|
||||
|
||||
List<Tuple> resultList = session.createQuery( cr ).setFirstResult( 1 ).getResultList();
|
||||
assertEquals( 3, resultList.size() );
|
||||
assertEquals( 1L, resultList.get( 0 ).get( 1, Long.class ) );
|
||||
|
|
|
@ -9,7 +9,6 @@ package org.hibernate.orm.test.query.criteria;
|
|||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.dialect.DB2Dialect;
|
||||
import org.hibernate.dialect.SQLServerDialect;
|
||||
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
|
||||
import org.hibernate.query.criteria.JpaExpression;
|
||||
|
@ -104,7 +103,7 @@ public class CriteriaWindowFunctionTest {
|
|||
@AfterEach
|
||||
public void tearDown(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> session.createQuery( "delete from EntityOfBasics" ).executeUpdate()
|
||||
session -> session.createMutationQuery( "delete from EntityOfBasics" ).executeUpdate()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -156,28 +155,27 @@ public class CriteriaWindowFunctionTest {
|
|||
|
||||
@Test
|
||||
@SkipForDialect(dialectClass = SQLServerDialect.class)
|
||||
@SkipForDialect(dialectClass = DB2Dialect.class)
|
||||
public void testNthValue(SessionFactoryScope scope) {
|
||||
// note : SQLServer does not support nth_value function
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
|
||||
CriteriaQuery<Integer> cr = cb.createQuery( Integer.class );
|
||||
Root<EntityOfBasics> root = cr.from( EntityOfBasics.class );
|
||||
|
||||
JpaWindow window = cb.createWindow().orderBy( cb.desc( root.get( "theInt" ) ) );
|
||||
JpaWindow window = cb.createWindow()
|
||||
.orderBy( cb.desc( root.get( "theInt" ) ) )
|
||||
.frameRows( cb.frameUnboundedPreceding(), cb.frameUnboundedFollowing() );
|
||||
JpaExpression<Integer> nthValue = cb.nthValue(
|
||||
root.get( "theInt" ),
|
||||
2,
|
||||
window
|
||||
);
|
||||
|
||||
// todo marco : db2 throws java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 1
|
||||
// on getResultList() line, and SqlServer doesn't support nth_value function (even tho it's in Dialect)
|
||||
|
||||
cr.select( nthValue ).orderBy( cb.asc( cb.literal( 1 ), true ) );
|
||||
cr.select( nthValue );
|
||||
List<Integer> resultList = session.createQuery( cr ).getResultList();
|
||||
assertEquals( 5, resultList.size() );
|
||||
assertNull( resultList.get( 0 ) );
|
||||
assertEquals( 7, resultList.get( 0 ) );
|
||||
assertEquals( 7, resultList.get( 1 ) );
|
||||
assertEquals( 7, resultList.get( 2 ) );
|
||||
assertEquals( 7, resultList.get( 3 ) );
|
||||
|
|
Loading…
Reference in New Issue