From 7ff0567383a49aafc41cf8df6d390b88687b8cec Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Fri, 20 Sep 2024 21:43:32 +0200 Subject: [PATCH] HHH-18497 Make reserved word identification for JPA compliance more robust --- .../hql/internal/SqmTreeCreationHelper.java | 107 +++++++++++++++++- 1 file changed, 103 insertions(+), 4 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SqmTreeCreationHelper.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SqmTreeCreationHelper.java index ad93326c52..44db3663b2 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SqmTreeCreationHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SqmTreeCreationHelper.java @@ -5,6 +5,7 @@ package org.hibernate.query.hql.internal; import java.util.Locale; +import java.util.Set; import org.hibernate.grammars.hql.HqlParser; import org.hibernate.jpa.spi.JpaCompliance; @@ -19,8 +20,6 @@ import org.hibernate.query.sqm.tree.from.SqmRoot; import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.tree.ParseTree; -import static org.hibernate.grammars.hql.HqlParser.IDENTIFIER; - /** * Helper for dealing with SQM tree creation * @@ -28,6 +27,106 @@ import static org.hibernate.grammars.hql.HqlParser.IDENTIFIER; */ public class SqmTreeCreationHelper { + // The list is from the spec section 4.4.1 + private static final Set RESERVED_WORDS = Set.of( + "abs", + "all", + "and", + "any", + "as", + "asc", + "avg", + "between", + "bit_length", + "both", + "by", + "case", + "ceiling", + "char_length", + "character_length", + "class", + "coalesce", + "concat", + "count", + "current_date", + "current_time", + "current_timestamp", + "delete", + "desc", + "distinct", + "else", + "empty", + "end", + "entry", + "escape", + "exists", + "exp", + "extract", + "false", + "fetch", + "first", + "floor", + "from", + "function", + "group", + "having", + "in", + "index", + "inner", + "is", + "join", + "key", + "leading", + "last", + "left", + "length", + "like", + "local", + "ln", + "locate", + "lower", + "max", + "member", + "min", + "mod", + "new", + "not", + "null", + "nulls", + "nullif", + "object", + "of", + "on", + "or", + "order", + "outer", + "position", + "power", + "replace", + "right", + "round", + "select", + "set", + "sign", + "size", + "some", + "sqrt", + "substring", + "sum", + "then", + "trailing", + "treat", + "trim", + "true", + "type", + "unknown", + "update", + "upper", + "value", + "when", + "where" + ); + /** * Handle secondary query roots using cross-join semantics. * @@ -108,7 +207,7 @@ public class SqmTreeCreationHelper { // which JPA disallows... if ( sqmBuilder.getCreationOptions().useStrictJpaCompliance() ) { final Token identificationVariableToken = identifierContext.getStart(); - if ( identificationVariableToken.getType() != IDENTIFIER ) { + if ( RESERVED_WORDS.contains( identificationVariableToken.getText().toLowerCase( Locale.ENGLISH ) ) ) { throw new StrictJpaComplianceViolation( String.format( Locale.ROOT, @@ -128,7 +227,7 @@ public class SqmTreeCreationHelper { // which JPA disallows... if ( sqmBuilder.getCreationOptions().useStrictJpaCompliance() ) { final Token identificationVariableToken = identifierContext.getStart(); - if ( identificationVariableToken.getType() != IDENTIFIER ) { + if ( RESERVED_WORDS.contains( identificationVariableToken.getText().toLowerCase( Locale.ENGLISH ) ) ) { throw new StrictJpaComplianceViolation( String.format( Locale.ROOT,