5353import org .hibernate .sql .ast .tree .from .TableGroupJoin ;
5454import org .hibernate .sql .ast .tree .predicate .ComparisonPredicate ;
5555import org .hibernate .sql .ast .tree .predicate .Predicate ;
56+ import org .hibernate .sql .ast .tree .predicate .PredicateContainer ;
5657import org .hibernate .sql .ast .tree .select .QuerySpec ;
5758import org .hibernate .type .BasicType ;
5859import org .hibernate .type .SqlTypes ;
@@ -153,12 +154,31 @@ public QuerySpec transform(CteContainer cteContainer, QuerySpec querySpec, SqmTo
153154 final TableGroup parentTableGroup = querySpec .getFromClause ().queryTableGroups (
154155 tg -> tg .findTableGroupJoin ( functionTableGroup ) == null ? null : tg
155156 );
156- final TableGroupJoin join = parentTableGroup .findTableGroupJoin ( functionTableGroup );
157+ final PredicateContainer predicateContainer ;
158+ if ( parentTableGroup != null ) {
159+ predicateContainer = parentTableGroup .findTableGroupJoin ( functionTableGroup );
160+ }
161+ else {
162+ predicateContainer = querySpec ;
163+ }
157164 final BasicType <Integer > integerType = converter .getCreationContext ()
158165 .getSessionFactory ()
159166 .getNodeBuilder ()
160167 .getIntegerType ();
161- final Expression lhs = new ArrayLengthExpression ( arguments .jsonDocument (), integerType );
168+ final Expression jsonDocument ;
169+ if ( arguments .jsonDocument ().getColumnReference () == null ) {
170+ jsonDocument = new ColumnReference (
171+ functionTableGroup .getPrimaryTableReference ().getIdentificationVariable () + "_" ,
172+ "d" ,
173+ false ,
174+ null ,
175+ arguments .jsonDocument ().getExpressionType ().getSingleJdbcMapping ()
176+ );
177+ }
178+ else {
179+ jsonDocument = arguments .jsonDocument ();
180+ }
181+ final Expression lhs = new ArrayLengthExpression ( jsonDocument , integerType );
162182 final Expression rhs = new ColumnReference (
163183 functionTableGroup .getPrimaryTableReference ().getIdentificationVariable (),
164184 // The default column name for the system_range function
@@ -167,7 +187,7 @@ public QuerySpec transform(CteContainer cteContainer, QuerySpec querySpec, SqmTo
167187 null ,
168188 integerType
169189 );
170- join .applyPredicate (
190+ predicateContainer .applyPredicate (
171191 new ComparisonPredicate ( lhs , ComparisonOperator .GREATER_THAN_OR_EQUAL , rhs ) );
172192 }
173193 final int lastArrayIndex = getLastArrayIndex ( arguments .columnsClause (), 0 );
@@ -176,6 +196,19 @@ public QuerySpec transform(CteContainer cteContainer, QuerySpec querySpec, SqmTo
176196 // for every nested path for arrays
177197 final String tableIdentifierVariable = functionTableGroup .getPrimaryTableReference ()
178198 .getIdentificationVariable ();
199+ final Expression jsonDocument ;
200+ if ( arguments .jsonDocument ().getColumnReference () == null ) {
201+ jsonDocument = new ColumnReference (
202+ tableIdentifierVariable + "_" ,
203+ "d" ,
204+ false ,
205+ null ,
206+ arguments .jsonDocument ().getExpressionType ().getSingleJdbcMapping ()
207+ );
208+ }
209+ else {
210+ jsonDocument = arguments .jsonDocument ();
211+ }
179212 final TableGroup tableGroup = new FunctionTableGroup (
180213 functionTableGroup .getNavigablePath ().append ( "{synthetic}" ),
181214 null ,
@@ -184,6 +217,7 @@ public QuerySpec transform(CteContainer cteContainer, QuerySpec querySpec, SqmTo
184217 new NestedPathFunctionRenderer (
185218 tableIdentifierVariable ,
186219 arguments ,
220+ jsonDocument ,
187221 maximumArraySize ,
188222 lastArrayIndex
189223 ),
@@ -207,7 +241,7 @@ public QuerySpec transform(CteContainer cteContainer, QuerySpec querySpec, SqmTo
207241 // The join predicate compares the length of the last array expression against system_range() index.
208242 // Since a table function expression can't render its own `on` clause, this split of logic is necessary
209243 final Expression lhs = new ArrayLengthExpression (
210- determineLastArrayExpression ( tableIdentifierVariable , arguments ),
244+ determineLastArrayExpression ( tableIdentifierVariable , arguments , jsonDocument ),
211245 integerType
212246 );
213247 final Expression rhs = new ColumnReference (
@@ -226,10 +260,10 @@ public QuerySpec transform(CteContainer cteContainer, QuerySpec querySpec, SqmTo
226260 return querySpec ;
227261 }
228262
229- private static Expression determineLastArrayExpression (String tableIdentifierVariable , JsonTableArguments arguments ) {
263+ private static Expression determineLastArrayExpression (String tableIdentifierVariable , JsonTableArguments arguments , Expression jsonDocument ) {
230264 final ArrayExpressionEntry arrayExpressionEntry = determineLastArrayExpression (
231265 tableIdentifierVariable ,
232- determineJsonElement ( tableIdentifierVariable , arguments ),
266+ determineJsonElement ( tableIdentifierVariable , arguments , jsonDocument ),
233267 arguments .columnsClause (),
234268 new ArrayExpressionEntry ( 0 , null )
235269 );
@@ -253,7 +287,7 @@ private static ArrayExpressionEntry determineLastArrayExpression(String tableIde
253287 final ArrayExpressionEntry nextArrayExpression ;
254288 if ( isArray ) {
255289 final int nextArrayIndex = currentArrayEntry .arrayIndex () + 1 ;
256- jsonElement = new ArrayAccessExpression ( jsonQueryResult , tableIdentifierVariable + "_" + nextArrayIndex + "_.x" );
290+ jsonElement = new ArrayAccessExpression ( jsonQueryResult , ordinalityExpression ( tableIdentifierVariable , nextArrayIndex ) );
257291 nextArrayExpression = new ArrayExpressionEntry ( nextArrayIndex , jsonQueryResult );
258292 }
259293 else {
@@ -271,10 +305,9 @@ private static ArrayExpressionEntry determineLastArrayExpression(String tableIde
271305 return currentArrayEntry ;
272306 }
273307
274- private static Expression determineJsonElement (String tableIdentifierVariable , JsonTableArguments arguments ) {
308+ private static Expression determineJsonElement (String tableIdentifierVariable , JsonTableArguments arguments , Expression jsonDocument ) {
275309 // Applies the json path and array index access to obtain the "current" processing element
276310
277- final Expression jsonDocument = arguments .jsonDocument ();
278311 final boolean isArray ;
279312 final Expression jsonQueryResult ;
280313 if ( arguments .jsonPath () != null ) {
@@ -309,19 +342,21 @@ private static Expression determineJsonElement(String tableIdentifierVariable, J
309342 private static class NestedPathFunctionRenderer implements FunctionRenderer {
310343 private final String tableIdentifierVariable ;
311344 private final JsonTableArguments arguments ;
345+ private final Expression jsonDocument ;
312346 private final int maximumArraySize ;
313347 private final int lastArrayIndex ;
314348
315- public NestedPathFunctionRenderer (String tableIdentifierVariable , JsonTableArguments arguments , int maximumArraySize , int lastArrayIndex ) {
349+ public NestedPathFunctionRenderer (String tableIdentifierVariable , JsonTableArguments arguments , Expression jsonDocument , int maximumArraySize , int lastArrayIndex ) {
316350 this .tableIdentifierVariable = tableIdentifierVariable ;
317351 this .arguments = arguments ;
352+ this .jsonDocument = jsonDocument ;
318353 this .maximumArraySize = maximumArraySize ;
319354 this .lastArrayIndex = lastArrayIndex ;
320355 }
321356
322357 @ Override
323358 public void render (SqlAppender sqlAppender , List <? extends SqlAstNode > sqlAstArguments , ReturnableType <?> returnType , SqlAstTranslator <?> walker ) {
324- final Expression jsonElement = determineJsonElement ( tableIdentifierVariable , arguments );
359+ final Expression jsonElement = determineJsonElement ( tableIdentifierVariable , arguments , jsonDocument );
325360 renderNestedColumnJoins ( sqlAppender , tableIdentifierVariable , jsonElement , arguments .columnsClause (), 0 , lastArrayIndex , walker );
326361 }
327362
@@ -352,17 +387,15 @@ private int renderNestedColumnJoins(SqlAppender sqlAppender, String tableIdentif
352387 sqlAppender .appendSql ( nextArrayIndex );
353388 sqlAppender .appendSql ( '_' );
354389
390+ final String ordinalityExpression = ordinalityExpression ( tableIdentifierVariable , nextArrayIndex );
355391 // The join condition for the last array will be rendered via TableGroupJoin
356392 if ( nextArrayIndex != lastArrayIndex ) {
357393 sqlAppender .appendSql ( " on coalesce(array_length(" );
358394 jsonQueryResult .accept ( walker );
359395 sqlAppender .append ( "),0)>=" );
360- sqlAppender .appendSql ( tableIdentifierVariable );
361- sqlAppender .appendSql ( '_' );
362- sqlAppender .appendSql ( nextArrayIndex );
363- sqlAppender .appendSql ( "_.x" );
396+ sqlAppender .appendSql ( ordinalityExpression );
364397 }
365- jsonElement = new ArrayAccessExpression ( jsonQueryResult , tableIdentifierVariable + "_" + nextArrayIndex + "_.x" );
398+ jsonElement = new ArrayAccessExpression ( jsonQueryResult , ordinalityExpression );
366399 }
367400 else {
368401 jsonElement = jsonQueryResult ;
@@ -383,6 +416,12 @@ private int renderNestedColumnJoins(SqlAppender sqlAppender, String tableIdentif
383416 }
384417 }
385418
419+ @ Override
420+ public boolean rendersIdentifierVariable (List <SqlAstNode > arguments , SessionFactoryImplementor sessionFactory ) {
421+ // To make our lives simpler when supporting non-column JSON document arguments
422+ return true ;
423+ }
424+
386425 @ Override
387426 protected void renderJsonTable (
388427 SqlAppender sqlAppender ,
@@ -397,13 +436,27 @@ protected void renderJsonTable(
397436 final Expression jsonPathExpression = arguments .jsonPath ();
398437 final boolean isArray = isArrayAccess ( jsonPathExpression , walker );
399438
439+ if ( arguments .jsonDocument ().getColumnReference () == null ) {
440+ sqlAppender .append ( '(' );
441+ }
400442 if ( isArray ) {
401443 sqlAppender .append ( "system_range(1," );
402444 sqlAppender .append ( Integer .toString ( maximumArraySize ) );
403- sqlAppender .append ( ")" );
445+ sqlAppender .append ( ") " );
404446 }
405447 else {
406- sqlAppender .append ( "system_range(1,1)" );
448+ sqlAppender .append ( "system_range(1,1) " );
449+ }
450+ sqlAppender .append ( tableIdentifierVariable );
451+ if ( arguments .jsonDocument ().getColumnReference () == null ) {
452+ sqlAppender .append ( " join (values (" );
453+ arguments .jsonDocument ().accept ( walker );
454+ if ( !arguments .isJsonType () ) {
455+ sqlAppender .append ( " format json" );
456+ }
457+ sqlAppender .append ( ")) " );
458+ sqlAppender .append ( tableIdentifierVariable );
459+ sqlAppender .append ( "_(d) on 1=1)" );
407460 }
408461 }
409462
@@ -526,6 +579,13 @@ public JdbcMappingContainer getExpressionType() {
526579 }
527580 }
528581
582+ private static String ordinalityExpression (String tableIdentifierVariable , int clauseLevel ) {
583+ if ( clauseLevel == 0 ) {
584+ return tableIdentifierVariable + ".x" ;
585+ }
586+ return tableIdentifierVariable + "_" + clauseLevel + "_.x" ;
587+ }
588+
529589 /**
530590 * This type resolver essentially implements all the JSON path handling and casting via column read expressions
531591 * instead of rendering to the {@code from} clause like other {@code json_table()} implementations.
@@ -545,10 +605,15 @@ public SelectableMapping[] resolveFunctionReturnType(
545605 boolean withOrdinality ,
546606 SqmToSqlAstConverter converter ) {
547607 final JsonTableArguments arguments = JsonTableArguments .extract ( sqlAstNodes );
548- final ColumnReference columnReference = arguments .jsonDocument ().getColumnReference ();
549- assert columnReference != null ;
550-
551- final String documentPath = columnReference .getExpressionText ();
608+ final Expression jsonDocument = arguments .jsonDocument ();
609+ final String documentPath ;
610+ final ColumnReference columnReference = jsonDocument .getColumnReference ();
611+ if ( columnReference != null ) {
612+ documentPath = columnReference .getExpressionText ();
613+ }
614+ else {
615+ documentPath = tableIdentifierVariable + "_." + "d" ;
616+ }
552617
553618 final String parentPath ;
554619 final boolean isArray ;
@@ -620,7 +685,7 @@ protected int addSelectableMappings(List<SelectableMapping> selectableMappings,
620685 final String readExpression ;
621686 if ( isArray ) {
622687 nextClauseLevel = clauseLevel + 1 ;
623- readExpression = "array_get(" + parentPath + "," + tableIdentifierVariable + "_" + nextClauseLevel + "_.x )" ;
688+ readExpression = "array_get(" + parentPath + "," + ordinalityExpression ( tableIdentifierVariable , nextClauseLevel ) + " )" ;
624689 }
625690 else {
626691 nextClauseLevel = clauseLevel ;
@@ -633,7 +698,7 @@ protected void addSelectableMappings(List<SelectableMapping> selectableMappings,
633698 addSelectableMapping (
634699 selectableMappings ,
635700 definition .name (),
636- tableIdentifierVariable + "_" + clauseLevel + "_.x" ,
701+ ordinalityExpression ( tableIdentifierVariable , clauseLevel ) ,
637702 converter .getCreationContext ().getTypeConfiguration ().getBasicTypeForJavaType ( Long .class )
638703 );
639704 }
0 commit comments