6
6
7
7
import java .util .List ;
8
8
9
+ import org .hibernate .metamodel .mapping .JdbcMappingContainer ;
9
10
import org .hibernate .metamodel .model .domain .ReturnableType ;
11
+ import org .hibernate .query .sqm .function .SelfRenderingOrderedSetAggregateFunctionSqlAstExpression ;
12
+ import org .hibernate .sql .ast .Clause ;
10
13
import org .hibernate .sql .ast .SqlAstTranslator ;
11
14
import org .hibernate .sql .ast .spi .SqlAppender ;
12
15
import org .hibernate .sql .ast .tree .SqlAstNode ;
13
16
import org .hibernate .sql .ast .tree .expression .Expression ;
17
+ import org .hibernate .sql .ast .tree .expression .FunctionExpression ;
18
+ import org .hibernate .sql .ast .tree .predicate .Predicate ;
19
+ import org .hibernate .sql .ast .tree .select .SortSpecification ;
20
+ import org .hibernate .type .SqlTypes ;
14
21
import org .hibernate .type .spi .TypeConfiguration ;
15
22
23
+ import org .checkerframework .checker .nullness .qual .Nullable ;
24
+
16
25
/**
17
26
* Oracle array_to_string function.
18
27
*/
@@ -28,22 +37,89 @@ public void render(
28
37
List <? extends SqlAstNode > sqlAstArguments ,
29
38
ReturnableType <?> returnType ,
30
39
SqlAstTranslator <?> walker ) {
31
- final String arrayTypeName = DdlTypeHelper .getTypeName (
32
- ( (Expression ) sqlAstArguments .get ( 0 ) ).getExpressionType (),
33
- walker .getSessionFactory ().getTypeConfiguration ()
34
- );
35
- sqlAppender .append ( arrayTypeName );
36
- sqlAppender .append ( "_to_string(" );
37
- sqlAstArguments .get ( 0 ).accept ( walker );
38
- sqlAppender .append ( ',' );
39
- sqlAstArguments .get ( 1 ).accept ( walker );
40
- if ( sqlAstArguments .size () > 2 ) {
40
+ final Expression arrayExpression = (Expression ) sqlAstArguments .get ( 0 );
41
+ final JdbcMappingContainer expressionType = (arrayExpression ).getExpressionType ();
42
+ if ( arrayExpression instanceof SelfRenderingOrderedSetAggregateFunctionSqlAstExpression
43
+ && ArrayAggFunction .FUNCTION_NAME .equals ( ( (FunctionExpression ) arrayExpression ).getFunctionName () ) ) {
44
+ final SelfRenderingOrderedSetAggregateFunctionSqlAstExpression functionExpression
45
+ = (SelfRenderingOrderedSetAggregateFunctionSqlAstExpression ) arrayExpression ;
46
+ // When the array argument is an aggregate expression, we access its contents directly
47
+ final Expression arrayElementExpression = (Expression ) functionExpression .getArguments ().get ( 0 );
48
+ final @ Nullable Expression defaultExpression =
49
+ sqlAstArguments .size () > 2 ? (Expression ) sqlAstArguments .get ( 2 ) : null ;
50
+ final List <SortSpecification > withinGroup = functionExpression .getWithinGroup ();
51
+ final Predicate filter = functionExpression .getFilter ();
52
+
53
+ sqlAppender .append ( "listagg(" );
54
+ if ( filter != null ) {
55
+ sqlAppender .appendSql ( "case when " );
56
+ walker .getCurrentClauseStack ().push ( Clause .WHERE );
57
+ filter .accept ( walker );
58
+ walker .getCurrentClauseStack ().pop ();
59
+ sqlAppender .appendSql ( " then " );
60
+ }
61
+ if ( defaultExpression != null ) {
62
+ sqlAppender .append ( "coalesce(" );
63
+ }
64
+ arrayElementExpression .accept ( walker );
65
+ if ( defaultExpression != null ) {
66
+ sqlAppender .append ( ',' );
67
+ defaultExpression .accept ( walker );
68
+ sqlAppender .append ( ')' );
69
+ }
70
+ if ( filter != null ) {
71
+ sqlAppender .appendSql ( " else null end" );
72
+ }
41
73
sqlAppender .append ( ',' );
42
- sqlAstArguments .get ( 2 ).accept ( walker );
74
+ sqlAstArguments .get ( 1 ).accept ( walker );
75
+ sqlAppender .appendSql ( ')' );
76
+
77
+ if ( withinGroup != null && !withinGroup .isEmpty () ) {
78
+ walker .getCurrentClauseStack ().push ( Clause .WITHIN_GROUP );
79
+ sqlAppender .appendSql ( " within group (order by " );
80
+ withinGroup .get ( 0 ).accept ( walker );
81
+ for ( int i = 1 ; i < withinGroup .size (); i ++ ) {
82
+ sqlAppender .appendSql ( ',' );
83
+ withinGroup .get ( i ).accept ( walker );
84
+ }
85
+ sqlAppender .appendSql ( ')' );
86
+ walker .getCurrentClauseStack ().pop ();
87
+ }
88
+ }
89
+ else if ( expressionType .getSingleJdbcMapping ().getJdbcType ().getDefaultSqlTypeCode () == SqlTypes .JSON_ARRAY ) {
90
+ sqlAppender .append ( "(select listagg(" );
91
+ if ( sqlAstArguments .size () > 2 ) {
92
+ sqlAppender .append ( "coalesce(t.v," );
93
+ sqlAstArguments .get ( 2 ).accept ( walker );
94
+ sqlAppender .append ( ")," );
95
+ }
96
+ else {
97
+ sqlAppender .append ( "t.v," );
98
+ }
99
+
100
+ sqlAstArguments .get ( 1 ).accept ( walker );
101
+ sqlAppender .append ( ") from json_table(" );
102
+ sqlAstArguments .get ( 0 ).accept ( walker );
103
+ sqlAppender .append ( ",'$[*]' columns (v path '$')) t)" );
43
104
}
44
105
else {
45
- sqlAppender .append ( ",null" );
106
+ final String arrayTypeName = DdlTypeHelper .getTypeName (
107
+ expressionType ,
108
+ walker .getSessionFactory ().getTypeConfiguration ()
109
+ );
110
+ sqlAppender .append ( arrayTypeName );
111
+ sqlAppender .append ( "_to_string(" );
112
+ sqlAstArguments .get ( 0 ).accept ( walker );
113
+ sqlAppender .append ( ',' );
114
+ sqlAstArguments .get ( 1 ).accept ( walker );
115
+ if ( sqlAstArguments .size () > 2 ) {
116
+ sqlAppender .append ( ',' );
117
+ sqlAstArguments .get ( 2 ).accept ( walker );
118
+ }
119
+ else {
120
+ sqlAppender .append ( ",null" );
121
+ }
122
+ sqlAppender .append ( ')' );
46
123
}
47
- sqlAppender .append ( ')' );
48
124
}
49
125
}
0 commit comments