9
9
import java .util .List ;
10
10
11
11
import 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 ;
12
15
import org .hibernate .sql .ast .SqlAstTranslator ;
13
16
import org .hibernate .sql .ast .spi .SqlAppender ;
14
17
import org .hibernate .sql .ast .tree .SqlAstNode ;
15
18
import 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 ;
16
24
import org .hibernate .type .spi .TypeConfiguration ;
17
25
18
26
/**
@@ -38,26 +46,99 @@ public void render(
38
46
final Expression arrayExpression = (Expression ) sqlAstArguments .get ( 0 );
39
47
final Expression separatorExpression = (Expression ) sqlAstArguments .get ( 1 );
40
48
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
+ }
46
106
}
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
+ }
51
135
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" );
54
142
}
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" );
62
143
}
63
144
}
0 commit comments