This is an automated email from the ASF dual-hosted git repository.
JackieTien97 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new 4b0099f05a3 [Bug] Reject misplaced repetition signs in pattern_match
(#18983)
4b0099f05a3 is described below
commit 4b0099f05a396cf5dd673ff721791f58c8ccb2ef
Author: Jackie Tien <[email protected]>
AuthorDate: Thu Oct 22 14:18:14 2026 +0800
[Bug] Reject misplaced repetition signs in pattern_match (#18983)
---
.../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());
}
}