Skip to content

Commit 71bc2df

Browse files
committed
HHH-3404 introduce 'like regexp' and 'ilike regexp' syntax sugar
HHH-3404 oops
1 parent e0ba29b commit 71bc2df

File tree

4 files changed

+35
-8
lines changed

4 files changed

+35
-8
lines changed

hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlLexer.g4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ POSITION : [pP] [oO] [sS] [iI] [tT] [iI] [oO] [nN];
292292
PRECEDING : [pP] [rR] [eE] [cC] [eE] [dD] [iI] [nN] [gG];
293293
QUARTER : [qQ] [uU] [aA] [rR] [tT] [eE] [rR];
294294
RANGE : [rR] [aA] [nN] [gG] [eE];
295+
REGEXP : [rR] [eE] [gG] [eE] [xX] [pP];
295296
RESPECT : [rR] [eE] [sS] [pP] [eE] [cC] [tT];
296297
RETURNING : [rR] [eE] [tT] [uU] [rR] [nN] [iI] [nN] [gG];
297298
RIGHT : [rR] [iI] [gG] [hH] [tT];

hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,7 @@ predicate
669669
| expression NOT? MEMBER OF? path # MemberOfPredicate
670670
| expression NOT? IN inList # InPredicate
671671
| expression NOT? BETWEEN expression AND expression # BetweenPredicate
672-
| expression NOT? (LIKE | ILIKE) expression likeEscape? # LikePredicate
672+
| expression NOT? (LIKE | ILIKE) REGEXP? expression likeEscape? # LikePredicate
673673
| expression NOT? CONTAINS expression # ContainsPredicate
674674
| expression NOT? INCLUDES expression # IncludesPredicate
675675
| expression NOT? INTERSECTS expression # IntersectsPredicate
@@ -1998,6 +1998,7 @@ xmltableDefaultClause
19981998
| PRECEDING
19991999
| QUARTER
20002000
| RANGE
2001+
| REGEXP
20012002
| RESPECT
20022003
| RETURNING
20032004
// | RIGHT

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

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3222,19 +3222,43 @@ public SqmPredicate visitIntersectsPredicate(HqlParser.IntersectsPredicateContex
32223222
public SqmPredicate visitLikePredicate(HqlParser.LikePredicateContext ctx) {
32233223
final boolean negated = ctx.NOT() != null;
32243224
final boolean caseSensitive = ctx.LIKE() != null;
3225-
if ( ctx.likeEscape() == null ) {
3225+
final SqmExpression<?> expression = (SqmExpression<?>) ctx.expression( 0 ).accept( this );
3226+
final SqmExpression<?> pattern = (SqmExpression<?>) ctx.expression( 1 ).accept( this );
3227+
if ( ctx.REGEXP() != null ) {
3228+
if ( ctx.likeEscape() != null ) {
3229+
throw new SemanticException( "'ESCAPE' may not be used with 'LIKE REGEXP'", query );
3230+
}
3231+
return new SqmBooleanExpressionPredicate(
3232+
getFunctionDescriptor( "regexp_like" )
3233+
.generateSqmExpression(
3234+
caseSensitive
3235+
? asList( expression, pattern )
3236+
: asList( expression, pattern,
3237+
new SqmLiteral<>( "i",
3238+
resolveExpressibleTypeBasic( String.class ),
3239+
nodeBuilder()
3240+
)
3241+
),
3242+
null,
3243+
queryEngine()
3244+
),
3245+
negated,
3246+
nodeBuilder()
3247+
);
3248+
}
3249+
else if ( ctx.likeEscape() == null ) {
32263250
return new SqmLikePredicate(
3227-
(SqmExpression<?>) ctx.expression(0).accept( this ),
3228-
(SqmExpression<?>) ctx.expression(1).accept( this ),
3251+
expression,
3252+
pattern,
32293253
negated,
32303254
caseSensitive,
32313255
nodeBuilder()
32323256
);
32333257
}
32343258
else {
32353259
return new SqmLikePredicate(
3236-
(SqmExpression<?>) ctx.expression(0).accept( this ),
3237-
(SqmExpression<?>) ctx.expression(1).accept( this ),
3260+
expression,
3261+
pattern,
32383262
(SqmExpression<?>) ctx.likeEscape().accept( this ),
32393263
negated,
32403264
caseSensitive,
@@ -4338,9 +4362,8 @@ private SqmLiteral<String> stringLiteral(String text) {
43384362
}
43394363

43404364
private SqmLiteral<String> javaStringLiteral(String text) {
4341-
String unquoted = unquoteJavaStringLiteral( text );
43424365
return new SqmLiteral<>(
4343-
unquoted,
4366+
unquoteJavaStringLiteral( text ),
43444367
resolveExpressibleTypeBasic( String.class ),
43454368
nodeBuilder()
43464369
);

hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/RegexTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ void testInSelect(EntityManagerFactoryScope scope) {
4444
void testInSelectCaseInsensitive(EntityManagerFactoryScope scope) {
4545
scope.inEntityManager( em -> {
4646
assertTrue( em.createQuery( "select regexp_like('ABCDEF', 'ab.*', 'i')", Boolean.class ).getSingleResult() );
47+
assertTrue( em.createQuery( "select 'abcdef' ilike regexp 'ab.*'", Boolean.class ).getSingleResult() );
4748
} );
4849
}
4950

@@ -55,6 +56,7 @@ void testInSelectCaseInsensitive(EntityManagerFactoryScope scope) {
5556
void testInWhere(EntityManagerFactoryScope scope) {
5657
scope.inEntityManager( em -> {
5758
assertEquals( 1, em.createQuery( "select 1 where regexp_like('abcdef', 'ab.*')", Integer.class ).getSingleResult() );
59+
assertEquals( 1, em.createQuery( "select 1 where 'abcdef' like regexp 'ab.*'", Integer.class ).getSingleResult() );
5860
} );
5961
}
6062
}

0 commit comments

Comments
 (0)