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

JackieTien97 pushed a commit to branch ty/fix-pattern-match-repetition-signs
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit 86b651ba5ecb2642c7f1ce1e84aa27934666abea
Author: JackieTien97 <[email protected]>
AuthorDate: Thu Oct 22 12:27:46 2026 +0800

    [Bug] Reject misplaced repetition signs in pattern_match
---
 .../relational/it/db/it/IoTDBWindowTVFIT.java      | 55 ++++++++++++++++------
 .../apache/iotdb/commons/i18n/QueryMessages.java   |  2 +
 .../apache/iotdb/commons/i18n/QueryMessages.java   |  2 +
 .../function/tvf/match/QetchAlgorithm.java         |  7 +++
 .../tvf/PatternMatchTableFunctionTest.java         | 45 +++++++++++++++++-
 5 files changed, 96 insertions(+), 15 deletions(-)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBWindowTVFIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBWindowTVFIT.java
index 22d099e5bae..0adddc0cf69 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBWindowTVFIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBWindowTVFIT.java
@@ -1083,20 +1083,50 @@ public class IoTDBWindowTVFIT {
 
   @Test
   public void testPatternMatchEmptyRepetitionGroups() throws SQLException {
+    assertInvalidPatternMatchPatterns(
+        new String[] {
+          "1,{,}+,1",
+          "1,{}+,1",
+          "1,{ , , }*,1",
+          "{,}+,1,2",
+          "1,2,{,}+",
+          "1,{2,{,}+,3}+,1",
+          "1,{{,}*}+,1"
+        },
+        "Repetition groups must contain at least one numeric data point.");
+  }
+
+  @Test
+  public void testPatternMatchMisplacedRepetitionSigns() throws SQLException {
+    assertInvalidPatternMatchPatterns(
+        new String[] {
+          "1,+,2",
+          "1,*,2",
+          "1, + ,2",
+          "1, * ,2",
+          "+,1,2",
+          "*,1,2",
+          "1,2,+",
+          "1,2,*",
+          "1+,2",
+          "1*,2",
+          "1,{2,+,3}+,1",
+          "1,{2,*,3}*,1",
+          "1,{2,3}++,1",
+          "1,{2,3}+*,1",
+          "1,{2,3}*+,1",
+          "1,{2,3}**,1"
+        },
+        "Repetition signs '+' and '*' must immediately follow '}'.");
+  }
+
+  private void assertInvalidPatternMatchPatterns(String[] patterns, String 
expectedMessage)
+      throws SQLException {
     try (Connection connection = EnvFactory.getEnv().getTableConnection();
         Statement statement = connection.createStatement()) {
       statement.execute("USE " + DATABASE_NAME);
       for (String data : new String[] {"t1", "(SELECT * FROM t1 WHERE time < 
0)"}) {
-        for (String pattern :
-            new String[] {
-              "1,{,}+,1",
-              "1,{}+,1",
-              "1,{ , , }*,1",
-              "{,}+,1,2",
-              "1,2,{,}+",
-              "1,{2,{,}+,3}+,1",
-              "1,{{,}*}+,1"
-            }) {
+        for (String pattern : patterns) {
           SQLException exception =
               assertThrows(
                   SQLException.class,
@@ -1115,10 +1145,7 @@ public class IoTDBWindowTVFIT {
               exception.getMessage(),
               exception
                   .getMessage()
-                  .contains(
-                      "Invalid pattern: '"
-                          + pattern
-                          + "'. Repetition groups must contain at least one 
numeric data point."));
+                  .contains("Invalid pattern: '" + pattern + "'. " + 
expectedMessage));
         }
       }
     }
diff --git 
a/iotdb-core/node-commons/src/main/i18n/en/org/apache/iotdb/commons/i18n/QueryMessages.java
 
b/iotdb-core/node-commons/src/main/i18n/en/org/apache/iotdb/commons/i18n/QueryMessages.java
index 6f8fe1f305f..877bb671f6d 100644
--- 
a/iotdb-core/node-commons/src/main/i18n/en/org/apache/iotdb/commons/i18n/QueryMessages.java
+++ 
b/iotdb-core/node-commons/src/main/i18n/en/org/apache/iotdb/commons/i18n/QueryMessages.java
@@ -163,6 +163,8 @@ public final class QueryMessages {
       "height must be a non-negative number, but got: %s";
   public static final String INVALID_PATTERN_MISSING_REPEAT_SIGN =
       "Invalid pattern: %s, missing repeat sign after '}'";
+  public static final String 
EXCEPTION_INVALID_PATTERN_ARG_REPETITION_SIGNS_AND_MUST_IMMEDIATELY_FOLLOW_30FC3998
 =
+      "Invalid pattern: '%s'. Repetition signs '+' and '*' must immediately 
follow '}'.";
   public static final String INVALID_PATTERN_MUST_CONTAIN_DATA_POINTS =
       "Invalid pattern: '%s'. Pattern must contain at least two numeric data 
points separated by commas, e.g., '1,2,3'";
   public static final String 
EXCEPTION_INVALID_PATTERN_ARG_REPETITION_GROUPS_MUST_CONTAIN_AT_LEAST_ONE_NUMERIC_DATA_POINT_E1880CCB
 =
diff --git 
a/iotdb-core/node-commons/src/main/i18n/zh/org/apache/iotdb/commons/i18n/QueryMessages.java
 
b/iotdb-core/node-commons/src/main/i18n/zh/org/apache/iotdb/commons/i18n/QueryMessages.java
index 19c5d8db981..840fb99ec6e 100644
--- 
a/iotdb-core/node-commons/src/main/i18n/zh/org/apache/iotdb/commons/i18n/QueryMessages.java
+++ 
b/iotdb-core/node-commons/src/main/i18n/zh/org/apache/iotdb/commons/i18n/QueryMessages.java
@@ -163,6 +163,8 @@ public final class QueryMessages {
       "height 必须为非负数,但传入了:%s";
   public static final String INVALID_PATTERN_MISSING_REPEAT_SIGN =
       "无效的模式:%s,'}' 后缺少重复符号";
+  public static final String 
EXCEPTION_INVALID_PATTERN_ARG_REPETITION_SIGNS_AND_MUST_IMMEDIATELY_FOLLOW_30FC3998
 =
+      "无效的模式:'%s'。重复符号 '+' 和 '*' 必须紧跟在 '}' 后。";
   public static final String INVALID_PATTERN_MUST_CONTAIN_DATA_POINTS =
       "无效的模式:'%s'。模式必须包含至少两个以逗号分隔的数值数据点,例如 '1,2,3'";
   public static final String 
EXCEPTION_INVALID_PATTERN_ARG_REPETITION_GROUPS_MUST_CONTAIN_AT_LEAST_ONE_NUMERIC_DATA_POINT_E1880CCB
 =
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/queryengine/plan/relational/function/tvf/match/QetchAlgorithm.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/queryengine/plan/relational/function/tvf/match/QetchAlgorithm.java
index d0ef585197a..af231849631 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/queryengine/plan/relational/function/tvf/match/QetchAlgorithm.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/queryengine/plan/relational/function/tvf/match/QetchAlgorithm.java
@@ -106,6 +106,13 @@ public class QetchAlgorithm {
             throw new IllegalArgumentException(
                 
String.format(QueryMessages.INVALID_PATTERN_MISSING_REPEAT_SIGN, pattern));
           }
+        } else if (c == '+' || c == '*') {
+          // Valid repetition signs are consumed together with the preceding 
'}'.
+          throw new IllegalArgumentException(
+              String.format(
+                  QueryMessages
+                      
.EXCEPTION_INVALID_PATTERN_ARG_REPETITION_SIGNS_AND_MUST_IMMEDIATELY_FOLLOW_30FC3998,
+                  pattern));
         } else if (Character.isDigit(c) || c == '.' || c == '-') {
           // scan the number, and push it to the list
           StringBuilder numBuilder = new StringBuilder();
diff --git 
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/queryengine/plan/relational/function/tvf/PatternMatchTableFunctionTest.java
 
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/queryengine/plan/relational/function/tvf/PatternMatchTableFunctionTest.java
index 6dd55366ec1..a55813fa599 100644
--- 
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/queryengine/plan/relational/function/tvf/PatternMatchTableFunctionTest.java
+++ 
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/queryengine/plan/relational/function/tvf/PatternMatchTableFunctionTest.java
@@ -78,6 +78,41 @@ public class PatternMatchTableFunctionTest {
     }
   }
 
+  @Test
+  public void testRejectMisplacedRepetitionSigns() {
+    for (String pattern :
+        new String[] {
+          "1,+,2",
+          "1,*,2",
+          "1, + ,2",
+          "1, * ,2",
+          "+,1,2",
+          "*,1,2",
+          "1,2,+",
+          "1,2,*",
+          "1+,2",
+          "1*,2",
+          "1,{2,+,3}+,1",
+          "1,{2,*,3}*,1",
+          "1,{2,3}++,1",
+          "1,{2,3}+*,1",
+          "1,{2,3}*+,1",
+          "1,{2,3}**,1"
+        }) {
+      String expectedMessage =
+          String.format(
+              QueryMessages
+                  
.EXCEPTION_INVALID_PATTERN_ARG_REPETITION_SIGNS_AND_MUST_IMMEDIATELY_FOLLOW_30FC3998,
+              pattern);
+      assertInvalidPattern(pattern, expectedMessage);
+      IllegalArgumentException exception =
+          assertThrows(
+              IllegalArgumentException.class,
+              () -> new QetchAlgorithm().parsePattern2Automaton(pattern));
+      assertEquals(expectedMessage, exception.getMessage());
+    }
+  }
+
   @Test
   public void testRejectMalformedPatternsDuringAnalysis() {
     for (String pattern : new String[] {null, "", "1", "abc,def,ghi"}) {
@@ -103,7 +138,15 @@ public class PatternMatchTableFunctionTest {
   @Test
   public void testAcceptNonEmptyRepetitionGroups() {
     for (String pattern :
-        new String[] {"1,{2,3,2}+,1", "1,{,2,3,2,}*,1", "1,{{2,3,2}+}+,1", 
"1,{2,{3,2}+,1}+,1"}) {
+        new String[] {
+          "1,{2,3,2}+,1",
+          "1,{2,3,2}*,1",
+          "1,{,2,3,2,}*,1",
+          "1,{{2,3,2}+}+,1",
+          "1,{{2,3,2}*}+,1",
+          "1,{2,{3,2}+,1}+,1",
+          "1,{2,{3,2}*,1}+,1"
+        }) {
       assertNotNull(createProvider(pattern).getDataProcessor());
     }
   }

Reply via email to