Add support for missing clauses and functions.
Original Pull Request: #3691
This commit is contained in:
committed by
Christoph Strobl
parent
d203031dfb
commit
1658b9bde0
@@ -188,10 +188,6 @@ instantiation
|
||||
: NEW instantiationTarget '(' instantiationArguments ')'
|
||||
;
|
||||
|
||||
alias
|
||||
: AS? identifier // spec says IDENTIFIER but clearly does NOT mean a reserved word
|
||||
;
|
||||
|
||||
groupedItem
|
||||
: identifier
|
||||
| INTEGER_LITERAL
|
||||
@@ -354,6 +350,17 @@ dateTimeLiteral
|
||||
| INSTANT
|
||||
;
|
||||
|
||||
/**
|
||||
* A field that may be extracted from a date, time, or datetime
|
||||
*/
|
||||
extractField
|
||||
: datetimeField
|
||||
| dayField
|
||||
| weekField
|
||||
| timeZoneField
|
||||
| dateOrTimeField
|
||||
;
|
||||
|
||||
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-duration-literals
|
||||
datetimeField
|
||||
: YEAR
|
||||
@@ -368,6 +375,27 @@ datetimeField
|
||||
| EPOCH
|
||||
;
|
||||
|
||||
dayField
|
||||
: DAY OF MONTH
|
||||
| DAY OF WEEK
|
||||
| DAY OF YEAR
|
||||
;
|
||||
|
||||
weekField
|
||||
: WEEK OF MONTH
|
||||
| WEEK OF YEAR
|
||||
;
|
||||
|
||||
timeZoneField
|
||||
: OFFSET (HOUR | MINUTE)?
|
||||
| TIMEZONE_HOUR | TIMEZONE_MINUTE
|
||||
;
|
||||
|
||||
dateOrTimeField
|
||||
: DATE
|
||||
| TIME
|
||||
;
|
||||
|
||||
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-binary-literals
|
||||
binaryLiteral
|
||||
: BINARY_LITERAL
|
||||
@@ -416,11 +444,6 @@ primaryExpression
|
||||
// TBD
|
||||
|
||||
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-path-expressions
|
||||
identificationVariable
|
||||
: identifier
|
||||
| simplePath
|
||||
;
|
||||
|
||||
path
|
||||
: treatedPath pathContinutation?
|
||||
| generalPathFragment
|
||||
@@ -467,112 +490,498 @@ caseWhenPredicateClause
|
||||
;
|
||||
|
||||
// Functions
|
||||
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-exp-functions
|
||||
/**
|
||||
* A function invocation that may occur in an arbitrary expression
|
||||
*/
|
||||
function
|
||||
: functionName '(' (functionArguments | ASTERISK)? ')' pathContinutation? filterClause? withinGroup? overClause? # GenericFunction
|
||||
| functionName '(' subquery ')' # FunctionWithSubquery
|
||||
| castFunction # CastFunctionInvocation
|
||||
| extractFunction # ExtractFunctionInvocation
|
||||
| trimFunction # TrimFunctionInvocation
|
||||
| everyFunction # EveryFunctionInvocation
|
||||
| anyFunction # AnyFunctionInvocation
|
||||
| treatedPath # TreatedPathInvocation
|
||||
: standardFunction # StandardFunctionInvocation
|
||||
| aggregateFunction # AggregateFunctionInvocation
|
||||
| collectionSizeFunction # CollectionSizeFunctionInvocation
|
||||
| collectionAggregateFunction # CollectionAggregateFunctionInvocation
|
||||
| collectionFunctionMisuse # CollectionFunctionMisuseInvocation
|
||||
| jpaNonstandardFunction # JpaNonstandardFunctionInvocation
|
||||
| columnFunction # ColumnFunctionInvocation
|
||||
| genericFunction # GenericFunctionInvocation
|
||||
;
|
||||
|
||||
functionArguments
|
||||
: DISTINCT? expressionOrPredicate (',' expressionOrPredicate)*
|
||||
/**
|
||||
* Any function with an irregular syntax for the argument list
|
||||
*
|
||||
* These are all inspired by the syntax of ANSI SQL
|
||||
*/
|
||||
standardFunction
|
||||
: castFunction
|
||||
| treatedPath
|
||||
| extractFunction
|
||||
| truncFunction
|
||||
| formatFunction
|
||||
| collateFunction
|
||||
| substringFunction
|
||||
| overlayFunction
|
||||
| trimFunction
|
||||
| padFunction
|
||||
| positionFunction
|
||||
| currentDateFunction
|
||||
| currentTimeFunction
|
||||
| currentTimestampFunction
|
||||
| instantFunction
|
||||
| localDateFunction
|
||||
| localTimeFunction
|
||||
| localDateTimeFunction
|
||||
| offsetDateTimeFunction
|
||||
| cube
|
||||
| rollup
|
||||
;
|
||||
|
||||
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-aggregate-functions-filter
|
||||
filterClause
|
||||
: FILTER '(' whereClause ')'
|
||||
;
|
||||
|
||||
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-aggregate-functions-orderedset
|
||||
withinGroup
|
||||
: WITHIN GROUP '(' orderByClause ')'
|
||||
;
|
||||
|
||||
overClause
|
||||
: OVER '(' partitionClause? orderByClause? frameClause? ')'
|
||||
;
|
||||
|
||||
partitionClause
|
||||
: PARTITION BY expression (',' expression)*
|
||||
;
|
||||
|
||||
frameClause
|
||||
: (RANGE|ROWS|GROUPS) frameStart frameExclusion?
|
||||
| (RANGE|ROWS|GROUPS) BETWEEN frameStart AND frameEnd frameExclusion?
|
||||
;
|
||||
|
||||
frameStart
|
||||
: UNBOUNDED PRECEDING # UnboundedPrecedingFrameStart
|
||||
| expression PRECEDING # ExpressionPrecedingFrameStart
|
||||
| CURRENT ROW # CurrentRowFrameStart
|
||||
| expression FOLLOWING # ExpressionFollowingFrameStart
|
||||
;
|
||||
|
||||
frameExclusion
|
||||
: EXCLUDE CURRENT ROW # CurrentRowFrameExclusion
|
||||
| EXCLUDE GROUP # GroupFrameExclusion
|
||||
| EXCLUDE TIES # TiesFrameExclusion
|
||||
| EXCLUDE NO OTHERS # NoOthersFrameExclusion
|
||||
;
|
||||
|
||||
frameEnd
|
||||
: expression PRECEDING # ExpressionPrecedingFrameEnd
|
||||
| CURRENT ROW # CurrentRowFrameEnd
|
||||
| expression FOLLOWING # ExpressionFollowingFrameEnd
|
||||
| UNBOUNDED FOLLOWING # UnboundedFollowingFrameEnd
|
||||
;
|
||||
|
||||
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-functions
|
||||
/**
|
||||
* The 'cast()' function for typecasting
|
||||
*/
|
||||
castFunction
|
||||
: CAST '(' expression AS castTarget ')'
|
||||
;
|
||||
|
||||
/**
|
||||
* The target type for a typecast: a typename, together with length or precision/scale
|
||||
*/
|
||||
castTarget
|
||||
: castTargetType ('(' INTEGER_LITERAL (',' INTEGER_LITERAL)? ')')?
|
||||
;
|
||||
|
||||
/**
|
||||
* The name of the target type in a typecast
|
||||
*
|
||||
* Like the 'entityName' rule, we have a specialized dotIdentifierSequence rule
|
||||
*/
|
||||
castTargetType
|
||||
returns [String fullTargetName]
|
||||
: (i=identifier { $fullTargetName = _localctx.i.getText(); }) ('.' c=identifier { $fullTargetName += ("." + _localctx.c.getText() ); })*
|
||||
;
|
||||
|
||||
extractFunction
|
||||
: EXTRACT '(' expression FROM expression ')'
|
||||
| dateTimeFunction '(' expression ')'
|
||||
/**
|
||||
* The two formats for the 'substring() function: one defined by JPQL, the other by ANSI SQL
|
||||
*/
|
||||
substringFunction
|
||||
: SUBSTRING '(' expression ',' substringFunctionStartArgument (',' substringFunctionLengthArgument)? ')'
|
||||
| SUBSTRING '(' expression FROM substringFunctionStartArgument (FOR substringFunctionLengthArgument)? ')'
|
||||
;
|
||||
|
||||
substringFunctionStartArgument
|
||||
: expression
|
||||
;
|
||||
|
||||
substringFunctionLengthArgument
|
||||
: expression
|
||||
;
|
||||
|
||||
/**
|
||||
* The ANSI SQL-style 'trim()' function
|
||||
*/
|
||||
trimFunction
|
||||
: TRIM '(' (LEADING | TRAILING | BOTH)? stringLiteral? FROM? expression ')'
|
||||
: TRIM '(' trimSpecification? trimCharacter? FROM? expression ')'
|
||||
;
|
||||
|
||||
dateTimeFunction
|
||||
: d=(YEAR
|
||||
| MONTH
|
||||
| DAY
|
||||
| WEEK
|
||||
| QUARTER
|
||||
| HOUR
|
||||
| MINUTE
|
||||
| SECOND
|
||||
| NANOSECOND
|
||||
| EPOCH)
|
||||
trimSpecification
|
||||
: LEADING
|
||||
| TRAILING
|
||||
| BOTH
|
||||
;
|
||||
|
||||
trimCharacter
|
||||
: stringLiteral
|
||||
| parameter
|
||||
;
|
||||
|
||||
/**
|
||||
* A 'pad()' function inspired by 'trim()'
|
||||
*/
|
||||
padFunction
|
||||
: PAD '(' expression WITH padLength padSpecification padCharacter? ')'
|
||||
;
|
||||
|
||||
padSpecification
|
||||
: LEADING
|
||||
| TRAILING
|
||||
;
|
||||
|
||||
padCharacter
|
||||
: stringLiteral
|
||||
;
|
||||
|
||||
padLength
|
||||
: expression
|
||||
;
|
||||
|
||||
/**
|
||||
* The ANSI SQL-style 'position()' function
|
||||
*/
|
||||
positionFunction
|
||||
: POSITION '(' positionFunctionPatternArgument IN positionFunctionStringArgument ')'
|
||||
;
|
||||
|
||||
positionFunctionPatternArgument
|
||||
: expression
|
||||
;
|
||||
|
||||
positionFunctionStringArgument
|
||||
: expression
|
||||
;
|
||||
|
||||
/**
|
||||
* The ANSI SQL-style 'overlay()' function
|
||||
*/
|
||||
overlayFunction
|
||||
: OVERLAY '(' overlayFunctionStringArgument PLACING overlayFunctionReplacementArgument FROM overlayFunctionStartArgument (FOR overlayFunctionLengthArgument)? ')'
|
||||
;
|
||||
|
||||
overlayFunctionStringArgument
|
||||
: expression
|
||||
;
|
||||
|
||||
overlayFunctionReplacementArgument
|
||||
: expression
|
||||
;
|
||||
|
||||
overlayFunctionStartArgument
|
||||
: expression
|
||||
;
|
||||
|
||||
overlayFunctionLengthArgument
|
||||
: expression
|
||||
;
|
||||
|
||||
/**
|
||||
* The deprecated current_date function required by JPQL
|
||||
*/
|
||||
currentDateFunction
|
||||
: CURRENT_DATE ('(' ')')?
|
||||
| CURRENT DATE
|
||||
;
|
||||
|
||||
/**
|
||||
* The deprecated current_time function required by JPQL
|
||||
*/
|
||||
currentTimeFunction
|
||||
: CURRENT_TIME ('(' ')')?
|
||||
| CURRENT TIME
|
||||
;
|
||||
|
||||
/**
|
||||
* The deprecated current_timestamp function required by JPQL
|
||||
*/
|
||||
currentTimestampFunction
|
||||
: CURRENT_TIMESTAMP ('(' ')')?
|
||||
| CURRENT TIMESTAMP
|
||||
;
|
||||
|
||||
/**
|
||||
* The instant function, and deprecated current_instant function
|
||||
*/
|
||||
instantFunction
|
||||
: CURRENT_INSTANT ('(' ')')? //deprecated legacy syntax
|
||||
| INSTANT
|
||||
;
|
||||
|
||||
/**
|
||||
* The 'local datetime' function (or literal if you prefer)
|
||||
*/
|
||||
localDateTimeFunction
|
||||
: LOCAL_DATETIME ('(' ')')?
|
||||
| LOCAL DATETIME
|
||||
;
|
||||
|
||||
/**
|
||||
* The 'offset datetime' function (or literal if you prefer)
|
||||
*/
|
||||
offsetDateTimeFunction
|
||||
: OFFSET_DATETIME ('(' ')')?
|
||||
| OFFSET DATETIME
|
||||
;
|
||||
|
||||
/**
|
||||
* The 'local date' function (or literal if you prefer)
|
||||
*/
|
||||
localDateFunction
|
||||
: LOCAL_DATE ('(' ')')?
|
||||
| LOCAL DATE
|
||||
;
|
||||
|
||||
/**
|
||||
* The 'local time' function (or literal if you prefer)
|
||||
*/
|
||||
localTimeFunction
|
||||
: LOCAL_TIME ('(' ')')?
|
||||
| LOCAL TIME
|
||||
;
|
||||
|
||||
/**
|
||||
* The 'format()' function for formatting dates and times according to a pattern
|
||||
*/
|
||||
formatFunction
|
||||
: FORMAT '(' expression AS format ')'
|
||||
;
|
||||
|
||||
/**
|
||||
* The name of a database-defined collation
|
||||
*
|
||||
* Certain databases allow a period in a collation name
|
||||
*/
|
||||
collation
|
||||
: simplePath
|
||||
;
|
||||
|
||||
/**
|
||||
* The special 'collate()' functions
|
||||
*/
|
||||
collateFunction
|
||||
: COLLATE '(' expression AS collation ')'
|
||||
;
|
||||
|
||||
/**
|
||||
* The 'cube()' function specific to the 'group by' clause
|
||||
*/
|
||||
cube
|
||||
: CUBE '(' expressionOrPredicate (',' expressionOrPredicate)* ')'
|
||||
;
|
||||
|
||||
/**
|
||||
* The 'rollup()' function specific to the 'group by' clause
|
||||
*/
|
||||
rollup
|
||||
: ROLLUP '(' expressionOrPredicate (',' expressionOrPredicate)* ')'
|
||||
;
|
||||
|
||||
/**
|
||||
* A format pattern, with a syntax inspired by by java.time.format.DateTimeFormatter
|
||||
*
|
||||
* see 'Dialect.appendDatetimeFormat()'
|
||||
*/
|
||||
format
|
||||
: stringLiteral
|
||||
;
|
||||
|
||||
/**
|
||||
* The 'extract()' function for extracting fields of dates, times, and datetimes
|
||||
*/
|
||||
extractFunction
|
||||
: EXTRACT '(' extractField FROM expression ')'
|
||||
| datetimeField '(' expression ')'
|
||||
;
|
||||
|
||||
/**
|
||||
* The 'trunc()' function for truncating both numeric and datetime values
|
||||
*/
|
||||
truncFunction
|
||||
: (TRUNC | TRUNCATE) '(' expression (',' (datetimeField | expression))? ')'
|
||||
;
|
||||
|
||||
/**
|
||||
* A syntax for calling user-defined or native database functions, required by JPQL
|
||||
*/
|
||||
jpaNonstandardFunction
|
||||
: FUNCTION '(' jpaNonstandardFunctionName (AS castTarget)? (',' genericFunctionArguments)? ')'
|
||||
;
|
||||
|
||||
/**
|
||||
* The name of a user-defined or native database function, given as a quoted string
|
||||
*/
|
||||
jpaNonstandardFunctionName
|
||||
: stringLiteral
|
||||
| identifier
|
||||
;
|
||||
|
||||
columnFunction
|
||||
: COLUMN '(' path '.' jpaNonstandardFunctionName (AS castTarget)? ')'
|
||||
;
|
||||
|
||||
/**
|
||||
* Any function invocation that follows the regular syntax
|
||||
*
|
||||
* The function name, followed by a parenthesized list of ','-separated expressions
|
||||
*/
|
||||
genericFunction
|
||||
: genericFunctionName '(' (genericFunctionArguments | ASTERISK)? ')' pathContinutation?
|
||||
nthSideClause? nullsClause? withinGroupClause? filterClause? overClause?
|
||||
;
|
||||
|
||||
/**
|
||||
* The name of a generic function, which may contain periods and quoted identifiers
|
||||
*
|
||||
* Names of generic functions are resolved against the SqmFunctionRegistry
|
||||
*/
|
||||
genericFunctionName
|
||||
: simplePath
|
||||
;
|
||||
|
||||
/**
|
||||
* The arguments of a generic function
|
||||
*/
|
||||
genericFunctionArguments
|
||||
: (DISTINCT | datetimeField ',')? expressionOrPredicate (',' expressionOrPredicate)*
|
||||
;
|
||||
|
||||
/**
|
||||
* The special 'size()' function defined by JPQL
|
||||
*/
|
||||
collectionSizeFunction
|
||||
: SIZE '(' path ')'
|
||||
;
|
||||
|
||||
/**
|
||||
* Special rule for 'max(elements())`, 'avg(keys())', 'sum(indices())`, etc., as defined by HQL
|
||||
* Also the deprecated 'maxindex()', 'maxelement()', 'minindex()', 'minelement()' functions from old HQL
|
||||
*/
|
||||
collectionAggregateFunction
|
||||
: (MAX|MIN|SUM|AVG) '(' elementsValuesQuantifier '(' path ')' ')' # ElementAggregateFunction
|
||||
| (MAX|MIN|SUM|AVG) '(' indicesKeysQuantifier '(' path ')' ')' # IndexAggregateFunction
|
||||
| (MAXELEMENT|MINELEMENT) '(' path ')' # ElementAggregateFunction
|
||||
| (MAXINDEX|MININDEX) '(' path ')' # IndexAggregateFunction
|
||||
;
|
||||
|
||||
/**
|
||||
* To accommodate the misuse of elements() and indices() in the select clause
|
||||
*
|
||||
* (At some stage in the history of HQL, someone mixed them up with value() and index(),
|
||||
* and so we have tests that insist they're interchangeable. Ugh.)
|
||||
*/
|
||||
collectionFunctionMisuse
|
||||
: elementsValuesQuantifier '(' path ')'
|
||||
| indicesKeysQuantifier '(' path ')'
|
||||
;
|
||||
|
||||
/**
|
||||
* The special 'every()', 'all()', 'any()' and 'some()' functions defined by HQL
|
||||
*
|
||||
* May be applied to a subquery or collection reference, or may occur as an aggregate function in the 'select' clause
|
||||
*/
|
||||
aggregateFunction
|
||||
: everyFunction
|
||||
| anyFunction
|
||||
| listaggFunction
|
||||
;
|
||||
|
||||
/**
|
||||
* The functions 'every()' and 'all()' are synonyms
|
||||
*/
|
||||
everyFunction
|
||||
: every=(EVERY | ALL) '(' predicate ')'
|
||||
| every=(EVERY | ALL) '(' subquery ')'
|
||||
| every=(EVERY | ALL) (ELEMENTS | INDICES) '(' simplePath ')'
|
||||
: everyAllQuantifier '(' predicate ')' filterClause? overClause?
|
||||
| everyAllQuantifier '(' subquery ')'
|
||||
| everyAllQuantifier collectionQuantifier '(' simplePath ')'
|
||||
;
|
||||
|
||||
/**
|
||||
* The functions 'any()' and 'some()' are synonyms
|
||||
*/
|
||||
anyFunction
|
||||
: any=(ANY | SOME) '(' predicate ')'
|
||||
| any=(ANY | SOME) '(' subquery ')'
|
||||
| any=(ANY | SOME) (ELEMENTS | INDICES) '(' simplePath ')'
|
||||
: anySomeQuantifier '(' predicate ')' filterClause? overClause?
|
||||
| anySomeQuantifier '(' subquery ')'
|
||||
| anySomeQuantifier collectionQuantifier '(' simplePath ')'
|
||||
;
|
||||
|
||||
everyAllQuantifier
|
||||
: EVERY
|
||||
| ALL
|
||||
;
|
||||
|
||||
anySomeQuantifier
|
||||
: ANY
|
||||
| SOME
|
||||
;
|
||||
|
||||
/**
|
||||
* The 'listagg()' ordered set-aggregate function
|
||||
*/
|
||||
listaggFunction
|
||||
: LISTAGG '(' DISTINCT? expressionOrPredicate ',' expressionOrPredicate onOverflowClause? ')'
|
||||
withinGroupClause? filterClause? overClause?
|
||||
;
|
||||
|
||||
/**
|
||||
* A 'on overflow' clause: what to do when the text data type used for 'listagg' overflows
|
||||
*/
|
||||
onOverflowClause
|
||||
: ON OVERFLOW (ERROR | TRUNCATE expression? (WITH|WITHOUT) COUNT)
|
||||
;
|
||||
|
||||
/**
|
||||
* A 'within group' clause: defines the order in which the ordered set-aggregate function should work
|
||||
*/
|
||||
withinGroupClause
|
||||
: WITHIN GROUP '(' orderByClause ')'
|
||||
;
|
||||
|
||||
/**
|
||||
* A 'filter' clause: a restriction applied to an aggregate function
|
||||
*/
|
||||
filterClause
|
||||
: FILTER '(' whereClause ')'
|
||||
;
|
||||
|
||||
/**
|
||||
* A `nulls` clause: what should a value access window function do when encountering a `null`
|
||||
*/
|
||||
nullsClause
|
||||
: RESPECT NULLS
|
||||
| IGNORE NULLS
|
||||
;
|
||||
|
||||
/**
|
||||
* A `nulls` clause: what should a value access window function do when encountering a `null`
|
||||
*/
|
||||
nthSideClause
|
||||
: FROM FIRST
|
||||
| FROM LAST
|
||||
;
|
||||
|
||||
/**
|
||||
* A 'over' clause: the specification of a window within which the function should act
|
||||
*/
|
||||
overClause
|
||||
: OVER '(' partitionClause? orderByClause? frameClause? ')'
|
||||
;
|
||||
|
||||
/**
|
||||
* A 'partition' clause: the specification the group within which a function should act in a window
|
||||
*/
|
||||
partitionClause
|
||||
: PARTITION BY expression (',' expression)*
|
||||
;
|
||||
|
||||
/**
|
||||
* A 'frame' clause: the specification the content of the window
|
||||
*/
|
||||
frameClause
|
||||
: (RANGE|ROWS|GROUPS) frameStart frameExclusion?
|
||||
| (RANGE|ROWS|GROUPS) BETWEEN frameStart AND frameEnd frameExclusion?
|
||||
;
|
||||
|
||||
/**
|
||||
* The start of the window content
|
||||
*/
|
||||
frameStart
|
||||
: CURRENT ROW
|
||||
| UNBOUNDED PRECEDING
|
||||
| expression PRECEDING
|
||||
| expression FOLLOWING
|
||||
;
|
||||
|
||||
/**
|
||||
* The end of the window content
|
||||
*/
|
||||
frameEnd
|
||||
: CURRENT ROW
|
||||
| UNBOUNDED FOLLOWING
|
||||
| expression PRECEDING
|
||||
| expression FOLLOWING
|
||||
;
|
||||
|
||||
/**
|
||||
* A 'exclusion' clause: the specification what to exclude from the window content
|
||||
*/
|
||||
frameExclusion
|
||||
: EXCLUDE CURRENT ROW
|
||||
| EXCLUDE GROUP
|
||||
| EXCLUDE TIES
|
||||
| EXCLUDE NO OTHERS
|
||||
;
|
||||
|
||||
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-treat-type
|
||||
@@ -608,6 +1017,21 @@ expressionOrPredicate
|
||||
| predicate
|
||||
;
|
||||
|
||||
collectionQuantifier
|
||||
: elementsValuesQuantifier
|
||||
| indicesKeysQuantifier
|
||||
;
|
||||
|
||||
elementsValuesQuantifier
|
||||
: ELEMENTS
|
||||
| VALUES
|
||||
;
|
||||
|
||||
indicesKeysQuantifier
|
||||
: INDICES
|
||||
| KEYS
|
||||
;
|
||||
|
||||
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-relational-comparisons
|
||||
// NOTE: The TIP shows that "!=" is also supported. Hibernate's source code shows that "^=" is another NOT_EQUALS option as well.
|
||||
relationalExpression
|
||||
@@ -691,10 +1115,6 @@ identifier
|
||||
: reservedWord
|
||||
;
|
||||
|
||||
character
|
||||
: CHARACTER
|
||||
;
|
||||
|
||||
functionName
|
||||
: reservedWord ('.' reservedWord)*
|
||||
;
|
||||
@@ -998,6 +1418,7 @@ INTO : I N T O;
|
||||
IS : I S;
|
||||
JOIN : J O I N;
|
||||
KEY : K E Y;
|
||||
KEYS : K E Y S;
|
||||
LAST : L A S T;
|
||||
LATERAL : L A T E R A L;
|
||||
LEADING : L E A D I N G;
|
||||
@@ -1114,4 +1535,3 @@ BINARY_LITERAL : [xX] '\'' HEX_DIGIT+ '\''
|
||||
;
|
||||
|
||||
IDENTIFICATION_VARIABLE : ('a' .. 'z' | 'A' .. 'Z' | '\u0080' .. '\ufffe' | '$' | '_') ('a' .. 'z' | 'A' .. 'Z' | '\u0080' .. '\ufffe' | '0' .. '9' | '$' | '_')* ;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -37,6 +37,7 @@ import org.junit.jupiter.params.provider.ValueSource;
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @since 3.1
|
||||
*/
|
||||
class HqlQueryRendererTests {
|
||||
@@ -1551,9 +1552,11 @@ class HqlQueryRendererTests {
|
||||
assertQuery("SELECT o FROM Order o WHERE CAST(:userId AS java.util.UUID) IS NULL OR o.user.id = :userId");
|
||||
}
|
||||
|
||||
@Test // GH-3025
|
||||
void durationLiteralsShouldWork() {
|
||||
assertQuery("SELECT ce.id FROM CalendarEvent ce WHERE (ce.endDate - ce.startDate) > 5 MINUTE");
|
||||
@ParameterizedTest // GH-3025
|
||||
@ValueSource(strings = { "YEAR", "MONTH", "DAY", "WEEK", "QUARTER", "HOUR", "MINUTE", "SECOND", "NANOSECOND",
|
||||
"NANOSECOND", "EPOCH" })
|
||||
void durationLiteralsShouldWork(String dtField) {
|
||||
assertQuery("SELECT ce.id FROM CalendarEvent ce WHERE (ce.endDate - ce.startDate) > 5 %s".formatted(dtField));
|
||||
}
|
||||
|
||||
@Test // GH-3025
|
||||
|
||||
@@ -21,6 +21,9 @@ import org.antlr.v4.runtime.CharStreams;
|
||||
import org.antlr.v4.runtime.CommonTokenStream;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import org.springframework.data.jpa.repository.query.QueryRenderer.TokenRenderer;
|
||||
|
||||
/**
|
||||
@@ -31,6 +34,7 @@ import org.springframework.data.jpa.repository.query.QueryRenderer.TokenRenderer
|
||||
* IMPORTANT: Purely verifies the parser without any transformations.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @author Mark Paluch
|
||||
* @since 3.1
|
||||
*/
|
||||
class HqlSpecificationTests {
|
||||
@@ -331,6 +335,177 @@ class HqlSpecificationTests {
|
||||
""");
|
||||
}
|
||||
|
||||
@Test // GH-3689
|
||||
void generic() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e
|
||||
WHERE FOO(x).bar RESPECT NULLS
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e
|
||||
WHERE FOO(x).bar IGNORE NULLS
|
||||
""");
|
||||
}
|
||||
|
||||
@Test // GH-3689
|
||||
void size() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e
|
||||
WHERE SIZE(x) > 1
|
||||
""");
|
||||
}
|
||||
|
||||
@Test // GH-3689
|
||||
void collectionAggregate() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e
|
||||
WHERE MAXELEMENT(foo) > MINELEMENT(bar)
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e
|
||||
WHERE MININDEX(foo) > MAXINDEX(bar)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test // GH-3689
|
||||
void trunc() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e
|
||||
WHERE TRUNC(x) = TRUNCATE(y)
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e
|
||||
WHERE TRUNC(e, 'foo') = TRUNCATE(e, 'bar')
|
||||
""");
|
||||
}
|
||||
|
||||
@ParameterizedTest // GH-3689
|
||||
@ValueSource(strings = { "YYYY", "MONTH", "DAY", "WEEK", "QUARTER", "HOUR", "MINUTE", "SECOND", "NANOSECOND",
|
||||
"NANOSECOND", "EPOCH" })
|
||||
void trunc(String truncation) {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e
|
||||
WHERE TRUNC(e, %1$s) = TRUNCATE(e, %1$s)
|
||||
""".formatted(truncation));
|
||||
}
|
||||
|
||||
@Test // GH-3689
|
||||
void format() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e
|
||||
WHERE FORMAT(x AS 'foo') = FORMAT(x AS 'bar')
|
||||
""");
|
||||
}
|
||||
|
||||
@Test // GH-3689
|
||||
void collate() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e
|
||||
WHERE COLLATE(x AS foo) = COLLATE(x AS foo.bar)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test // GH-3689
|
||||
void substring() {
|
||||
|
||||
assertQuery("select substring(c.number, 1, 2) " + //
|
||||
"from Call c");
|
||||
|
||||
assertQuery("select substring(c.number, 1) " + //
|
||||
"from Call c");
|
||||
|
||||
assertQuery("select substring(c.number FROM 1 FOR 2) " + //
|
||||
"from Call c");
|
||||
|
||||
assertQuery("select substring(c.number FROM 1) " + //
|
||||
"from Call c");
|
||||
}
|
||||
|
||||
@Test // GH-3689
|
||||
void overlay() {
|
||||
|
||||
assertQuery("select OVERLAY(c.number PLACING 1 FROM 2) " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select OVERLAY(p.number PLACING 1 FROM 2 FOR 3) " + //
|
||||
"from Call c ");
|
||||
}
|
||||
|
||||
@Test // GH-3689
|
||||
void pad() {
|
||||
|
||||
assertQuery("select PAD(c.number WITH 1 LEADING) " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select PAD(c.number WITH 1 TRAILING) " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select PAD(c.number WITH 1 LEADING '0') " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select PAD(c.number WITH 1 TRAILING '0') " + //
|
||||
"from Call c ");
|
||||
}
|
||||
|
||||
@Test // GH-3689
|
||||
void position() {
|
||||
|
||||
assertQuery("select POSITION(c.number IN 'foo') " + //
|
||||
"from Call c ");
|
||||
}
|
||||
|
||||
@Test // GH-3689
|
||||
void currentDateFunctions() {
|
||||
|
||||
assertQuery("select CURRENT DATE, CURRENT_DATE() " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select CURRENT TIME, CURRENT_TIME() " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select CURRENT TIMESTAMP, CURRENT_TIMESTAMP() " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select INSTANT, CURRENT_INSTANT() " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select LOCAL DATE, LOCAL_DATE() " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select LOCAL TIME, LOCAL_TIME() " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select LOCAL DATETIME, LOCAL_DATETIME() " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select OFFSET DATETIME, OFFSET_DATETIME() " + //
|
||||
"from Call c ");
|
||||
}
|
||||
|
||||
@Test // GH-3689
|
||||
void cube() {
|
||||
|
||||
assertQuery("select CUBE(foo), CUBE(foo, bar) " + //
|
||||
"from Call c ");
|
||||
}
|
||||
|
||||
@Test // GH-3689
|
||||
void rollup() {
|
||||
|
||||
assertQuery("select ROLLUP(foo), ROLLUP(foo, bar) " + //
|
||||
"from Call c ");
|
||||
}
|
||||
|
||||
@Test
|
||||
void pathExpressionsNamedParametersExample() {
|
||||
|
||||
@@ -383,6 +558,80 @@ class HqlSpecificationTests {
|
||||
""");
|
||||
}
|
||||
|
||||
@Test // GH-3689
|
||||
void everyAll() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT emp
|
||||
FROM Employee emp
|
||||
WHERE EVERY (SELECT spouseEmp
|
||||
FROM Employee spouseEmp) > 1
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT emp
|
||||
FROM Employee emp
|
||||
WHERE ALL (SELECT spouseEmp
|
||||
FROM Employee spouseEmp) > 1
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT emp
|
||||
FROM Employee emp
|
||||
WHERE ALL (foo > 1) OVER (PARTITION BY bar)
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT emp
|
||||
FROM Employee emp
|
||||
WHERE ALL VALUES (foo) > 1
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT emp
|
||||
FROM Employee emp
|
||||
WHERE ALL ELEMENTS (foo) > 1
|
||||
""");
|
||||
}
|
||||
|
||||
@Test // GH-3689
|
||||
void anySome() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT emp
|
||||
FROM Employee emp
|
||||
WHERE ANY (SELECT spouseEmp
|
||||
FROM Employee spouseEmp) > 1
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT emp
|
||||
FROM Employee emp
|
||||
WHERE SOME (SELECT spouseEmp
|
||||
FROM Employee spouseEmp) > 1
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT emp
|
||||
FROM Employee emp
|
||||
WHERE ANY (foo > 1) OVER (PARTITION BY bar)
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT emp
|
||||
FROM Employee emp
|
||||
WHERE ANY VALUES (foo) > 1
|
||||
""");
|
||||
}
|
||||
|
||||
@Test // GH-3689
|
||||
void listAgg() {
|
||||
|
||||
assertQuery("select listagg(p.number, ', ') within group (order by p.type, p.number) " + //
|
||||
"from Phone p " + //
|
||||
"group by p.person");
|
||||
}
|
||||
|
||||
@Test
|
||||
void allExample() {
|
||||
|
||||
@@ -1119,9 +1368,6 @@ class HqlSpecificationTests {
|
||||
assertQuery("select concat(p.number, ' : ', cast(c.duration as string)) " + //
|
||||
"from Call c " + //
|
||||
"join c.phone p");
|
||||
assertQuery("select substring(p.number, 1, 2) " + //
|
||||
"from Call c " + //
|
||||
"join c.phone p");
|
||||
assertQuery("select upper(p.name) " + //
|
||||
"from Person p ");
|
||||
assertQuery("select lower(p.name) " + //
|
||||
@@ -1450,9 +1696,6 @@ class HqlSpecificationTests {
|
||||
"from Call c " + //
|
||||
"join c.phone p " + //
|
||||
"group by p.number");
|
||||
assertQuery("select listagg(p.number, ', ') within group (order by p.type, p.number) " + //
|
||||
"from Phone p " + //
|
||||
"group by p.person");
|
||||
assertQuery("select sum(c.duration) " + //
|
||||
"from Call c ");
|
||||
assertQuery("select p.name, sum(c.duration) " + //
|
||||
|
||||
Reference in New Issue
Block a user