Skip to content

Commit 7921eeb

Browse files
committed
HHH-18496 Hide JSON functions behind feature flag
1 parent 286d696 commit 7921eeb

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
@@ -132,6 +132,7 @@
132132
import static org.hibernate.cfg.CacheSettings.QUERY_CACHE_LAYOUT;
133133
import static org.hibernate.cfg.PersistenceSettings.UNOWNED_ASSOCIATION_TRANSIENT_CHECK;
134134
import static org.hibernate.cfg.QuerySettings.DEFAULT_NULL_ORDERING;
135+
import static org.hibernate.cfg.QuerySettings.JSON_FUNCTIONS_ENABLED;
135136
import static org.hibernate.cfg.QuerySettings.PORTABLE_INTEGER_DIVISION;
136137
import static org.hibernate.engine.config.spi.StandardConverters.BOOLEAN;
137138
import static org.hibernate.internal.CoreLogging.messageLogger;
@@ -278,6 +279,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
278279
private final boolean inClauseParameterPaddingEnabled;
279280

280281
private final boolean portableIntegerDivisionEnabled;
282+
private final boolean jsonFunctionsEnabled;
281283

282284
private final int queryStatisticsMaxSize;
283285

@@ -618,6 +620,10 @@ else if ( jdbcTimeZoneValue != null ) {
618620
PORTABLE_INTEGER_DIVISION,
619621
configurationSettings
620622
);
623+
this.jsonFunctionsEnabled = getBoolean(
624+
JSON_FUNCTIONS_ENABLED,
625+
configurationSettings
626+
);
621627

622628
this.queryStatisticsMaxSize = getInt(
623629
QUERY_STATISTICS_MAX_SIZE,
@@ -1248,6 +1254,11 @@ public boolean inClauseParameterPaddingEnabled() {
12481254
return this.inClauseParameterPaddingEnabled;
12491255
}
12501256

1257+
@Override
1258+
public boolean isJsonFunctionsEnabled() {
1259+
return jsonFunctionsEnabled;
1260+
}
1261+
12511262
@Override
12521263
public boolean isPortableIntegerDivisionEnabled() {
12531264
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
@@ -423,6 +423,11 @@ public boolean inClauseParameterPaddingEnabled() {
423423
return delegate.inClauseParameterPaddingEnabled();
424424
}
425425

426+
@Override
427+
public boolean isJsonFunctionsEnabled() {
428+
return delegate.isJsonFunctionsEnabled();
429+
}
430+
426431
@Override
427432
public boolean isPortableIntegerDivisionEnabled() {
428433
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
@@ -268,6 +268,14 @@ default boolean inClauseParameterPaddingEnabled() {
268268
return false;
269269
}
270270

271+
/**
272+
* @see org.hibernate.cfg.AvailableSettings#JSON_FUNCTIONS_ENABLED
273+
*/
274+
@Override
275+
default boolean isJsonFunctionsEnabled() {
276+
return false;
277+
}
278+
271279
/**
272280
* @see org.hibernate.cfg.AvailableSettings#PORTABLE_INTEGER_DIVISION
273281
*/

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

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

9+
import org.hibernate.Incubating;
910
import org.hibernate.boot.spi.SessionFactoryOptions;
1011
import org.hibernate.query.spi.QueryPlan;
1112

@@ -17,6 +18,14 @@
1718
* @author Steve Ebersole
1819
*/
1920
public interface QuerySettings {
21+
/**
22+
* Boolean setting to control if the use of tech preview JSON functions in HQL is enabled.
23+
* By default, this is {@code false} i.e. disabled since the functions are still incubating.
24+
*
25+
* @since 7.0
26+
*/
27+
@Incubating
28+
String JSON_FUNCTIONS_ENABLED = "hibernate.query.hql.json_functions_enabled";
2029
/**
2130
* Specifies that division of two integers should produce an integer on all
2231
* 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
@@ -34,6 +34,7 @@
3434
import java.util.Set;
3535

3636
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
37+
import org.hibernate.cfg.QuerySettings;
3738
import org.hibernate.dialect.function.SqlColumn;
3839
import org.hibernate.grammars.hql.HqlLexer;
3940
import org.hibernate.grammars.hql.HqlParser;
@@ -2701,6 +2702,7 @@ public SqmPredicate visitContainsPredicate(HqlParser.ContainsPredicateContext ct
27012702

27022703
@Override
27032704
public SqmExpression<?> visitJsonValueFunction(HqlParser.JsonValueFunctionContext ctx) {
2705+
checkJsonFunctionsEnabled( ctx );
27042706
final SqmExpression<?> jsonDocument = (SqmExpression<?>) ctx.expression( 0 ).accept( this );
27052707
final SqmExpression<?> jsonPath = (SqmExpression<?>) ctx.expression( 1 ).accept( this );
27062708
final HqlParser.JsonValueReturningClauseContext returningClause = ctx.jsonValueReturningClause();
@@ -2751,6 +2753,7 @@ public SqmExpression<?> visitJsonValueFunction(HqlParser.JsonValueFunctionContex
27512753

27522754
@Override
27532755
public SqmExpression<?> visitJsonQueryFunction(HqlParser.JsonQueryFunctionContext ctx) {
2756+
checkJsonFunctionsEnabled( ctx );
27542757
final SqmExpression<?> jsonDocument = (SqmExpression<?>) ctx.expression( 0 ).accept( this );
27552758
final SqmExpression<?> jsonPath = (SqmExpression<?>) ctx.expression( 1 ).accept( this );
27562759
final SqmJsonQueryExpression jsonQuery = (SqmJsonQueryExpression) getFunctionDescriptor( "json_query" ).<String>generateSqmExpression(
@@ -2824,6 +2827,7 @@ public SqmExpression<?> visitJsonQueryFunction(HqlParser.JsonQueryFunctionContex
28242827

28252828
@Override
28262829
public SqmExpression<?> visitJsonExistsFunction(HqlParser.JsonExistsFunctionContext ctx) {
2830+
checkJsonFunctionsEnabled( ctx );
28272831
final SqmExpression<?> jsonDocument = (SqmExpression<?>) ctx.expression( 0 ).accept( this );
28282832
final SqmExpression<?> jsonPath = (SqmExpression<?>) ctx.expression( 1 ).accept( this );
28292833

@@ -2857,6 +2861,7 @@ public SqmExpression<?> visitJsonExistsFunction(HqlParser.JsonExistsFunctionCont
28572861

28582862
@Override
28592863
public SqmExpression<?> visitJsonArrayFunction(HqlParser.JsonArrayFunctionContext ctx) {
2864+
checkJsonFunctionsEnabled( ctx );
28602865
final HqlParser.JsonNullClauseContext subCtx = ctx.jsonNullClause();
28612866
final List<HqlParser.ExpressionOrPredicateContext> argumentContexts = ctx.expressionOrPredicate();
28622867
int count = argumentContexts.size();
@@ -2881,6 +2886,7 @@ public SqmExpression<?> visitJsonArrayFunction(HqlParser.JsonArrayFunctionContex
28812886

28822887
@Override
28832888
public SqmExpression<?> visitJsonObjectFunction(HqlParser.JsonObjectFunctionContext ctx) {
2889+
checkJsonFunctionsEnabled( ctx );
28842890
final HqlParser.JsonObjectFunctionEntriesContext entries = ctx.jsonObjectFunctionEntries();
28852891
final List<SqmTypedNode<?>> arguments;
28862892
if ( entries == null ) {
@@ -2912,6 +2918,7 @@ public SqmExpression<?> visitJsonObjectFunction(HqlParser.JsonObjectFunctionCont
29122918

29132919
@Override
29142920
public Object visitJsonArrayAggFunction(HqlParser.JsonArrayAggFunctionContext ctx) {
2921+
checkJsonFunctionsEnabled( ctx );
29152922
final HqlParser.JsonNullClauseContext jsonNullClauseContext = ctx.jsonNullClause();
29162923
final ArrayList<SqmTypedNode<?>> arguments = new ArrayList<>( jsonNullClauseContext == null ? 1 : 2 );
29172924
arguments.add( (SqmTypedNode<?>) ctx.expressionOrPredicate().accept( this ) );
@@ -2936,6 +2943,7 @@ public Object visitJsonArrayAggFunction(HqlParser.JsonArrayAggFunctionContext ct
29362943

29372944
@Override
29382945
public Object visitJsonObjectAggFunction(HqlParser.JsonObjectAggFunctionContext ctx) {
2946+
checkJsonFunctionsEnabled( ctx );
29392947
final HqlParser.JsonNullClauseContext jsonNullClauseContext = ctx.jsonNullClause();
29402948
final HqlParser.JsonUniqueKeysClauseContext jsonUniqueKeysClauseContext = ctx.jsonUniqueKeysClause();
29412949
final ArrayList<SqmTypedNode<?>> arguments = new ArrayList<>( 4 );
@@ -2966,6 +2974,16 @@ public Object visitJsonObjectAggFunction(HqlParser.JsonObjectAggFunctionContext
29662974
);
29672975
}
29682976

2977+
private void checkJsonFunctionsEnabled(ParserRuleContext ctx) {
2978+
if ( !creationOptions.isJsonFunctionsEnabled() ) {
2979+
throw new SemanticException(
2980+
"Can't use function '" + ctx.children.get( 0 ).getText() +
2981+
"', because tech preview JSON functions are not enabled. To enable, set the '" + QuerySettings.JSON_FUNCTIONS_ENABLED + "' setting to 'true'.",
2982+
query
2983+
);
2984+
}
2985+
}
2986+
29692987
@Override
29702988
public SqmPredicate visitIncludesPredicate(HqlParser.IncludesPredicateContext ctx) {
29712989
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
@@ -26,6 +26,13 @@ default boolean useStrictJpaCompliance() {
2626
return false;
2727
}
2828

29+
/**
30+
* @see org.hibernate.cfg.AvailableSettings#JSON_FUNCTIONS_ENABLED
31+
*/
32+
default boolean isJsonFunctionsEnabled() {
33+
return false;
34+
}
35+
2936
/**
3037
* @see org.hibernate.cfg.AvailableSettings#PORTABLE_INTEGER_DIVISION
3138
*/

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
@@ -78,6 +78,11 @@ default ImmutableEntityUpdateQueryHandlingMode getImmutableEntityUpdateQueryHand
7878
return ImmutableEntityUpdateQueryHandlingMode.WARNING;
7979
}
8080

81+
/**
82+
* @see org.hibernate.cfg.AvailableSettings#JSON_FUNCTIONS_ENABLED
83+
*/
84+
boolean isJsonFunctionsEnabled();
85+
8186
/**
8287
* @see org.hibernate.cfg.AvailableSettings#PORTABLE_INTEGER_DIVISION
8388
*/

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
@@ -24,6 +24,11 @@ public boolean useStrictJpaCompliance() {
2424
return queryEngineOptions.getJpaCompliance().isJpaQueryComplianceEnabled();
2525
}
2626

27+
@Override
28+
public boolean isJsonFunctionsEnabled() {
29+
return queryEngineOptions.isJsonFunctionsEnabled();
30+
}
31+
2732
@Override
2833
public boolean isPortableIntegerDivisionEnabled() {
2934
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)