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