99import java .util .List ;
1010
1111import org .hibernate .query .ReturnableType ;
12+ import org .hibernate .query .sqm .function .SelfRenderingOrderedSetAggregateFunctionSqlAstExpression ;
13+ import org .hibernate .sql .ast .Clause ;
14+ import org .hibernate .sql .ast .SqlAstNodeRenderingMode ;
1215import org .hibernate .sql .ast .SqlAstTranslator ;
1316import org .hibernate .sql .ast .spi .SqlAppender ;
1417import org .hibernate .sql .ast .tree .SqlAstNode ;
1518import org .hibernate .sql .ast .tree .expression .Expression ;
19+ import org .hibernate .sql .ast .tree .expression .FunctionExpression ;
20+ import org .hibernate .sql .ast .tree .predicate .Predicate ;
21+ import org .hibernate .sql .ast .tree .select .SortSpecification ;
22+ import org .hibernate .type .BasicPluralType ;
23+ import org .hibernate .type .SqlTypes ;
1624import org .hibernate .type .spi .TypeConfiguration ;
1725
1826/**
@@ -38,26 +46,99 @@ public void render(
3846 final Expression arrayExpression = (Expression ) sqlAstArguments .get ( 0 );
3947 final Expression separatorExpression = (Expression ) sqlAstArguments .get ( 1 );
4048 final Expression defaultExpression = sqlAstArguments .size () > 2 ? (Expression ) sqlAstArguments .get ( 2 ) : null ;
41- sqlAppender .append ( "case when " );
42- arrayExpression .accept ( walker );
43- sqlAppender .append ( " is not null then coalesce((select listagg(" );
44- if ( defaultExpression != null ) {
45- sqlAppender .append ( "coalesce(" );
49+ final BasicPluralType <?, ?> pluralType = (BasicPluralType <?, ?>) arrayExpression .getExpressionType ().getSingleJdbcMapping ();
50+ final int ddlTypeCode = pluralType .getElementType ().getJdbcType ().getDdlTypeCode ();
51+ final boolean needsCast = !SqlTypes .isStringType ( ddlTypeCode );
52+ if ( arrayExpression instanceof SelfRenderingOrderedSetAggregateFunctionSqlAstExpression
53+ && ArrayAggFunction .FUNCTION_NAME .equals ( ( (FunctionExpression ) arrayExpression ).getFunctionName () ) ) {
54+ final SelfRenderingOrderedSetAggregateFunctionSqlAstExpression functionExpression
55+ = (SelfRenderingOrderedSetAggregateFunctionSqlAstExpression ) arrayExpression ;
56+ // When the array argument is an aggregate expression, we access its contents directly
57+ final Expression arrayElementExpression = (Expression ) functionExpression .getArguments ().get ( 0 );
58+ final List <SortSpecification > withinGroup = functionExpression .getWithinGroup ();
59+ final Predicate filter = functionExpression .getFilter ();
60+
61+ sqlAppender .append ( "listagg(" );
62+ if ( defaultExpression != null ) {
63+ sqlAppender .append ( "coalesce(" );
64+ }
65+ if ( needsCast ) {
66+ if ( ddlTypeCode == SqlTypes .BOOLEAN ) {
67+ // By default, H2 uses upper case, so lower it for a consistent experience
68+ sqlAppender .append ( "lower(" );
69+ }
70+ sqlAppender .append ( "cast(" );
71+ }
72+ arrayElementExpression .accept ( walker );
73+ if ( needsCast ) {
74+ sqlAppender .append ( " as varchar)" );
75+ if ( ddlTypeCode == SqlTypes .BOOLEAN ) {
76+ sqlAppender .append ( ')' );
77+ }
78+ }
79+ if ( defaultExpression != null ) {
80+ sqlAppender .append ( ',' );
81+ defaultExpression .accept ( walker );
82+ sqlAppender .append ( ')' );
83+ }
84+ sqlAppender .append ( "," );
85+ walker .render ( separatorExpression , SqlAstNodeRenderingMode .DEFAULT );
86+ sqlAppender .appendSql ( ')' );
87+
88+ if ( withinGroup != null && !withinGroup .isEmpty () ) {
89+ walker .getCurrentClauseStack ().push ( Clause .WITHIN_GROUP );
90+ sqlAppender .appendSql ( " within group (order by " );
91+ withinGroup .get ( 0 ).accept ( walker );
92+ for ( int i = 1 ; i < withinGroup .size (); i ++ ) {
93+ sqlAppender .appendSql ( ',' );
94+ withinGroup .get ( i ).accept ( walker );
95+ }
96+ sqlAppender .appendSql ( ')' );
97+ walker .getCurrentClauseStack ().pop ();
98+ }
99+ if ( filter != null ) {
100+ walker .getCurrentClauseStack ().push ( Clause .WHERE );
101+ sqlAppender .appendSql ( " filter (where " );
102+ filter .accept ( walker );
103+ sqlAppender .appendSql ( ')' );
104+ walker .getCurrentClauseStack ().pop ();
105+ }
46106 }
47- sqlAppender .append ( "array_get(" );
48- arrayExpression .accept ( walker );
49- sqlAppender .append (",i.idx)" );
50- if ( defaultExpression != null ) {
107+ else {
108+ sqlAppender .append ( "case when " );
109+ arrayExpression .accept ( walker );
110+ sqlAppender .append ( " is not null then coalesce((select listagg(" );
111+ if ( defaultExpression != null ) {
112+ sqlAppender .append ( "coalesce(" );
113+ }
114+ if ( needsCast ) {
115+ if ( ddlTypeCode == SqlTypes .BOOLEAN ) {
116+ // By default, H2 uses upper case, so lower it for a consistent experience
117+ sqlAppender .append ( "lower(" );
118+ }
119+ sqlAppender .append ( "cast(" );
120+ }
121+ sqlAppender .append ( "array_get(" );
122+ arrayExpression .accept ( walker );
123+ sqlAppender .append ( ",i.idx)" );
124+ if ( needsCast ) {
125+ sqlAppender .append ( " as varchar)" );
126+ if ( ddlTypeCode == SqlTypes .BOOLEAN ) {
127+ sqlAppender .append ( ')' );
128+ }
129+ }
130+ if ( defaultExpression != null ) {
131+ sqlAppender .append ( ',' );
132+ defaultExpression .accept ( walker );
133+ sqlAppender .append ( ')' );
134+ }
51135 sqlAppender .append ( "," );
52- defaultExpression .accept ( walker );
53- sqlAppender .append ( ")" );
136+ walker .render ( separatorExpression , SqlAstNodeRenderingMode .DEFAULT );
137+ sqlAppender .append ( ") within group (order by i.idx) from system_range(1," );
138+ sqlAppender .append ( Integer .toString ( maximumArraySize ) );
139+ sqlAppender .append ( ") i(idx) where i.idx<=coalesce(cardinality(" );
140+ arrayExpression .accept ( walker );
141+ sqlAppender .append ( "),0)),'') end" );
54142 }
55- sqlAppender .append ("," );
56- separatorExpression .accept ( walker );
57- sqlAppender .append ( ") within group (order by i.idx) from system_range(1," );
58- sqlAppender .append ( Integer .toString ( maximumArraySize ) );
59- sqlAppender .append ( ") i(idx) where i.idx<=coalesce(cardinality(" );
60- arrayExpression .accept ( walker );
61- sqlAppender .append ("),0)),'') end" );
62143 }
63144}
0 commit comments