You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by hu...@apache.org on 2022/10/28 02:44:03 UTC
[iotdb] branch rel/0.13 updated: [To rel/0.13][IOTDB-4781] Implement NOT LIKE/REGEXP value filter (#7764)
This is an automated email from the ASF dual-hosted git repository.
hui pushed a commit to branch rel/0.13
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/rel/0.13 by this push:
new b51b4391de [To rel/0.13][IOTDB-4781] Implement NOT LIKE/REGEXP value filter (#7764)
b51b4391de is described below
commit b51b4391dea967c0a64544d208a32f5ea2faf244
Author: liuminghui233 <36...@users.noreply.github.com>
AuthorDate: Fri Oct 28 10:43:56 2022 +0800
[To rel/0.13][IOTDB-4781] Implement NOT LIKE/REGEXP value filter (#7764)
---
.../iotdb/db/integration/IoTDBFuzzyQueryIT.java | 354 +++++++++++++--------
.../iotdb/db/qp/logical/crud/LikeOperator.java | 40 ++-
.../iotdb/db/qp/logical/crud/RegexpOperator.java | 40 ++-
.../apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java | 4 +-
.../qp/strategy/optimizer/ConcatPathOptimizer.java | 6 +-
.../iotdb/db/qp/physical/PhysicalPlanTest.java | 3 +-
.../iotdb/tsfile/read/filter/ValueFilter.java | 38 ++-
.../iotdb/tsfile/read/filter/operator/Like.java | 22 +-
.../iotdb/tsfile/read/filter/operator/Regexp.java | 20 +-
.../tsfile/read/filter/FilterSerializeTest.java | 2 +-
10 files changed, 338 insertions(+), 191 deletions(-)
diff --git a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBFuzzyQueryIT.java b/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBFuzzyQueryIT.java
index 9e99f60e9e..a1ecc0df5f 100644
--- a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBFuzzyQueryIT.java
+++ b/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBFuzzyQueryIT.java
@@ -37,176 +37,207 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import static org.junit.Assert.fail;
@Category({LocalStandaloneTest.class})
public class IoTDBFuzzyQueryIT {
- private static List<String> sqls = new ArrayList<>();
+
+ private static final List<String> sqls =
+ Arrays.asList(
+ "SET STORAGE GROUP TO root.t1",
+ "CREATE TIMESERIES root.t1.wf01.wt01.status WITH DATATYPE=TEXT, ENCODING=PLAIN",
+ "CREATE TIMESERIES root.t1.wf01.wt01.temperature WITH DATATYPE=FLOAT, ENCODING=RLE",
+ "CREATE TIMESERIES root.t1.wf01.wt02.status WITH DATATYPE=TEXT, ENCODING=PLAIN",
+ "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509465600000,'1',12.1)",
+ "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509465660000,'14',13.1)",
+ "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509465720000,'616',5.5)",
+ "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509465780000,'626',8.1)",
+ "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509465840000,'6116',4.3)",
+ "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509465900000,'6%16',10.3)",
+ "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509465960000,'8[sS]*',11.3)",
+ "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509466020000,'%123',18.3)",
+ "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509466080000,'123%',18.3)",
+ "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509466090000,'\\\\',10.3)",
+ "insert into root.t1.wf01.wt02 (time,status) values (1509465600000,'14')");
+
private static Connection connection;
@BeforeClass
public static void setUp() throws Exception {
- initCreateSQLStatement();
EnvironmentUtils.envSetUp();
+
+ Class.forName(Config.JDBC_DRIVER_NAME);
+ connection =
+ DriverManager.getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root");
+
insertData();
}
@AfterClass
public static void tearDown() throws Exception {
- close();
+ connection.close();
EnvironmentUtils.cleanEnv();
}
- private static void close() {
- if (Objects.nonNull(connection)) {
- try {
- connection.close();
- } catch (Exception e) {
- e.printStackTrace();
+ private static void insertData() {
+ try (Statement statement = connection.createStatement(); ) {
+ for (String sql : sqls) {
+ statement.execute(sql);
}
+ } catch (SQLException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
}
}
- private static void initCreateSQLStatement() {
- sqls.add("SET STORAGE GROUP TO root.t1");
- sqls.add("CREATE TIMESERIES root.t1.wf01.wt01.status WITH DATATYPE=TEXT, ENCODING=PLAIN");
- sqls.add("CREATE TIMESERIES root.t1.wf01.wt01.temperature WITH DATATYPE=FLOAT, ENCODING=RLE");
- sqls.add("CREATE TIMESERIES root.t1.wf01.wt02.status WITH DATATYPE=TEXT, ENCODING=PLAIN");
-
- sqls.add(
- "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509465600000,'1',12.1)");
- sqls.add(
- "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509465660000,'14',13.1)");
- sqls.add(
- "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509465720000,'616',5.5)");
- sqls.add(
- "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509465780000,'626',8.1)");
- sqls.add(
- "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509465840000,'6116',4.3)");
- sqls.add(
- "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509465900000,'6%16',10.3)");
- sqls.add(
- "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509465960000,'8[sS]*',11.3)");
- sqls.add(
- "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509466020000,'%123',18.3)");
- sqls.add(
- "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509466080000,'123%',18.3)");
- sqls.add(
- "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509466090000,'\\\\',10.3)");
- sqls.add("insert into root.t1.wf01.wt02 (time,status) values (1509465600000,'14')");
- }
+ @Test
+ public void testLike() {
+ try (Statement statement = connection.createStatement(); ) {
+ boolean hasResultSet =
+ statement.execute("select status from root.t1.wf01.wt01 where status like '1'");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals("1", outputResultStr(statement.getResultSet()));
- private static void insertData() throws ClassNotFoundException, SQLException {
- Class.forName(Config.JDBC_DRIVER_NAME);
- connection =
- DriverManager.getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root");
- Statement statement = connection.createStatement();
+ hasResultSet =
+ statement.execute("select status from root.t1.wf01.wt01 where status like '%'");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals(
+ "1,14,616,626,6116,6%16,8[sS]*,%123,123%,\\", outputResultStr(statement.getResultSet()));
+
+ hasResultSet =
+ statement.execute("select status from root.t1.wf01.wt01 where status like '1%'");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals("1,14,123%", outputResultStr(statement.getResultSet()));
+
+ hasResultSet =
+ statement.execute("select status from root.t1.wf01.wt01 where status like '%1%'");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals(
+ "1,14,616,6116,6%16,%123,123%", outputResultStr(statement.getResultSet()));
+
+ hasResultSet =
+ statement.execute("select status from root.t1.wf01.wt01 where status like '6%6'");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals("616,626,6116,6%16", outputResultStr(statement.getResultSet()));
+
+ hasResultSet =
+ statement.execute("select status from root.t1.wf01.wt01 where status like '1_'");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals("14", outputResultStr(statement.getResultSet()));
+
+ hasResultSet =
+ statement.execute("select status from root.t1.wf01.wt01 where status like '6_1%'");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals("6116,6%16", outputResultStr(statement.getResultSet()));
+
+ hasResultSet =
+ statement.execute("select status from root.t1.wf01.wt01 where status like '6\\%%'");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals("6%16", outputResultStr(statement.getResultSet()));
+
+ hasResultSet =
+ statement.execute("select status from root.t1.wf01.wt01 where status like '\\%%'");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals("%123", outputResultStr(statement.getResultSet()));
- for (String sql : sqls) {
- statement.execute(sql);
+ hasResultSet =
+ statement.execute("select status from root.t1.wf01.wt01 where status like '%\\%'");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals("123%", outputResultStr(statement.getResultSet()));
+
+ hasResultSet =
+ statement.execute("select status from root.t1.wf01.wt01 where status like '%\\\\\\\\%'");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals("\\", outputResultStr(statement.getResultSet()));
+ } catch (SQLException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
}
- statement.close();
}
@Test
- public void testLike() throws SQLException {
- Statement st0 = connection.createStatement();
- boolean hasResultSet =
- st0.execute("select status from root.t1.wf01.wt01 where status like '1'");
- Assert.assertTrue(hasResultSet);
- Assert.assertEquals("1", outputResultStr(st0.getResultSet()));
- hasResultSet = st0.execute("select status from root.t1.wf01.wt01 where status like '%'");
- Assert.assertTrue(hasResultSet);
- Assert.assertEquals(
- "1,14,616,626,6116,6%16,8[sS]*,%123,123%,\\", outputResultStr(st0.getResultSet()));
-
- hasResultSet = st0.execute("select status from root.t1.wf01.wt01 where status like '1%'");
- Assert.assertTrue(hasResultSet);
- Assert.assertEquals("1,14,123%", outputResultStr(st0.getResultSet()));
-
- hasResultSet = st0.execute("select status from root.t1.wf01.wt01 where status like '%1%'");
- Assert.assertTrue(hasResultSet);
- Assert.assertEquals("1,14,616,6116,6%16,%123,123%", outputResultStr(st0.getResultSet()));
-
- hasResultSet = st0.execute("select status from root.t1.wf01.wt01 where status like '6%6'");
- Assert.assertTrue(hasResultSet);
- Assert.assertEquals("616,626,6116,6%16", outputResultStr(st0.getResultSet()));
-
- hasResultSet = st0.execute("select status from root.t1.wf01.wt01 where status like '1_'");
- Assert.assertTrue(hasResultSet);
- Assert.assertEquals("14", outputResultStr(st0.getResultSet()));
-
- hasResultSet = st0.execute("select status from root.t1.wf01.wt01 where status like '6_1%'");
- Assert.assertTrue(hasResultSet);
- Assert.assertEquals("6116,6%16", outputResultStr(st0.getResultSet()));
-
- hasResultSet = st0.execute("select status from root.t1.wf01.wt01 where status like '6\\%%'");
- Assert.assertTrue(hasResultSet);
- Assert.assertEquals("6%16", outputResultStr(st0.getResultSet()));
-
- hasResultSet = st0.execute("select status from root.t1.wf01.wt01 where status like '\\%%'");
- Assert.assertTrue(hasResultSet);
- Assert.assertEquals("%123", outputResultStr(st0.getResultSet()));
-
- hasResultSet = st0.execute("select status from root.t1.wf01.wt01 where status like '%\\%'");
- Assert.assertTrue(hasResultSet);
- Assert.assertEquals("123%", outputResultStr(st0.getResultSet()));
-
- hasResultSet =
- st0.execute("select status from root.t1.wf01.wt01 where status like '%\\\\\\\\%'");
- Assert.assertTrue(hasResultSet);
- Assert.assertEquals("\\", outputResultStr(st0.getResultSet()));
- }
+ public void testNotLike() {
+ try (Statement statement = connection.createStatement(); ) {
+ boolean hasResultSet =
+ statement.execute("select status from root.t1.wf01.wt01 where not (status like '1')");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals(
+ "14,616,626,6116,6%16,8[sS]*,%123,123%,\\", outputResultStr(statement.getResultSet()));
- @Test(expected = Exception.class)
- public void testLikeNonTextCloumn() throws SQLException {
- Statement st1 = connection.createStatement();
- st1.execute("select * from root.t1.wf01.wt01 where temperature like '1'");
- }
+ hasResultSet =
+ statement.execute("select status from root.t1.wf01.wt01 where not (status like '%')");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals("", outputResultStr(statement.getResultSet()));
- private String outputResultStr(ResultSet resultSet) throws SQLException {
- StringBuilder resultBuilder = new StringBuilder();
- while (resultSet.next()) {
- resultBuilder.append(resultSet.getString(2)).append(",");
- }
- String result = resultBuilder.toString();
- return result.substring(0, result.length() - 1);
- }
+ hasResultSet =
+ statement.execute("select status from root.t1.wf01.wt01 where not (status like '1%')");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals(
+ "616,626,6116,6%16,8[sS]*,%123,\\", outputResultStr(statement.getResultSet()));
- private List<Integer> checkHeader(
- ResultSetMetaData resultSetMetaData, String expectedHeaderStrings, int[] expectedTypes)
- throws SQLException {
- String[] expectedHeaders = expectedHeaderStrings.split(",");
- Map<String, Integer> expectedHeaderToTypeIndexMap = new HashMap<>();
- for (int i = 0; i < expectedHeaders.length; ++i) {
- expectedHeaderToTypeIndexMap.put(expectedHeaders[i], i);
- }
+ hasResultSet =
+ statement.execute("select status from root.t1.wf01.wt01 where not (status like '%1%')");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals("626,8[sS]*,\\", outputResultStr(statement.getResultSet()));
- List<Integer> actualIndexToExpectedIndexList = new ArrayList<>();
- for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
- Integer typeIndex = expectedHeaderToTypeIndexMap.get(resultSetMetaData.getColumnName(i));
- Assert.assertNotNull(typeIndex);
- Assert.assertEquals(expectedTypes[typeIndex], resultSetMetaData.getColumnType(i));
- actualIndexToExpectedIndexList.add(typeIndex);
+ hasResultSet =
+ statement.execute("select status from root.t1.wf01.wt01 where not (status like '6%6')");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals("1,14,8[sS]*,%123,123%,\\", outputResultStr(statement.getResultSet()));
+
+ hasResultSet =
+ statement.execute("select status from root.t1.wf01.wt01 where not (status like '1_')");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals(
+ "1,616,626,6116,6%16,8[sS]*,%123,123%,\\", outputResultStr(statement.getResultSet()));
+
+ hasResultSet =
+ statement.execute("select status from root.t1.wf01.wt01 where not (status like '6_1%')");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals(
+ "1,14,616,626,8[sS]*,%123,123%,\\", outputResultStr(statement.getResultSet()));
+
+ hasResultSet =
+ statement.execute("select status from root.t1.wf01.wt01 where not (status like '6\\%%')");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals(
+ "1,14,616,626,6116,8[sS]*,%123,123%,\\", outputResultStr(statement.getResultSet()));
+
+ hasResultSet =
+ statement.execute("select status from root.t1.wf01.wt01 where not (status like '\\%%')");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals(
+ "1,14,616,626,6116,6%16,8[sS]*,123%,\\", outputResultStr(statement.getResultSet()));
+
+ hasResultSet =
+ statement.execute("select status from root.t1.wf01.wt01 where not (status like '%\\%')");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals(
+ "1,14,616,626,6116,6%16,8[sS]*,%123,\\", outputResultStr(statement.getResultSet()));
+
+ hasResultSet =
+ statement.execute(
+ "select status from root.t1.wf01.wt01 where not (status like '%\\\\\\\\%')");
+ Assert.assertTrue(hasResultSet);
+ Assert.assertEquals(
+ "1,14,616,626,6116,6%16,8[sS]*,%123,123%", outputResultStr(statement.getResultSet()));
+ } catch (SQLException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
}
- return actualIndexToExpectedIndexList;
}
@Test
- public void selectLikeAlignByDevice() throws ClassNotFoundException {
+ public void selectLikeAlignByDevice() {
String[] retArray =
new String[] {"1509465660000,root.t1.wf01.wt01,14,", "1509465600000,root.t1.wf01.wt02,14"};
- Class.forName(Config.JDBC_DRIVER_NAME);
- try (Connection connection =
- DriverManager.getConnection(
- Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root");
- Statement statement = connection.createStatement()) {
+ try (Statement statement = connection.createStatement()) {
boolean hasResultSet =
statement.execute(
"select status from root.t1.wf01.wt0* where status like '14%' align by device");
@@ -236,14 +267,14 @@ public class IoTDBFuzzyQueryIT {
}
Assert.assertEquals(2, cnt);
}
- } catch (Exception e) {
+ } catch (SQLException e) {
e.printStackTrace();
fail(e.getMessage());
}
}
@Test
- public void selectRegexpAlignByDevice() throws ClassNotFoundException {
+ public void selectRegexpAlignByDevice() {
String[] retArray =
new String[] {
"1509465600000,root.t1.wf01.wt01,1,",
@@ -252,11 +283,7 @@ public class IoTDBFuzzyQueryIT {
"1509465600000,root.t1.wf01.wt02,14,"
};
- Class.forName(Config.JDBC_DRIVER_NAME);
- try (Connection connection =
- DriverManager.getConnection(
- Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root");
- Statement statement = connection.createStatement()) {
+ try (Statement statement = connection.createStatement()) {
boolean hasResultSet =
statement.execute(
"select status from root.t1.wf01.wt0* where status regexp '^1.*' align by device");
@@ -286,9 +313,64 @@ public class IoTDBFuzzyQueryIT {
}
Assert.assertEquals(4, cnt);
}
- } catch (Exception e) {
+ } catch (SQLException e) {
e.printStackTrace();
fail(e.getMessage());
}
}
+
+ @Test
+ public void testLikeNonTextColumn() {
+ try (Statement statement = connection.createStatement()) {
+ statement.execute("select * from root.t1.wf01.wt01 where temperature like '1'");
+ fail("no exception!");
+ } catch (SQLException e) {
+ Assert.assertTrue(
+ e.getMessage(),
+ e.getMessage().contains("Unsupported type: [FLOAT]. Only TEXT is supported in 'Like'"));
+ }
+ }
+
+ @Test
+ public void testRegexpNonTextColumn() {
+ try (Statement statement = connection.createStatement()) {
+ statement.execute("select * from root.t1.wf01.wt01 where temperature regexp '1'");
+ fail("no exception!");
+ } catch (SQLException e) {
+ Assert.assertTrue(
+ e.getMessage(),
+ e.getMessage().contains("Unsupported type: [FLOAT]. Only TEXT is supported in 'Regexp'"));
+ }
+ }
+
+ private String outputResultStr(ResultSet resultSet) throws SQLException {
+ StringBuilder resultBuilder = new StringBuilder();
+ while (resultSet.next()) {
+ resultBuilder.append(resultSet.getString(2)).append(",");
+ }
+ String result = resultBuilder.toString();
+ if (result.isEmpty()) {
+ return result;
+ }
+ return result.substring(0, result.length() - 1);
+ }
+
+ private List<Integer> checkHeader(
+ ResultSetMetaData resultSetMetaData, String expectedHeaderStrings, int[] expectedTypes)
+ throws SQLException {
+ String[] expectedHeaders = expectedHeaderStrings.split(",");
+ Map<String, Integer> expectedHeaderToTypeIndexMap = new HashMap<>();
+ for (int i = 0; i < expectedHeaders.length; ++i) {
+ expectedHeaderToTypeIndexMap.put(expectedHeaders[i], i);
+ }
+
+ List<Integer> actualIndexToExpectedIndexList = new ArrayList<>();
+ for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+ Integer typeIndex = expectedHeaderToTypeIndexMap.get(resultSetMetaData.getColumnName(i));
+ Assert.assertNotNull(typeIndex);
+ Assert.assertEquals(expectedTypes[typeIndex], resultSetMetaData.getColumnType(i));
+ actualIndexToExpectedIndexList.add(typeIndex);
+ }
+ return actualIndexToExpectedIndexList;
+ }
}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/LikeOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/LikeOperator.java
index 9183205230..1dd1e47151 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/LikeOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/LikeOperator.java
@@ -38,12 +38,14 @@ import static org.apache.iotdb.tsfile.file.metadata.enums.TSDataType.TEXT;
/** fuzzy query structure LikeOperator. */
public class LikeOperator extends FunctionOperator {
+ private boolean not;
protected String value;
- public LikeOperator(FilterType filterType, PartialPath path, String value) {
+ public LikeOperator(FilterType filterType, PartialPath path, String value, boolean not) {
super(filterType);
this.singlePath = path;
this.value = value;
+ this.not = not;
isLeaf = true;
isSingle = true;
}
@@ -68,19 +70,20 @@ public class LikeOperator extends FunctionOperator {
singlePath,
(value.startsWith("'") && value.endsWith("'"))
? value.substring(1, value.length() - 1)
- : value);
+ : value,
+ not);
}
return new Pair<>(ret, singlePath.getFullPath());
}
private static class Like {
public static <T extends Comparable<T>> IUnaryExpression getUnaryExpression(
- PartialPath path, String value) {
- return new SingleSeriesExpression(path, ValueFilter.like(value));
+ PartialPath path, String value, boolean not) {
+ return new SingleSeriesExpression(path, ValueFilter.like(value, not));
}
- public <T extends Comparable<T>> Filter getValueFilter(String value) {
- return ValueFilter.like(value);
+ public <T extends Comparable<T>> Filter getValueFilter(String value, boolean not) {
+ return ValueFilter.like(value, not);
}
}
@@ -90,13 +93,13 @@ public class LikeOperator extends FunctionOperator {
for (int i = 0; i < spaceNum; i++) {
sc.addTail(" ");
}
- sc.addTail(singlePath.getFullPath(), getFilterSymbol(), value, ", single\n");
+ sc.addTail(singlePath.getFullPath(), getFilterSymbol(), not, value, ", single\n");
return sc.toString();
}
@Override
public LikeOperator copy() {
- LikeOperator ret = new LikeOperator(this.filterType, singlePath.clone(), value);
+ LikeOperator ret = new LikeOperator(this.filterType, singlePath.clone(), value, not);
ret.isLeaf = isLeaf;
ret.isSingle = isSingle;
ret.pathSet = pathSet;
@@ -115,20 +118,35 @@ public class LikeOperator extends FunctionOperator {
return false;
}
LikeOperator that = (LikeOperator) o;
- return Objects.equals(value, that.value);
+ return Objects.equals(value, that.value) && not == that.not;
}
@Override
public int hashCode() {
- return Objects.hash(super.hashCode(), singlePath, value);
+ return Objects.hash(super.hashCode(), singlePath, value, not);
}
@Override
public String toString() {
- return "[" + singlePath.getFullPath() + getFilterSymbol() + value + "]";
+ return "["
+ + singlePath.getFullPath()
+ + (not ? " NOT " : " ")
+ + getFilterSymbol()
+ + " "
+ + value
+ + "]";
+ }
+
+ @Override
+ public void reverseFunc() {
+ not = !not;
}
public String getValue() {
return value;
}
+
+ public boolean isNot() {
+ return not;
+ }
}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/RegexpOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/RegexpOperator.java
index 4551f09f2a..a411de9a8e 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/RegexpOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/RegexpOperator.java
@@ -37,12 +37,14 @@ import static org.apache.iotdb.tsfile.file.metadata.enums.TSDataType.TEXT;
public class RegexpOperator extends FunctionOperator {
+ private boolean not;
protected String value;
- public RegexpOperator(FilterType filterType, PartialPath path, String value) {
+ public RegexpOperator(FilterType filterType, PartialPath path, String value, boolean not) {
super(filterType);
this.singlePath = path;
this.value = value;
+ this.not = not;
isLeaf = true;
isSingle = true;
}
@@ -67,19 +69,20 @@ public class RegexpOperator extends FunctionOperator {
singlePath,
(value.startsWith("'") && value.endsWith("'"))
? value.substring(1, value.length() - 1)
- : value);
+ : value,
+ not);
}
return new Pair<>(ret, singlePath.getFullPath());
}
private static class Regexp {
public static <T extends Comparable<T>> IUnaryExpression getUnaryExpression(
- PartialPath path, String value) {
- return new SingleSeriesExpression(path, ValueFilter.regexp(value));
+ PartialPath path, String value, boolean not) {
+ return new SingleSeriesExpression(path, ValueFilter.regexp(value, not));
}
- public <T extends Comparable<T>> Filter getValueFilter(String value) {
- return ValueFilter.regexp(value);
+ public <T extends Comparable<T>> Filter getValueFilter(String value, boolean not) {
+ return ValueFilter.regexp(value, not);
}
}
@@ -89,13 +92,13 @@ public class RegexpOperator extends FunctionOperator {
for (int i = 0; i < spaceNum; i++) {
sc.addTail(" ");
}
- sc.addTail(singlePath.getFullPath(), value, ", single\n");
+ sc.addTail(singlePath.getFullPath(), not, value, ", single\n");
return sc.toString();
}
@Override
public RegexpOperator copy() {
- RegexpOperator ret = new RegexpOperator(this.filterType, singlePath.clone(), value);
+ RegexpOperator ret = new RegexpOperator(this.filterType, singlePath.clone(), value, not);
ret.isLeaf = isLeaf;
ret.isSingle = isSingle;
ret.pathSet = pathSet;
@@ -114,20 +117,35 @@ public class RegexpOperator extends FunctionOperator {
return false;
}
RegexpOperator that = (RegexpOperator) o;
- return Objects.equals(value, that.value);
+ return Objects.equals(value, that.value) && not == that.not;
}
@Override
public int hashCode() {
- return Objects.hash(super.hashCode(), singlePath, value);
+ return Objects.hash(super.hashCode(), singlePath, value, not);
}
@Override
public String toString() {
- return "[" + singlePath.getFullPath() + value + "]";
+ return "["
+ + singlePath.getFullPath()
+ + (not ? " NOT " : " ")
+ + getFilterSymbol()
+ + " "
+ + value
+ + "]";
+ }
+
+ @Override
+ public void reverseFunc() {
+ not = !not;
}
public String getValue() {
return value;
}
+
+ public boolean isNot() {
+ return not;
+ }
}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
index 9b909b4aee..67ffe2efe3 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
@@ -2620,8 +2620,8 @@ public class IoTDBSqlVisitor extends IoTDBSqlParserBaseVisitor<Operator> {
throw new SQLParserException("Path is null, please check the sql.");
}
return ctx.REGEXP() != null
- ? new RegexpOperator(FilterType.REGEXP, path, ctx.STRING_LITERAL().getText())
- : new LikeOperator(FilterType.LIKE, path, ctx.STRING_LITERAL().getText());
+ ? new RegexpOperator(FilterType.REGEXP, path, ctx.STRING_LITERAL().getText(), false)
+ : new LikeOperator(FilterType.LIKE, path, ctx.STRING_LITERAL().getText(), false);
} else {
if (ctx.TIME() != null || ctx.TIMESTAMP() != null) {
path = new PartialPath(SQLConstant.getSingleTimeArray());
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java
index 756c27ac6b..4a23f77f6c 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java
@@ -343,13 +343,15 @@ public class ConcatPathOptimizer implements ILogicalOptimizer {
new LikeOperator(
operator.getFilterType(),
noStarPaths.get(i),
- ((LikeOperator) operator).getValue()));
+ ((LikeOperator) operator).getValue(),
+ ((LikeOperator) operator).isNot()));
} else if (operator instanceof RegexpOperator) {
currentNode.addChildOperator(
new RegexpOperator(
operator.getFilterType(),
noStarPaths.get(i),
- ((RegexpOperator) operator).getValue()));
+ ((RegexpOperator) operator).getValue(),
+ ((RegexpOperator) operator).isNot()));
} else {
currentNode.addChildOperator(
new BasicFunctionOperator(
diff --git a/server/src/test/java/org/apache/iotdb/db/qp/physical/PhysicalPlanTest.java b/server/src/test/java/org/apache/iotdb/db/qp/physical/PhysicalPlanTest.java
index 76fe66a39c..a91e78b5d3 100644
--- a/server/src/test/java/org/apache/iotdb/db/qp/physical/PhysicalPlanTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/qp/physical/PhysicalPlanTest.java
@@ -1443,7 +1443,8 @@ public class PhysicalPlanTest {
PhysicalPlan plan = processor.parseSQLToPhysicalPlan(sqlStr);
IExpression queryFilter = ((RawDataQueryPlan) plan).getExpression();
IExpression expect =
- new SingleSeriesExpression(new Path("root.vehicle.d5", "s1"), ValueFilter.like("string*"));
+ new SingleSeriesExpression(
+ new Path("root.vehicle.d5", "s1"), ValueFilter.regexp("string*", false));
assertEquals(expect.toString(), queryFilter.toString());
}
diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/ValueFilter.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/ValueFilter.java
index 3dcfbe94f8..c6bc55f34e 100644
--- a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/ValueFilter.java
+++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/ValueFilter.java
@@ -70,12 +70,12 @@ public class ValueFilter {
return new ValueNotEq(value);
}
- public static <T extends Comparable<T>> ValueRegexp<T> regexp(String value) {
- return new ValueRegexp(value);
+ public static <T extends Comparable<T>> ValueRegexp<T> regexp(String value, boolean not) {
+ return new ValueRegexp(value, not);
}
- public static <T extends Comparable<T>> ValueLike<T> like(String value) {
- return new ValueLike(value);
+ public static <T extends Comparable<T>> ValueLike<T> like(String value, boolean not) {
+ return new ValueLike(value, not);
}
public static class ValueIn<T extends Comparable<T>> extends In<T> {
@@ -246,8 +246,8 @@ public class ValueFilter {
public static class ValueRegexp<T extends Comparable<T>> extends Regexp<T> {
- private ValueRegexp(String value) {
- super(value, FilterType.VALUE_FILTER);
+ private ValueRegexp(String value, boolean not) {
+ super(value, FilterType.VALUE_FILTER, not);
}
}
@@ -255,21 +255,24 @@ public class ValueFilter {
private final int index;
- private VectorValueRegexp(String value, int index) {
- super(value);
+ private VectorValueRegexp(String value, int index, boolean not) {
+ super(value, not);
this.index = index;
}
public boolean satisfy(long time, TsPrimitiveType[] values) {
- Object v = filterType == FilterType.TIME_FILTER ? time : values[index].getValue();
- return this.value.equals(v);
+ if (filterType != FilterType.VALUE_FILTER) {
+ return false;
+ }
+ Object value = values[index].getValue();
+ return pattern.matcher(new MatcherInput(value.toString(), new AccessCount())).find() != not;
}
}
public static class ValueLike<T extends Comparable<T>> extends Like<T> {
- private ValueLike(String value) {
- super(value, FilterType.VALUE_FILTER);
+ private ValueLike(String value, boolean not) {
+ super(value, FilterType.VALUE_FILTER, not);
}
}
@@ -277,14 +280,17 @@ public class ValueFilter {
private final int index;
- private VectorValueLike(String value, int index) {
- super(value);
+ private VectorValueLike(String value, int index, boolean not) {
+ super(value, not);
this.index = index;
}
public boolean satisfy(long time, TsPrimitiveType[] values) {
- Object v = filterType == FilterType.TIME_FILTER ? time : values[index].getValue();
- return this.value.equals(v);
+ if (filterType != FilterType.VALUE_FILTER) {
+ return false;
+ }
+ Object value = values[index].getValue();
+ return pattern.matcher(value.toString()).find() != not;
}
}
}
diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/Like.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/Like.java
index fac3dfcf5b..7b7023d39a 100644
--- a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/Like.java
+++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/Like.java
@@ -27,6 +27,7 @@ import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.util.Objects;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
@@ -45,15 +46,18 @@ public class Like<T extends Comparable<T>> implements Filter {
protected Pattern pattern;
+ protected boolean not;
+
private Like() {}
/**
* The main idea of this part comes from
* https://codereview.stackexchange.com/questions/36861/convert-sql-like-to-regex/36864
*/
- public Like(String value, FilterType filterType) {
+ public Like(String value, FilterType filterType, boolean not) {
this.value = value;
this.filterType = filterType;
+ this.not = not;
try {
String unescapeValue = unescapeString(value);
String specialRegexStr = ".^$*+?{}[]|()";
@@ -94,7 +98,7 @@ public class Like<T extends Comparable<T>> implements Filter {
if (filterType != FilterType.VALUE_FILTER) {
return false;
}
- return pattern.matcher(value.toString()).find();
+ return pattern.matcher(value.toString()).find() != not;
}
@Override
@@ -109,7 +113,7 @@ public class Like<T extends Comparable<T>> implements Filter {
@Override
public Filter copy() {
- return new Like(value, filterType);
+ return new Like(value, filterType, not);
}
@Override
@@ -118,6 +122,7 @@ public class Like<T extends Comparable<T>> implements Filter {
outputStream.write(getSerializeId().ordinal());
outputStream.write(filterType.ordinal());
ReadWriteIOUtils.writeObject(value, outputStream);
+ ReadWriteIOUtils.write(not, outputStream);
} catch (IOException ex) {
throw new IllegalArgumentException("Failed to serialize outputStream of type:", ex);
}
@@ -127,11 +132,20 @@ public class Like<T extends Comparable<T>> implements Filter {
public void deserialize(ByteBuffer buffer) {
filterType = FilterType.values()[buffer.get()];
value = ReadWriteIOUtils.readString(buffer);
+ not = ReadWriteIOUtils.readBool(buffer);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof Like
+ && Objects.equals(((Like<?>) o).value, value)
+ && ((Like<?>) o).filterType == filterType
+ && ((Like<?>) o).not == not;
}
@Override
public String toString() {
- return filterType + " is " + value;
+ return filterType + (not ? " not like " : " like ") + value;
}
@Override
diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/Regexp.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/Regexp.java
index 31e7260469..2ffed8a253 100644
--- a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/Regexp.java
+++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/Regexp.java
@@ -45,11 +45,14 @@ public class Regexp<T extends Comparable<T>> implements Filter {
protected Pattern pattern;
+ protected boolean not;
+
public Regexp() {}
- public Regexp(String value, FilterType filterType) {
+ public Regexp(String value, FilterType filterType, boolean not) {
this.value = value;
this.filterType = filterType;
+ this.not = not;
try {
this.pattern = Pattern.compile(this.value);
} catch (PatternSyntaxException e) {
@@ -67,7 +70,7 @@ public class Regexp<T extends Comparable<T>> implements Filter {
if (filterType != FilterType.VALUE_FILTER) {
return false;
}
- return pattern.matcher(new MatcherInput(value.toString(), new AccessCount())).find();
+ return pattern.matcher(new MatcherInput(value.toString(), new AccessCount())).find() != not;
}
@Override
@@ -82,7 +85,7 @@ public class Regexp<T extends Comparable<T>> implements Filter {
@Override
public Filter copy() {
- return new Regexp(value, filterType);
+ return new Regexp(value, filterType, not);
}
@Override
@@ -91,6 +94,7 @@ public class Regexp<T extends Comparable<T>> implements Filter {
outputStream.write(getSerializeId().ordinal());
outputStream.write(filterType.ordinal());
ReadWriteIOUtils.write(value, outputStream);
+ ReadWriteIOUtils.write(not, outputStream);
} catch (IOException ex) {
throw new IllegalArgumentException("Failed to serialize outputStream of type:", ex);
}
@@ -107,18 +111,20 @@ public class Regexp<T extends Comparable<T>> implements Filter {
throw new PatternSyntaxException("Regular expression error", value, e.getIndex());
}
}
+ not = ReadWriteIOUtils.readBool(buffer);
}
@Override
public String toString() {
- return filterType + " is " + value;
+ return filterType + (not ? " not regexp " : " regexp ") + value;
}
@Override
public boolean equals(Object o) {
return o instanceof Regexp
&& Objects.equals(((Regexp<?>) o).value, value)
- && ((Regexp<?>) o).filterType == filterType;
+ && ((Regexp<?>) o).filterType == filterType
+ && ((Regexp<?>) o).not == not;
}
@Override
@@ -126,7 +132,7 @@ public class Regexp<T extends Comparable<T>> implements Filter {
return FilterSerializeId.REGEXP;
}
- private static class AccessCount {
+ public static class AccessCount {
private int count;
private final int accessThreshold =
TSFileDescriptor.getInstance().getConfig().getPatternMatchingThreshold();
@@ -138,7 +144,7 @@ public class Regexp<T extends Comparable<T>> implements Filter {
}
}
- private static class MatcherInput implements CharSequence {
+ public static class MatcherInput implements CharSequence {
private final CharSequence value;
diff --git a/tsfile/src/test/java/org/apache/iotdb/tsfile/read/filter/FilterSerializeTest.java b/tsfile/src/test/java/org/apache/iotdb/tsfile/read/filter/FilterSerializeTest.java
index 779e32d404..fc8e63a16f 100644
--- a/tsfile/src/test/java/org/apache/iotdb/tsfile/read/filter/FilterSerializeTest.java
+++ b/tsfile/src/test/java/org/apache/iotdb/tsfile/read/filter/FilterSerializeTest.java
@@ -48,7 +48,7 @@ public class FilterSerializeTest {
ValueFilter.notEq(false),
ValueFilter.in(new HashSet<>(Arrays.asList("a", "b")), false),
ValueFilter.in(new HashSet<>(Arrays.asList("c", "d")), true),
- ValueFilter.regexp("s.*"),
+ ValueFilter.regexp("s.*", false),
};
for (Filter filter : filters) {
validateSerialization(filter);