Browse Source

ES|QL: Fix RLIKE folding with (unsupported) case insensitive pattern (#118454) (#118769)

Luigi Dell'Aquila 10 months ago
parent
commit
b4d0f905e1

+ 5 - 0
docs/changelog/118454.yaml

@@ -0,0 +1,5 @@
+pr: 118454
+summary: Fix RLIKE folding with (unsupported) case insensitive pattern
+area: ES|QL
+type: bug
+issues: []

+ 1 - 11
x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/RLike.java

@@ -8,12 +8,11 @@ package org.elasticsearch.xpack.esql.core.expression.predicate.regex;
 
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
-import org.elasticsearch.xpack.esql.core.tree.NodeInfo;
 import org.elasticsearch.xpack.esql.core.tree.Source;
 
 import java.io.IOException;
 
-public class RLike extends RegexMatch<RLikePattern> {
+public abstract class RLike extends RegexMatch<RLikePattern> {
 
     public RLike(Source source, Expression value, RLikePattern pattern) {
         super(source, value, pattern, false);
@@ -33,13 +32,4 @@ public class RLike extends RegexMatch<RLikePattern> {
         throw new UnsupportedOperationException();
     }
 
-    @Override
-    protected NodeInfo<RLike> info() {
-        return NodeInfo.create(this, RLike::new, field(), pattern(), caseInsensitive());
-    }
-
-    @Override
-    protected RLike replaceChild(Expression newChild) {
-        return new RLike(source(), newChild, pattern(), caseInsensitive());
-    }
 }

+ 1 - 6
x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/RegexMatch.java

@@ -7,7 +7,6 @@
 
 package org.elasticsearch.xpack.esql.core.expression.predicate.regex;
 
-import org.apache.lucene.util.BytesRef;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
 import org.elasticsearch.xpack.esql.core.expression.Nullability;
 import org.elasticsearch.xpack.esql.core.expression.function.scalar.UnaryScalarFunction;
@@ -64,11 +63,7 @@ public abstract class RegexMatch<T extends StringPattern> extends UnaryScalarFun
 
     @Override
     public Boolean fold() {
-        Object val = field().fold();
-        if (val instanceof BytesRef br) {
-            val = br.utf8ToString();
-        }
-        return RegexOperation.match(val, pattern().asJavaRegex());
+        throw new UnsupportedOperationException();
     }
 
     @Override

+ 1 - 12
x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/WildcardLike.java

@@ -8,12 +8,11 @@ package org.elasticsearch.xpack.esql.core.expression.predicate.regex;
 
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
-import org.elasticsearch.xpack.esql.core.tree.NodeInfo;
 import org.elasticsearch.xpack.esql.core.tree.Source;
 
 import java.io.IOException;
 
-public class WildcardLike extends RegexMatch<WildcardPattern> {
+public abstract class WildcardLike extends RegexMatch<WildcardPattern> {
 
     public WildcardLike(Source source, Expression left, WildcardPattern pattern) {
         this(source, left, pattern, false);
@@ -33,14 +32,4 @@ public class WildcardLike extends RegexMatch<WildcardPattern> {
         throw new UnsupportedOperationException();
     }
 
-    @Override
-    protected NodeInfo<WildcardLike> info() {
-        return NodeInfo.create(this, WildcardLike::new, field(), pattern(), caseInsensitive());
-    }
-
-    @Override
-    protected WildcardLike replaceChild(Expression newLeft) {
-        return new WildcardLike(source(), newLeft, pattern(), caseInsensitive());
-    }
-
 }

+ 0 - 6
x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/util/TestUtils.java

@@ -11,8 +11,6 @@ import org.elasticsearch.xpack.esql.core.expression.Expression;
 import org.elasticsearch.xpack.esql.core.expression.FieldAttribute;
 import org.elasticsearch.xpack.esql.core.expression.Literal;
 import org.elasticsearch.xpack.esql.core.expression.predicate.Range;
-import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLike;
-import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLikePattern;
 import org.elasticsearch.xpack.esql.core.tree.Source;
 import org.elasticsearch.xpack.esql.core.type.DataType;
 import org.elasticsearch.xpack.esql.core.type.EsField;
@@ -46,10 +44,6 @@ public final class TestUtils {
         return new Range(EMPTY, value, lower, includeLower, upper, includeUpper, randomZone());
     }
 
-    public static RLike rlike(Expression left, String exp) {
-        return new RLike(EMPTY, left, new RLikePattern(exp));
-    }
-
     public static FieldAttribute fieldAttribute() {
         return fieldAttribute(randomAlphaOfLength(10), randomFrom(DataType.types()));
     }

+ 36 - 0
x-pack/plugin/esql/qa/testFixtures/src/main/resources/eval.csv-spec

@@ -601,3 +601,39 @@ Mokhtar             |Bernatsky          |38992          |BM
 Parto               |Bamford            |61805          |BP
 Premal              |Baek               |52833          |BP
 ;
+
+
+caseInsensitiveRegex
+from employees | where first_name RLIKE "(?i)geor.*" | keep first_name
+;
+
+first_name:keyword
+;
+
+
+caseInsensitiveRegex2
+from employees | where first_name RLIKE "(?i)Geor.*" | keep first_name
+;
+
+first_name:keyword
+;
+
+
+caseInsensitiveRegexFold
+required_capability: fixed_regex_fold
+row foo = "Bar" | where foo rlike "(?i)ba.*"
+;
+
+foo:keyword
+;
+
+
+caseInsensitiveRegexFold2
+required_capability: fixed_regex_fold
+row foo = "Bar" | where foo rlike "(?i)Ba.*"
+;
+
+foo:keyword
+;
+
+

+ 6 - 1
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java

@@ -562,7 +562,12 @@ public class EsqlCapabilities {
         /**
          * Additional types for match function and operator
          */
-        MATCH_ADDITIONAL_TYPES;
+        MATCH_ADDITIONAL_TYPES,
+
+        /**
+         * Fix for regex folding with case-insensitive pattern https://github.com/elastic/elasticsearch/issues/118371
+         */
+        FIXED_REGEX_FOLD;
 
         private final boolean enabled;
 

+ 6 - 1
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RLike.java

@@ -79,7 +79,7 @@ public class RLike extends org.elasticsearch.xpack.esql.core.expression.predicat
     }
 
     @Override
-    protected NodeInfo<org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLike> info() {
+    protected NodeInfo<RLike> info() {
         return NodeInfo.create(this, RLike::new, field(), pattern(), caseInsensitive());
     }
 
@@ -93,6 +93,11 @@ public class RLike extends org.elasticsearch.xpack.esql.core.expression.predicat
         return isString(field(), sourceText(), DEFAULT);
     }
 
+    @Override
+    public Boolean fold() {
+        return (Boolean) EvaluatorMapper.super.fold();
+    }
+
     @Override
     public EvalOperator.ExpressionEvaluator.Factory toEvaluator(ToEvaluator toEvaluator) {
         return AutomataMatch.toEvaluator(source(), toEvaluator.apply(field()), pattern().createAutomaton());

+ 5 - 0
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLike.java

@@ -99,6 +99,11 @@ public class WildcardLike extends org.elasticsearch.xpack.esql.core.expression.p
         return isString(field(), sourceText(), DEFAULT);
     }
 
+    @Override
+    public Boolean fold() {
+        return (Boolean) EvaluatorMapper.super.fold();
+    }
+
     @Override
     public EvalOperator.ExpressionEvaluator.Factory toEvaluator(ToEvaluator toEvaluator) {
         return AutomataMatch.toEvaluator(

+ 2 - 2
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/ConstantFoldingTests.java

@@ -17,11 +17,11 @@ import org.elasticsearch.xpack.esql.core.expression.predicate.BinaryOperator;
 import org.elasticsearch.xpack.esql.core.expression.predicate.logical.And;
 import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Not;
 import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Or;
-import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLike;
 import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLikePattern;
-import org.elasticsearch.xpack.esql.core.expression.predicate.regex.WildcardLike;
 import org.elasticsearch.xpack.esql.core.expression.predicate.regex.WildcardPattern;
 import org.elasticsearch.xpack.esql.core.type.DataType;
+import org.elasticsearch.xpack.esql.expression.function.scalar.string.RLike;
+import org.elasticsearch.xpack.esql.expression.function.scalar.string.WildcardLike;
 import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Add;
 import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Div;
 import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Mod;

+ 1 - 1
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PushDownAndCombineFiltersTests.java

@@ -199,7 +199,7 @@ public class PushDownAndCombineFiltersTests extends ESTestCase {
 
     public void testPushDownLikeRlikeFilter() {
         EsRelation relation = relation();
-        org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLike conditionA = rlike(getFieldAttribute("a"), "foo");
+        RLike conditionA = rlike(getFieldAttribute("a"), "foo");
         WildcardLike conditionB = wildcardLike(getFieldAttribute("b"), "bar");
 
         Filter fa = new Filter(EMPTY, relation, conditionA);

+ 2 - 2
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/ReplaceRegexMatchTests.java

@@ -11,11 +11,11 @@ import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
 import org.elasticsearch.xpack.esql.core.expression.FieldAttribute;
 import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNotNull;
-import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLike;
 import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLikePattern;
-import org.elasticsearch.xpack.esql.core.expression.predicate.regex.WildcardLike;
 import org.elasticsearch.xpack.esql.core.expression.predicate.regex.WildcardPattern;
 import org.elasticsearch.xpack.esql.core.util.StringUtils;
+import org.elasticsearch.xpack.esql.expression.function.scalar.string.RLike;
+import org.elasticsearch.xpack.esql.expression.function.scalar.string.WildcardLike;
 import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.Equals;
 
 import static java.util.Arrays.asList;