Skip to content

Commit a694e5f

Browse files
committed
HHH-18496 Hide JSON functions behind feature flag
1 parent c654068 commit a694e5f

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;
@@ -277,6 +278,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
277278
private final boolean inClauseParameterPaddingEnabled;
278279

279280
private final boolean portableIntegerDivisionEnabled;
281+
private final boolean jsonFunctionsEnabled;
280282

281283
private final int queryStatisticsMaxSize;
282284

@@ -617,6 +619,10 @@ else if ( jdbcTimeZoneValue != null ) {
617619
PORTABLE_INTEGER_DIVISION,
618620
configurationSettings
619621
);
622+
this.jsonFunctionsEnabled = getBoolean(
623+
JSON_FUNCTIONS_ENABLED,
624+
configurationSettings
625+
);
620626

621627
this.queryStatisticsMaxSize = getInt(
622628
QUERY_STATISTICS_MAX_SIZE,
@@ -1241,6 +1247,11 @@ public boolean inClauseParameterPaddingEnabled() {
12411247
return this.inClauseParameterPaddingEnabled;
12421248
}
12431249

1250+
@Override
1251+
public boolean isJsonFunctionsEnabled() {
1252+
return jsonFunctionsEnabled;
1253+
}
1254+
12441255
@Override
12451256
public boolean isPortableIntegerDivisionEnabled() {
12461257
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;
@@ -2704,6 +2705,7 @@ public SqmPredicate visitContainsPredicate(HqlParser.ContainsPredicateContext ct
27042705

27052706
@Override
27062707
public SqmExpression<?> visitJsonValueFunction(HqlParser.JsonValueFunctionContext ctx) {
2708+
checkJsonFunctionsEnabled( ctx );
27072709
final SqmExpression<?> jsonDocument = (SqmExpression<?>) ctx.expression( 0 ).accept( this );
27082710
final SqmExpression<?> jsonPath = (SqmExpression<?>) ctx.expression( 1 ).accept( this );
27092711
final HqlParser.JsonValueReturningClauseContext returningClause = ctx.jsonValueReturningClause();
@@ -2754,6 +2756,7 @@ public SqmExpression<?> visitJsonValueFunction(HqlParser.JsonValueFunctionContex
27542756

27552757
@Override
27562758
public SqmExpression<?> visitJsonQueryFunction(HqlParser.JsonQueryFunctionContext ctx) {
2759+
checkJsonFunctionsEnabled( ctx );
27572760
final SqmExpression<?> jsonDocument = (SqmExpression<?>) ctx.expression( 0 ).accept( this );
27582761
final SqmExpression<?> jsonPath = (SqmExpression<?>) ctx.expression( 1 ).accept( this );
27592762
final SqmJsonQueryExpression jsonQuery = (SqmJsonQueryExpression) getFunctionDescriptor( "json_query" ).<String>generateSqmExpression(
@@ -2827,6 +2830,7 @@ public SqmExpression<?> visitJsonQueryFunction(HqlParser.JsonQueryFunctionContex
28272830

28282831
@Override
28292832
public SqmExpression<?> visitJsonExistsFunction(HqlParser.JsonExistsFunctionContext ctx) {
2833+
checkJsonFunctionsEnabled( ctx );
28302834
final SqmExpression<?> jsonDocument = (SqmExpression<?>) ctx.expression( 0 ).accept( this );
28312835
final SqmExpression<?> jsonPath = (SqmExpression<?>) ctx.expression( 1 ).accept( this );
28322836

@@ -2860,6 +2864,7 @@ public SqmExpression<?> visitJsonExistsFunction(HqlParser.JsonExistsFunctionCont
28602864

28612865
@Override
28622866
public SqmExpression<?> visitJsonArrayFunction(HqlParser.JsonArrayFunctionContext ctx) {
2867+
checkJsonFunctionsEnabled( ctx );
28632868
final HqlParser.JsonNullClauseContext subCtx = ctx.jsonNullClause();
28642869
final List<HqlParser.ExpressionOrPredicateContext> argumentContexts = ctx.expressionOrPredicate();
28652870
int count = argumentContexts.size();
@@ -2884,6 +2889,7 @@ public SqmExpression<?> visitJsonArrayFunction(HqlParser.JsonArrayFunctionContex
28842889

28852890
@Override
28862891
public SqmExpression<?> visitJsonObjectFunction(HqlParser.JsonObjectFunctionContext ctx) {
2892+
checkJsonFunctionsEnabled( ctx );
28872893
final HqlParser.JsonObjectFunctionEntriesContext entries = ctx.jsonObjectFunctionEntries();
28882894
final List<SqmTypedNode<?>> arguments;
28892895
if ( entries == null ) {
@@ -2915,6 +2921,7 @@ public SqmExpression<?> visitJsonObjectFunction(HqlParser.JsonObjectFunctionCont
29152921

29162922
@Override
29172923
public Object visitJsonArrayAggFunction(HqlParser.JsonArrayAggFunctionContext ctx) {
2924+
checkJsonFunctionsEnabled( ctx );
29182925
final HqlParser.JsonNullClauseContext jsonNullClauseContext = ctx.jsonNullClause();
29192926
final ArrayList<SqmTypedNode<?>> arguments = new ArrayList<>( jsonNullClauseContext == null ? 1 : 2 );
29202927
arguments.add( (SqmTypedNode<?>) ctx.expressionOrPredicate().accept( this ) );
@@ -2939,6 +2946,7 @@ public Object visitJsonArrayAggFunction(HqlParser.JsonArrayAggFunctionContext ct
29392946

29402947
@Override
29412948
public Object visitJsonObjectAggFunction(HqlParser.JsonObjectAggFunctionContext ctx) {
2949+
checkJsonFunctionsEnabled( ctx );
29422950
final HqlParser.JsonNullClauseContext jsonNullClauseContext = ctx.jsonNullClause();
29432951
final HqlParser.JsonUniqueKeysClauseContext jsonUniqueKeysClauseContext = ctx.jsonUniqueKeysClause();
29442952
final ArrayList<SqmTypedNode<?>> arguments = new ArrayList<>( 4 );
@@ -2969,6 +2977,16 @@ public Object visitJsonObjectAggFunction(HqlParser.JsonObjectAggFunctionContext
29692977
);
29702978
}
29712979

2980+
private void checkJsonFunctionsEnabled(ParserRuleContext ctx) {
2981+
if ( !creationOptions.isJsonFunctionsEnabled() ) {
2982+
throw new SemanticException(
2983+
"Can't use function '" + ctx.children.get( 0 ).getText() +
2984+
"', because tech preview JSON functions are not enabled. To enable, set the '" + QuerySettings.JSON_FUNCTIONS_ENABLED + "' setting to 'true'.",
2985+
query
2986+
);
2987+
}
2988+
}
2989+
29722990
@Override
29732991
public SqmPredicate visitIncludesPredicate(HqlParser.IncludesPredicateContext ctx) {
29742992
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)