Skip to content

Commit 854a982

Browse files
committed
HHH-18758 Add json_table() set-returning function
1 parent 3deb8a5 commit 854a982

File tree

99 files changed

+6450
-759
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

99 files changed

+6450
-759
lines changed

documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1677,18 +1677,19 @@ it is necessary to enable the `hibernate.query.hql.json_functions_enabled` confi
16771677
|===
16781678
| Function | Purpose
16791679
1680-
| `json_object()` | Constructs a JSON object from pairs of key and value arguments
1681-
| `json_array()` | Constructs a JSON array from arguments
1682-
| `json_value()` | Extracts a value from a JSON document by JSON path
1683-
| `json_exists()` | Checks if a JSON path exists in a JSON document
1684-
| `json_query()` | Queries non-scalar values by JSON path in a JSON document
1685-
| `json_arrayagg()` | Creates a JSON array by aggregating values
1686-
| `json_objectagg()` | Creates a JSON object by aggregating values
1687-
| `json_set()` | Inserts/Replaces a value by JSON path within a JSON document
1688-
| `json_remove()` | Removes a value by JSON path within a JSON document
1689-
| `json_mergepatch()` | Merges JSON documents by performing an https://tools.ietf.org/html/rfc7396[RFC 7396] compliant merge
1690-
| `json_array_append()` | Appends to a JSON array of a JSON document by JSON path
1691-
| `json_array_insert()` | Inserts a value by JSON path to a JSON array within a JSON document
1680+
| <<hql-json-object-function,`json_object()`>> | Constructs a JSON object from pairs of key and value arguments
1681+
| <<hql-json-array-function,`json_array()`>> | Constructs a JSON array from arguments
1682+
| <<hql-json-value-function,`json_value()`>> | Extracts a value from a JSON document by JSON path
1683+
| <<hql-json-exists-function,`json_exists()`>> | Checks if a JSON path exists in a JSON document
1684+
| <<hql-json-query-function,`json_query()`>> | Queries non-scalar values by JSON path in a JSON document
1685+
| <<hql-json-arrayagg-function,`json_arrayagg()`>> | Creates a JSON array by aggregating values
1686+
| <<hql-json-objectagg-function,`json_objectagg()`>> | Creates a JSON object by aggregating values
1687+
| <<hql-json-set-function,`json_set()`>> | Inserts/Replaces a value by JSON path within a JSON document
1688+
| <<hql-json-remove-function,`json_remove()`>> | Removes a value by JSON path within a JSON document
1689+
| <<hql-json-mergepatch-function,`json_mergepatch()`>> | Merges JSON documents by performing an https://tools.ietf.org/html/rfc7396[RFC 7396] compliant merge
1690+
| <<hql-json-array-append-function,`json_array_append()`>> | Appends to a JSON array of a JSON document by JSON path
1691+
| <<hql-json-array-insert-function,`json_array_insert()`>> | Inserts a value by JSON path to a JSON array within a JSON document
1692+
| <<hql-json-table-function,`json_table()`>> | Turns a JSON document into rows
16921693
|===
16931694
16941695
@@ -2203,6 +2204,47 @@ include::{json-example-dir-hql}/JsonArrayInsertTest.java[tags=hql-json-array-ins
22032204
22042205
WARNING: SAP HANA, DB2, H2 and HSQLDB do not support this function.
22052206
2207+
[[hql-json-table-function]]
2208+
===== `json_table()`
2209+
2210+
A <<hql-from-set-returning-functions,set-returning function>>, which turns a JSON document argument into rows.
2211+
Returns no rows if the document is `null` or an empty JSON array.
2212+
2213+
[[hql-json-table-bnf]]
2214+
[source, antlrv4, indent=0]
2215+
----
2216+
include::{extrasdir}/json_table_bnf.txt[]
2217+
----
2218+
2219+
The first argument is the JSON document. The second optional argument represents the JSON path expression to use
2220+
in order to obtain JSON nodes for further processing. The default for the optional second argument is `$[*]`
2221+
i.e. access of root array elements.
2222+
2223+
NOTE: If the root of the JSON document is an object, it is recommended to pass `$` as JSON path for portability.
2224+
2225+
The `passing` clause can be used to pass values for variables in the JSON path.
2226+
2227+
Attributes/columns that ought to be accessible via the `from` node alias are defined in the `columns` clause,
2228+
which can be of varying forms:
2229+
2230+
* Value attributes - denoted by a `castTarget` after the name, behaves like <<hql-json-value-function,`json_value()`>>
2231+
* Query attributes - denoted by the `json` type after the name, behaves like <<hql-json-query-function,`json_query()`>>
2232+
* Exists attributes - denoted by the `exists` keyword after the name, behaves like <<hql-json-exists-function,`json_exists()`>>
2233+
* Ordinal attributes - denoted by the `for ordinality` syntax after the name, gives access to the 1-based index of the currently processed array element
2234+
* Nested paths - declare a JSON path for processing of a nested `columns` clause
2235+
2236+
[[hql-json-table-simple-example]]
2237+
====
2238+
[source, java, indent=0]
2239+
----
2240+
include::{json-example-dir-hql}/JsonTableTest.java[tags=hql-json-table-example]
2241+
----
2242+
====
2243+
2244+
The `lateral` keyword is mandatory if one of the arguments refer to a from node item of the same query level.
2245+
2246+
WARNING: H2 support is limited and HSQLDB as well as Sybase ASE do not support this function.
2247+
22062248
[[hql-functions-xml]]
22072249
==== Functions for dealing with XML
22082250
@@ -2959,6 +3001,7 @@ The following set-returning functions are available on many platforms:
29593001
29603002
| <<hql-array-unnest,`unnest()`>> | Turns an array into rows
29613003
| <<hql-from-set-returning-functions-generate-series,`generate_series()`>> | Creates a series of values as rows
3004+
| <<hql-json-table,`json_table()`>> | Turns a JSON document into rows
29623005
|===
29633006
29643007
To use set returning functions defined in the database, it is required to register them in a `FunctionContributor`:
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"json_table(" expression ("," expression)? passingClause? columnsClause errorClause? ")"
2+
3+
passingClause
4+
: "passing" expression "as" identifier ("," expression "as" identifier)*
5+
6+
columnsClause
7+
: "columns(" column ("," column)* ")"
8+
9+
column
10+
: "nested" "path"? STRING_LITERAL columnsClause
11+
| attributeName "json" wrapperClause? ("path" STRING_LITERAL)? queryOnErrorClause? queryOnEmptyClause?
12+
| attributeName "for ordinality"
13+
| attributeName "exists" ("path" STRING_LITERAL)? existsOnErrorClause?
14+
| attributeName castTarget ("path" STRING_LITERAL)? valueOnErrorClause? valueOnEmptyClause?
15+
16+
queryOnErrorClause
17+
: ( "error" | "null" | ( "empty" ( "array" | "object" )? ) ) "on error";
18+
19+
queryOnEmptyClause
20+
: ( "error" | "null" | ( "empty" ( "array" | "object" )? ) ) "on empty";
21+
22+
existsOnErrorClause
23+
: ( "error" | "true" | "false" ) "on error"
24+
25+
valueOnErrorClause
26+
: ( "error" | "null" | ( "default" expression ) ) "on error";
27+
28+
valueOnEmptyClause
29+
: ( "error" | "null" | ( "default" expression ) ) "on empty";
30+
31+
errorClause
32+
: ( "error" | "null" ) "on error"

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
519519

520520
functionFactory.unnest_postgresql();
521521
functionFactory.generateSeries( null, "ordinality", true );
522+
functionFactory.jsonTable_cockroachdb();
522523

523524
// Postgres uses # instead of ^ for XOR
524525
functionContributions.getFunctionRegistry().patternDescriptorBuilder( "bitxor", "(?1#?2)" )

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacyDialect.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,13 +432,14 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
432432
functionFactory.listagg( null );
433433

434434
if ( getDB2Version().isSameOrAfter( 11 ) ) {
435-
functionFactory.jsonValue_no_passing();
435+
functionFactory.jsonValue_db2();
436436
functionFactory.jsonQuery_no_passing();
437437
functionFactory.jsonExists_no_passing();
438438
functionFactory.jsonObject_db2();
439439
functionFactory.jsonArray_db2();
440440
functionFactory.jsonArrayAgg_db2();
441441
functionFactory.jsonObjectAgg_db2();
442+
functionFactory.jsonTable_db2();
442443
}
443444
}
444445

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
429429

430430
functionFactory.unnest_h2( getMaximumArraySize() );
431431
functionFactory.generateSeries_h2( getMaximumSeriesSize() );
432+
functionFactory.jsonTable_h2( getMaximumArraySize() );
432433
}
433434

434435
/**

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HANALegacyDialect.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
495495
functionFactory.jsonExists_hana();
496496

497497
functionFactory.unnest_hana();
498-
// functionFactory.json_table();
498+
functionFactory.jsonTable_hana();
499499

500500
functionFactory.generateSeries_hana( getMaximumSeriesSize() );
501501

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MariaDBLegacyDialect.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
100100
if ( getVersion().isSameOrAfter( 10, 3, 3 ) ) {
101101
if ( getVersion().isSameOrAfter( 10, 6 ) ) {
102102
commonFunctionFactory.unnest_emulated();
103+
commonFunctionFactory.jsonTable_mysql();
103104
}
104105

105106
commonFunctionFactory.inverseDistributionOrderedSetAggregates_windowEmulation();

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacyDialect.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
674674

675675
if ( getMySQLVersion().isSameOrAfter( 8 ) ) {
676676
functionFactory.unnest_emulated();
677+
functionFactory.jsonTable_mysql();
677678
}
678679
if ( supportsRecursiveCTE() ) {
679680
functionFactory.generateSeries_recursive( getMaximumSeriesSize(), false, false );

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
312312
functionFactory.jsonValue_oracle();
313313
functionFactory.jsonQuery_oracle();
314314
functionFactory.jsonExists_oracle();
315-
functionFactory.jsonObject_oracle();
315+
functionFactory.jsonObject_oracle( getVersion().isSameOrAfter( 19 ) );
316316
functionFactory.jsonArray_oracle();
317317
functionFactory.jsonArrayAgg_oracle();
318318
functionFactory.jsonObjectAgg_oracle();
@@ -323,6 +323,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
323323
functionFactory.jsonMergepatch_oracle();
324324
functionFactory.jsonArrayAppend_oracle();
325325
functionFactory.jsonArrayInsert_oracle();
326+
functionFactory.jsonTable_oracle();
326327
}
327328

328329
functionFactory.xmlelement();

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
639639
functionFactory.jsonArray();
640640
functionFactory.jsonArrayAgg_postgresql( true );
641641
functionFactory.jsonObjectAgg_postgresql( true );
642+
functionFactory.jsonTable();
642643
}
643644
else {
644645
functionFactory.jsonValue_postgresql();
@@ -656,6 +657,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
656657
functionFactory.jsonArrayAgg_postgresql( false );
657658
functionFactory.jsonObjectAgg_postgresql( false );
658659
}
660+
functionFactory.jsonTable_postgresql();
659661
}
660662
functionFactory.jsonSet_postgresql();
661663
functionFactory.jsonRemove_postgresql();

0 commit comments

Comments
 (0)