88
99import java .util .List ;
1010
11+ import org .hibernate .metamodel .mapping .JdbcMappingContainer ;
1112import 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 ;
1615import org .hibernate .sql .ast .SqlAstTranslator ;
1716import org .hibernate .sql .ast .spi .SqlAppender ;
1817import org .hibernate .sql .ast .tree .SqlAstNode ;
1918import 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 ;
2023import org .hibernate .type .spi .TypeConfiguration ;
2124
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 ;
2426
2527/**
2628 * Oracle array_to_string function.
@@ -37,22 +39,89 @@ public void render(
3739 List <? extends SqlAstNode > sqlAstArguments ,
3840 ReturnableType <?> returnType ,
3941 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+ }
5075 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)" );
52106 }
53107 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 ( ')' );
55125 }
56- sqlAppender .append ( ')' );
57126 }
58127}
0 commit comments