66
77import java .util .List ;
88
9+ import org .hibernate .metamodel .mapping .JdbcMappingContainer ;
910import org .hibernate .metamodel .model .domain .ReturnableType ;
11+ import org .hibernate .query .sqm .function .SelfRenderingOrderedSetAggregateFunctionSqlAstExpression ;
12+ import org .hibernate .sql .ast .Clause ;
1013import org .hibernate .sql .ast .SqlAstTranslator ;
1114import org .hibernate .sql .ast .spi .SqlAppender ;
1215import org .hibernate .sql .ast .tree .SqlAstNode ;
1316import 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 ;
1421import org .hibernate .type .spi .TypeConfiguration ;
1522
23+ import org .checkerframework .checker .nullness .qual .Nullable ;
24+
1625/**
1726 * Oracle array_to_string function.
1827 */
@@ -28,22 +37,89 @@ public void render(
2837 List <? extends SqlAstNode > sqlAstArguments ,
2938 ReturnableType <?> returnType ,
3039 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+ }
4173 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)" );
43104 }
44105 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 ( ')' );
46123 }
47- sqlAppender .append ( ')' );
48124 }
49125}
0 commit comments