HHH-15360 Fix listagg rendering on older H2 versions

This commit is contained in:
Christian Beikov 2022-06-23 23:09:11 +02:00
parent 2b78f99ea8
commit 0864ca58a3
5 changed files with 33 additions and 4 deletions

View File

@ -315,11 +315,15 @@ public class H2Dialect extends Dialect {
functionFactory.rownum(); functionFactory.rownum();
if ( getVersion().isSameOrAfter( 1, 4, 200 ) ) { if ( getVersion().isSameOrAfter( 1, 4, 200 ) ) {
functionFactory.windowFunctions(); functionFactory.windowFunctions();
functionFactory.listagg( null );
if ( getVersion().isSameOrAfter( 2 ) ) { if ( getVersion().isSameOrAfter( 2 ) ) {
functionFactory.listagg( null );
functionFactory.inverseDistributionOrderedSetAggregates(); functionFactory.inverseDistributionOrderedSetAggregates();
functionFactory.hypotheticalOrderedSetAggregates(); functionFactory.hypotheticalOrderedSetAggregates();
} }
else {
// Use group_concat until 2.x as listagg was buggy
functionFactory.listagg_groupConcat();
}
} }
else { else {
functionFactory.listagg_groupConcat(); functionFactory.listagg_groupConcat();

View File

@ -12,6 +12,7 @@ import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.query.sqm.ComparisonOperator; import org.hibernate.query.sqm.ComparisonOperator;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode; import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.spi.SqlSelection;
@ -198,6 +199,12 @@ public class H2SqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstT
return getDialect().getVersion().isSameOrAfter( 1, 4, 197 ); return getDialect().getVersion().isSameOrAfter( 1, 4, 197 );
} }
@Override
protected boolean supportsNullPrecedence() {
// Support for nulls clause in listagg was added in 2.0
return getClauseStack().getCurrent() != Clause.WITHIN_GROUP || getDialect().getVersion().isSameOrAfter( 2 );
}
@Override @Override
protected String getFromDual() { protected String getFromDual() {
return " from dual"; return " from dual";

View File

@ -590,7 +590,7 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
@Override @Override
public boolean supportsNullPrecedence() { public boolean supportsNullPrecedence() {
return getVersion().isBefore( 10 ); return false;
} }
@Override @Override

View File

@ -2230,7 +2230,8 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
} }
final boolean renderNullPrecedence = nullPrecedence != null && final boolean renderNullPrecedence = nullPrecedence != null &&
!nullPrecedence.isDefaultOrdering( sortOrder, getDialect().getNullOrdering() ); !nullPrecedence.isDefaultOrdering( sortOrder, getDialect().getNullOrdering() );
if ( renderNullPrecedence && !getDialect().supportsNullPrecedence() ) { final boolean supportsNullPrecedence = renderNullPrecedence && supportsNullPrecedence();
if ( renderNullPrecedence && !supportsNullPrecedence ) {
emulateSortSpecificationNullPrecedence( sortExpression, nullPrecedence ); emulateSortSpecificationNullPrecedence( sortExpression, nullPrecedence );
} }
@ -2248,12 +2249,16 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
appendSql( " desc" ); appendSql( " desc" );
} }
if ( renderNullPrecedence && getDialect().supportsNullPrecedence() ) { if ( renderNullPrecedence && supportsNullPrecedence ) {
appendSql( " nulls " ); appendSql( " nulls " );
appendSql( nullPrecedence == NullPrecedence.LAST ? "last" : "first" ); appendSql( nullPrecedence == NullPrecedence.LAST ? "last" : "first" );
} }
} }
protected boolean supportsNullPrecedence() {
return getDialect().supportsNullPrecedence();
}
protected void emulateSortSpecificationNullPrecedence(Expression sortExpression, NullPrecedence nullPrecedence) { protected void emulateSortSpecificationNullPrecedence(Expression sortExpression, NullPrecedence nullPrecedence) {
// TODO: generate "virtual" select items and use them here positionally // TODO: generate "virtual" select items and use them here positionally
appendSql( "case when (" ); appendSql( "case when (" );

View File

@ -10,6 +10,7 @@ import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.domain.StandardDomainModel; import org.hibernate.testing.orm.domain.StandardDomainModel;
import org.hibernate.testing.orm.domain.gambit.EntityOfBasics; import org.hibernate.testing.orm.domain.gambit.EntityOfBasics;
import org.hibernate.testing.orm.junit.DialectFeatureChecks; import org.hibernate.testing.orm.junit.DialectFeatureChecks;
@ -136,6 +137,18 @@ public class OrderedSetAggregateTest {
); );
} }
@Test
@TestForIssue( jiraKey = "HHH-15360")
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsStringAggregation.class)
public void testListaggWithNullsClause(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
TypedQuery<String> q = session.createQuery( "select listagg(eob.theString, ',') within group (order by eob.id desc nulls first) from EntityOfBasics eob", String.class );
assertEquals( "5,13,7,6,5", q.getSingleResult() );
}
);
}
@Test @Test
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsInverseDistributionFunctions.class) @RequiresDialectFeature(feature = DialectFeatureChecks.SupportsInverseDistributionFunctions.class)
public void testInverseDistribution(SessionFactoryScope scope) { public void testInverseDistribution(SessionFactoryScope scope) {