Skip to content

Commit f6ac53f

Browse files
committed
HHH-18496 Hide JSON functions behind feature flag
1 parent 59ae75b commit f6ac53f

File tree

18 files changed

+107
-1
lines changed

18 files changed

+107
-1
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1625,6 +1625,9 @@ include::{array-example-dir-hql}/ArrayToStringTest.java[tags=hql-array-to-string
16251625
16261626
The following functions deal with SQL JSON types, which are not supported on every database.
16271627
1628+
NOTE: The following functions are incubating/tech-preview and to use them in HQL,
1629+
it is necessary to enable the `hibernate.query.hql.json_functions_enabled` configuration setting.
1630+
16281631
[[hql-json-functions]]
16291632
|===
16301633
| Function | Purpose

hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@
130130
import static org.hibernate.cfg.CacheSettings.QUERY_CACHE_LAYOUT;
131131
import static org.hibernate.cfg.PersistenceSettings.UNOWNED_ASSOCIATION_TRANSIENT_CHECK;
132132
import static org.hibernate.cfg.QuerySettings.DEFAULT_NULL_ORDERING;
133+
import static org.hibernate.cfg.QuerySettings.JSON_FUNCTIONS_ENABLED;
133134
import static org.hibernate.cfg.QuerySettings.PORTABLE_INTEGER_DIVISION;
134135
import static org.hibernate.engine.config.spi.StandardConverters.BOOLEAN;
135136
import static org.hibernate.internal.CoreLogging.messageLogger;
@@ -276,6 +277,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
276277
private final boolean inClauseParameterPaddingEnabled;
277278

278279
private final boolean portableIntegerDivisionEnabled;
280+
private final boolean jsonFunctionsEnabled;
279281

280282
private final int queryStatisticsMaxSize;
281283

@@ -616,6 +618,10 @@ else if ( jdbcTimeZoneValue != null ) {
616618
PORTABLE_INTEGER_DIVISION,
617619
configurationSettings
618620
);
621+
this.jsonFunctionsEnabled = getBoolean(
622+
JSON_FUNCTIONS_ENABLED,
623+
configurationSettings
624+
);
619625

620626
this.queryStatisticsMaxSize = getInt(
621627
QUERY_STATISTICS_MAX_SIZE,
@@ -1246,6 +1252,11 @@ public boolean inClauseParameterPaddingEnabled() {
12461252
return this.inClauseParameterPaddingEnabled;
12471253
}
12481254

1255+
@Override
1256+
public boolean isJsonFunctionsEnabled() {
1257+
return jsonFunctionsEnabled;
1258+
}
1259+
12491260
@Override
12501261
public boolean isPortableIntegerDivisionEnabled() {
12511262
return portableIntegerDivisionEnabled;

hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,11 @@ public boolean inClauseParameterPaddingEnabled() {
421421
return delegate.inClauseParameterPaddingEnabled();
422422
}
423423

424+
@Override
425+
public boolean isJsonFunctionsEnabled() {
426+
return delegate.isJsonFunctionsEnabled();
427+
}
428+
424429
@Override
425430
public boolean isPortableIntegerDivisionEnabled() {
426431
return delegate.isPortableIntegerDivisionEnabled();

hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,14 @@ default boolean inClauseParameterPaddingEnabled() {
266266
return false;
267267
}
268268

269+
/**
270+
* @see org.hibernate.cfg.AvailableSettings#JSON_FUNCTIONS_ENABLED
271+
*/
272+
@Override
273+
default boolean isJsonFunctionsEnabled() {
274+
return false;
275+
}
276+
269277
/**
270278
* @see org.hibernate.cfg.AvailableSettings#PORTABLE_INTEGER_DIVISION
271279
*/

hibernate-core/src/main/java/org/hibernate/cfg/QuerySettings.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
package org.hibernate.cfg;
66

7+
import org.hibernate.Incubating;
78
import org.hibernate.boot.spi.SessionFactoryOptions;
89
import org.hibernate.query.spi.QueryPlan;
910

@@ -15,6 +16,14 @@
1516
* @author Steve Ebersole
1617
*/
1718
public interface QuerySettings {
19+
/**
20+
* Boolean setting to control if the use of tech preview JSON functions in HQL is enabled.
21+
* By default, this is {@code false} i.e. disabled since the functions are still incubating.
22+
*
23+
* @since 7.0
24+
*/
25+
@Incubating
26+
String JSON_FUNCTIONS_ENABLED = "hibernate.query.hql.json_functions_enabled";
1827
/**
1928
* Specifies that division of two integers should produce an integer on all
2029
* databases. By default, integer division in HQL can produce a non-integer

hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import java.util.Set;
3333

3434
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
35+
import org.hibernate.cfg.QuerySettings;
3536
import org.hibernate.dialect.function.SqlColumn;
3637
import org.hibernate.grammars.hql.HqlLexer;
3738
import org.hibernate.grammars.hql.HqlParser;
@@ -2699,6 +2700,7 @@ public SqmPredicate visitContainsPredicate(HqlParser.ContainsPredicateContext ct
26992700

27002701
@Override
27012702
public SqmExpression<?> visitJsonValueFunction(HqlParser.JsonValueFunctionContext ctx) {
2703+
checkJsonFunctionsEnabled( ctx );
27022704
final SqmExpression<?> jsonDocument = (SqmExpression<?>) ctx.expression( 0 ).accept( this );
27032705
final SqmExpression<?> jsonPath = (SqmExpression<?>) ctx.expression( 1 ).accept( this );
27042706
final HqlParser.JsonValueReturningClauseContext returningClause = ctx.jsonValueReturningClause();
@@ -2749,6 +2751,7 @@ public SqmExpression<?> visitJsonValueFunction(HqlParser.JsonValueFunctionContex
27492751

27502752
@Override
27512753
public SqmExpression<?> visitJsonQueryFunction(HqlParser.JsonQueryFunctionContext ctx) {
2754+
checkJsonFunctionsEnabled( ctx );
27522755
final SqmExpression<?> jsonDocument = (SqmExpression<?>) ctx.expression( 0 ).accept( this );
27532756
final SqmExpression<?> jsonPath = (SqmExpression<?>) ctx.expression( 1 ).accept( this );
27542757
final SqmJsonQueryExpression jsonQuery = (SqmJsonQueryExpression) getFunctionDescriptor( "json_query" ).<String>generateSqmExpression(
@@ -2822,6 +2825,7 @@ public SqmExpression<?> visitJsonQueryFunction(HqlParser.JsonQueryFunctionContex
28222825

28232826
@Override
28242827
public SqmExpression<?> visitJsonExistsFunction(HqlParser.JsonExistsFunctionContext ctx) {
2828+
checkJsonFunctionsEnabled( ctx );
28252829
final SqmExpression<?> jsonDocument = (SqmExpression<?>) ctx.expression( 0 ).accept( this );
28262830
final SqmExpression<?> jsonPath = (SqmExpression<?>) ctx.expression( 1 ).accept( this );
28272831

@@ -2855,6 +2859,7 @@ public SqmExpression<?> visitJsonExistsFunction(HqlParser.JsonExistsFunctionCont
28552859

28562860
@Override
28572861
public SqmExpression<?> visitJsonArrayFunction(HqlParser.JsonArrayFunctionContext ctx) {
2862+
checkJsonFunctionsEnabled( ctx );
28582863
final HqlParser.JsonNullClauseContext subCtx = ctx.jsonNullClause();
28592864
final List<HqlParser.ExpressionOrPredicateContext> argumentContexts = ctx.expressionOrPredicate();
28602865
int count = argumentContexts.size();
@@ -2879,6 +2884,7 @@ public SqmExpression<?> visitJsonArrayFunction(HqlParser.JsonArrayFunctionContex
28792884

28802885
@Override
28812886
public SqmExpression<?> visitJsonObjectFunction(HqlParser.JsonObjectFunctionContext ctx) {
2887+
checkJsonFunctionsEnabled( ctx );
28822888
final HqlParser.JsonObjectFunctionEntriesContext entries = ctx.jsonObjectFunctionEntries();
28832889
final List<SqmTypedNode<?>> arguments;
28842890
if ( entries == null ) {
@@ -2910,6 +2916,7 @@ public SqmExpression<?> visitJsonObjectFunction(HqlParser.JsonObjectFunctionCont
29102916

29112917
@Override
29122918
public Object visitJsonArrayAggFunction(HqlParser.JsonArrayAggFunctionContext ctx) {
2919+
checkJsonFunctionsEnabled( ctx );
29132920
final HqlParser.JsonNullClauseContext jsonNullClauseContext = ctx.jsonNullClause();
29142921
final ArrayList<SqmTypedNode<?>> arguments = new ArrayList<>( jsonNullClauseContext == null ? 1 : 2 );
29152922
arguments.add( (SqmTypedNode<?>) ctx.expressionOrPredicate().accept( this ) );
@@ -2934,6 +2941,7 @@ public Object visitJsonArrayAggFunction(HqlParser.JsonArrayAggFunctionContext ct
29342941

29352942
@Override
29362943
public Object visitJsonObjectAggFunction(HqlParser.JsonObjectAggFunctionContext ctx) {
2944+
checkJsonFunctionsEnabled( ctx );
29372945
final HqlParser.JsonNullClauseContext jsonNullClauseContext = ctx.jsonNullClause();
29382946
final HqlParser.JsonUniqueKeysClauseContext jsonUniqueKeysClauseContext = ctx.jsonUniqueKeysClause();
29392947
final ArrayList<SqmTypedNode<?>> arguments = new ArrayList<>( 4 );
@@ -2964,6 +2972,16 @@ public Object visitJsonObjectAggFunction(HqlParser.JsonObjectAggFunctionContext
29642972
);
29652973
}
29662974

2975+
private void checkJsonFunctionsEnabled(ParserRuleContext ctx) {
2976+
if ( !creationOptions.isJsonFunctionsEnabled() ) {
2977+
throw new SemanticException(
2978+
"Can't use function '" + ctx.children.get( 0 ).getText() +
2979+
"', because tech preview JSON functions are not enabled. To enable, set the '" + QuerySettings.JSON_FUNCTIONS_ENABLED + "' setting to 'true'.",
2980+
query
2981+
);
2982+
}
2983+
}
2984+
29672985
@Override
29682986
public SqmPredicate visitIncludesPredicate(HqlParser.IncludesPredicateContext ctx) {
29692987
final boolean negated = ctx.NOT() != null;

hibernate-core/src/main/java/org/hibernate/query/hql/spi/SqmCreationOptions.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ default boolean useStrictJpaCompliance() {
2424
return false;
2525
}
2626

27+
/**
28+
* @see org.hibernate.cfg.AvailableSettings#JSON_FUNCTIONS_ENABLED
29+
*/
30+
default boolean isJsonFunctionsEnabled() {
31+
return false;
32+
}
33+
2734
/**
2835
* @see org.hibernate.cfg.AvailableSettings#PORTABLE_INTEGER_DIVISION
2936
*/

hibernate-core/src/main/java/org/hibernate/query/spi/QueryEngineOptions.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ default ImmutableEntityUpdateQueryHandlingMode getImmutableEntityUpdateQueryHand
7676
return ImmutableEntityUpdateQueryHandlingMode.WARNING;
7777
}
7878

79+
/**
80+
* @see org.hibernate.cfg.AvailableSettings#JSON_FUNCTIONS_ENABLED
81+
*/
82+
boolean isJsonFunctionsEnabled();
83+
7984
/**
8085
* @see org.hibernate.cfg.AvailableSettings#PORTABLE_INTEGER_DIVISION
8186
*/

hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCreationOptionsStandard.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ public boolean useStrictJpaCompliance() {
2222
return queryEngineOptions.getJpaCompliance().isJpaQueryComplianceEnabled();
2323
}
2424

25+
@Override
26+
public boolean isJsonFunctionsEnabled() {
27+
return queryEngineOptions.isJsonFunctionsEnabled();
28+
}
29+
2530
@Override
2631
public boolean isPortableIntegerDivisionEnabled() {
2732
return queryEngineOptions.isPortableIntegerDivisionEnabled();

hibernate-core/src/test/java/org/hibernate/orm/test/function/json/JsonArrayAggregateTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,24 @@
66
*/
77
package org.hibernate.orm.test.function.json;
88

9+
import org.hibernate.cfg.QuerySettings;
10+
911
import org.hibernate.testing.orm.domain.StandardDomainModel;
1012
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
1113
import org.hibernate.testing.orm.junit.DomainModel;
1214
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
15+
import org.hibernate.testing.orm.junit.ServiceRegistry;
1316
import org.hibernate.testing.orm.junit.SessionFactory;
1417
import org.hibernate.testing.orm.junit.SessionFactoryScope;
18+
import org.hibernate.testing.orm.junit.Setting;
1519
import org.junit.jupiter.api.Test;
1620

1721
/**
1822
* @author Christian Beikov
1923
*/
2024
@DomainModel(standardModels = StandardDomainModel.GAMBIT)
2125
@SessionFactory
26+
@ServiceRegistry(settings = @Setting(name = QuerySettings.JSON_FUNCTIONS_ENABLED, value = "true"))
2227
@RequiresDialectFeature( feature = DialectFeatureChecks.SupportsJsonArrayAgg.class)
2328
public class JsonArrayAggregateTest {
2429

0 commit comments

Comments
 (0)