This is an automated email from the ASF dual-hosted git repository.

eldenmoon pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 68f54696ee8 [fix](reverted index) Validate nested variant MATCH 
predicates (#66207)
68f54696ee8 is described below

commit 68f54696ee86543277917d54ca1179290380580e
Author: lihangyu <[email protected]>
AuthorDate: Mon Aug 3 20:36:10 2026 +0800

    [fix](reverted index) Validate nested variant MATCH predicates (#66207)
    
    Related PR: #61190
    
    Problem Summary: Root VARIANT MATCH predicates were rejected only when
    the Match expression was a top-level filter conjunct. A Match nested
    under OR could bypass frontend analysis and reach backend execution,
    where it failed with an unrelated runtime error. Recursively collect
    Match expressions from each filter expression and apply the existing
    operand and root Variant validation to every Match node. Add focused FE
    unit and regression coverage for a mixed text/root Variant OR predicate.
    
    ### Release note
    
    Reject MATCH predicates on VARIANT root columns even when nested in
    compound filter expressions.
    
    ### Check List (For Author)
    
    - Test: Regression test / Unit Test
    - `./run-regression-test.sh --run -d search -s
    test_disable_root_variant_match` (failed before the fix and passed after
    it)
    - `./run-fe-ut.sh --run
    org.apache.doris.nereids.rules.rewrite.CheckMatchExpressionTest`
        - `./build.sh --fe`
    - Behavior changed: Yes. Nested root VARIANT MATCH predicates now fail
    during FE analysis, consistent with direct predicates.
    - Does this need documentation: No
---
 .../rules/rewrite/CheckMatchExpression.java        | 26 ++++++++++------------
 .../rules/rewrite/CheckMatchExpressionTest.java    | 14 ++++++++++++
 .../search/test_disable_root_variant_match.groovy  | 22 +++++++++++++++---
 3 files changed, 45 insertions(+), 17 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/CheckMatchExpression.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/CheckMatchExpression.java
index 8f0ad8706f3..c5923ab80da 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/CheckMatchExpression.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/CheckMatchExpression.java
@@ -47,20 +47,18 @@ public class CheckMatchExpression extends 
OneRewriteRuleFactory {
 
     private Plan checkChildren(LogicalFilter<? extends Plan> filter) {
         List<Expression> expressions = filter.getExpressions();
-        for (Expression expr : expressions) {
-            if (expr instanceof Match) {
-                Match matchExpression = (Match) expr;
-                SlotReference slotReference = 
getSlotFromSlotCastOrAliasChain(matchExpression.left());
-                if (slotReference == null
-                        || !(matchExpression.right() instanceof Literal)) {
-                    throw new AnalysisException(String.format("Only support 
match left operand is SlotRef,"
-                            + " right operand is Literal. But meet expression 
%s", matchExpression));
-                }
-                if (slotReference.getDataType().isVariantType() && 
!slotReference.hasSubColPath()) {
-                    throw new AnalysisException(String.format("VARIANT root 
column does not support MATCH predicates. "
-                                    + "Please query a subcolumn instead, for 
example %s['field'] MATCH 'xxx'",
-                            slotReference.getName()));
-                }
+        List<Match> matchExpressions = 
ExpressionUtils.collectToList(expressions, Match.class::isInstance);
+        for (Match matchExpression : matchExpressions) {
+            SlotReference slotReference = 
getSlotFromSlotCastOrAliasChain(matchExpression.left());
+            if (slotReference == null
+                    || !(matchExpression.right() instanceof Literal)) {
+                throw new AnalysisException(String.format("Only support match 
left operand is SlotRef,"
+                        + " right operand is Literal. But meet expression %s", 
matchExpression));
+            }
+            if (slotReference.getDataType().isVariantType() && 
!slotReference.hasSubColPath()) {
+                throw new AnalysisException(String.format("VARIANT root column 
does not support MATCH predicates. "
+                                + "Please query a subcolumn instead, for 
example %s['field'] MATCH 'xxx'",
+                        slotReference.getName()));
             }
         }
         return filter;
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/CheckMatchExpressionTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/CheckMatchExpressionTest.java
index c1991a08aa7..93fb9e82264 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/CheckMatchExpressionTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/CheckMatchExpressionTest.java
@@ -23,6 +23,7 @@ import org.apache.doris.nereids.trees.expressions.Alias;
 import org.apache.doris.nereids.trees.expressions.Cast;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.MatchAny;
+import org.apache.doris.nereids.trees.expressions.Or;
 import org.apache.doris.nereids.trees.expressions.SlotReference;
 import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.StringLiteral;
@@ -63,6 +64,19 @@ class CheckMatchExpressionTest {
                 exception.getMessage());
     }
 
+    @Test
+    void testRejectsRootVariantMatchNestedInOr() {
+        SlotReference textSlot = new SlotReference("response_body", 
StringType.INSTANCE, true);
+        SlotReference rootVariantSlot = new SlotReference("response", 
VariantType.INSTANCE, true, Arrays.asList());
+        Or match = new Or(
+                new MatchAny(textSlot, new StringLiteral("doris")),
+                new MatchAny(rootVariantSlot, new StringLiteral("doris")));
+
+        AnalysisException exception = 
Assertions.assertThrows(AnalysisException.class, () -> invokeCheck(match));
+        Assertions.assertTrue(exception.getMessage().contains("VARIANT root 
column does not support MATCH"),
+                exception.getMessage());
+    }
+
     @Test
     void testRejectsCastOnRootVariantMatch() {
         SlotReference rootVariantSlot = new SlotReference("response", 
VariantType.INSTANCE, true, Arrays.asList());
diff --git 
a/regression-test/suites/search/test_disable_root_variant_match.groovy 
b/regression-test/suites/search/test_disable_root_variant_match.groovy
index 4236e61b4da..d6e26a881a4 100644
--- a/regression-test/suites/search/test_disable_root_variant_match.groovy
+++ b/regression-test/suites/search/test_disable_root_variant_match.groovy
@@ -26,10 +26,15 @@ suite("test_disable_root_variant_match", "p0") {
     sql """
         CREATE TABLE test_disable_root_variant_match_tbl (
             `id` INT NOT NULL,
+            `response_body` TEXT NULL,
             `response` variant<
                 MATCH_NAME 'msg' : string,
                 properties("variant_max_subcolumns_count" = "16")
             > NULL,
+            INDEX idx_response_body (response_body) USING INVERTED PROPERTIES(
+                "parser" = "unicode",
+                "lower_case" = "true"
+            ),
             INDEX idx_response (response) USING INVERTED PROPERTIES(
                 "parser" = "unicode",
                 "field_pattern" = "msg",
@@ -45,9 +50,9 @@ suite("test_disable_root_variant_match", "p0") {
     """
 
     sql """INSERT INTO test_disable_root_variant_match_tbl VALUES
-        (1, '{"msg": "doris community"}'),
-        (2, '{"msg": "apache software"}'),
-        (3, '{"msg": "doris variant index"}')
+        (1, 'doris community', '{"msg": "doris community"}'),
+        (2, 'apache software', '{"msg": "apache software"}'),
+        (3, 'doris variant index', '{"msg": "doris variant index"}')
     """
 
     sql "sync"
@@ -63,6 +68,17 @@ suite("test_disable_root_variant_match", "p0") {
         exception "VARIANT root column does not support MATCH"
     }
 
+    test {
+        sql """
+            SELECT /*+SET_VAR(enable_segment_limit_pushdown=true)*/ id
+            FROM test_disable_root_variant_match_tbl
+            WHERE response_body MATCH_ANY 'doris'
+                OR response MATCH_ANY 'doris'
+            ORDER BY id
+        """
+        exception "VARIANT root column does not support MATCH"
+    }
+
     def variantSubcolumnMatchResult = sql """
         SELECT /*+SET_VAR(enable_segment_limit_pushdown=true)*/ id
         FROM test_disable_root_variant_match_tbl


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to