You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ja...@apache.org on 2024/10/13 12:09:33 UTC
(iotdb) branch master updated: Add escape grammer and support like's SQL multi column transformer
This is an automated email from the ASF dual-hosted git repository.
jackietien 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 5994c9e4e96 Add escape grammer and support like's SQL multi column transformer
5994c9e4e96 is described below
commit 5994c9e4e968a258d01b29a222814ea1be6689aa
Author: Lin Xintao <lx...@163.com>
AuthorDate: Sun Oct 13 20:09:27 2024 +0800
Add escape grammer and support like's SQL multi column transformer
---
.../org/apache/iotdb/db/it/IoTDBNestedQueryIT.java | 6 +-
.../iotdb/db/it/query/IoTDBFuzzyQueryIT.java | 24 ++-
.../iotdb/db/it/query/IoTDBNullOperandIT.java | 2 +-
.../it/query/old/query/IoTDBFuzzyQueryTableIT.java | 218 +++------------------
.../org/apache/iotdb/db/qp/sql/IdentifierParser.g4 | 1 +
.../org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 | 3 +-
.../antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4 | 4 +
.../relational/ColumnTransformerBuilder.java | 46 +++--
.../queryengine/plan/analyze/ExpressionUtils.java | 2 +-
.../plan/expression/unary/LikeExpression.java | 82 +++++---
.../visitor/ColumnTransformerVisitor.java | 6 +-
.../visitor/IntermediateLayerVisitor.java | 5 +-
.../visitor/TransformToViewExpressionVisitor.java | 5 +-
.../predicate/ConvertPredicateToFilterVisitor.java | 7 +-
.../visitor/predicate/ReversePredicateVisitor.java | 2 +-
.../db/queryengine/plan/parser/ASTVisitor.java | 13 +-
.../predicate/ConvertPredicateToFilterVisitor.java | 9 +-
.../ConvertSchemaPredicateToFilterVisitor.java | 5 +-
.../dag/column/binary/Like2ColumnTransformer.java | 92 +++++++++
.../dag/column/ternary/Like3ColumnTransformer.java | 105 ++++++++++
.../dag/transformer/unary/LikeTransformer.java | 1 -
.../view/visitor/TransformToExpressionVisitor.java | 5 +-
.../schema/filter/impl/values/LikeFilter.java | 5 +-
.../viewExpression/unary/LikeViewExpression.java | 65 +++---
.../db/relational/grammar/sql/RelationalSql.g4 | 5 +-
25 files changed, 417 insertions(+), 301 deletions(-)
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBNestedQueryIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBNestedQueryIT.java
index 205f8b00910..f60bacb0fd0 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBNestedQueryIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBNestedQueryIT.java
@@ -624,12 +624,8 @@ public class IoTDBNestedQueryIT {
try (Connection connection = EnvFactory.getEnv().getConnection();
Statement statement = connection.createStatement()) {
String query =
- "SELECT s1 FROM root.vehicle.d1 WHERE s3 LIKE '_' && s3 REGEXP '[0-9]' && s3 IN ('4', '2', '3')";
+ "SELECT s1 FROM root.vehicle.d1 WHERE s3 LIKE '_' && s3 not REGEXP '[0-9]' && s3 IN ('4', '2', '3')";
try (ResultSet rs = statement.executeQuery(query)) {
- for (int i = 2; i <= 4; i++) {
- Assert.assertTrue(rs.next());
- Assert.assertEquals(i, rs.getLong(1));
- }
Assert.assertFalse(rs.next());
}
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/query/IoTDBFuzzyQueryIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/query/IoTDBFuzzyQueryIT.java
index a9e6e37dd56..2694faaf526 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/query/IoTDBFuzzyQueryIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/query/IoTDBFuzzyQueryIT.java
@@ -86,7 +86,7 @@ public class IoTDBFuzzyQueryIT {
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)");
+ "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')");
}
@@ -106,13 +106,15 @@ public class IoTDBFuzzyQueryIT {
Connection connection = EnvFactory.getEnv().getConnection();
Statement st0 = connection.createStatement();
ResultSet resultSet =
- st0.executeQuery("select status from root.t1.wf01.wt01 where status like '1'");
+ st0.executeQuery("select status from root.t1.wf01.wt01 where status not like '1'");
- Assert.assertEquals("1", outputResultStr(resultSet));
+ Assert.assertEquals(
+ "14,616,626,6116,6%16,8[sS]*,%123,123%,\\\\\\\\", outputResultStr(resultSet));
resultSet = st0.executeQuery("select status from root.t1.wf01.wt01 where status like '%'");
- Assert.assertEquals("1,14,616,626,6116,6%16,8[sS]*,%123,123%,\\\\", outputResultStr(resultSet));
+ Assert.assertEquals(
+ "1,14,616,626,6116,6%16,8[sS]*,%123,123%,\\\\\\\\", outputResultStr(resultSet));
resultSet = st0.executeQuery("select status from root.t1.wf01.wt01 where status like '1%'");
@@ -134,22 +136,28 @@ public class IoTDBFuzzyQueryIT {
Assert.assertEquals("6116,6%16", outputResultStr(resultSet));
- resultSet = st0.executeQuery("select status from root.t1.wf01.wt01 where status like '6\\%%'");
+ resultSet =
+ st0.executeQuery(
+ "select status from root.t1.wf01.wt01 where status like '6\\%%' escape '\\'");
Assert.assertEquals("6%16", outputResultStr(resultSet));
- resultSet = st0.executeQuery("select status from root.t1.wf01.wt01 where status like '\\%%'");
+ resultSet =
+ st0.executeQuery(
+ "select status from root.t1.wf01.wt01 where status like '\\%%' escape '\\'");
Assert.assertEquals("%123", outputResultStr(resultSet));
- resultSet = st0.executeQuery("select status from root.t1.wf01.wt01 where status like '%\\%'");
+ resultSet =
+ st0.executeQuery(
+ "select status from root.t1.wf01.wt01 where status like '%\\%' escape '\\'");
Assert.assertEquals("123%", outputResultStr(resultSet));
resultSet =
st0.executeQuery("select status from root.t1.wf01.wt01 where status like '%\\\\\\\\%'");
- Assert.assertEquals("\\\\", outputResultStr(resultSet));
+ Assert.assertEquals("\\\\\\\\", outputResultStr(resultSet));
}
@Test(expected = Exception.class)
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/query/IoTDBNullOperandIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/query/IoTDBNullOperandIT.java
index b1aa94805f3..f292b162155 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/query/IoTDBNullOperandIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/query/IoTDBNullOperandIT.java
@@ -104,7 +104,7 @@ public class IoTDBNullOperandIT {
"root.test.sg1.s1 = root.test.sg1.s2",
"root.test.sg1.s1 > root.test.sg1.s2",
"root.test.sg1.s1 < root.test.sg1.s2",
- "root.test.sg1.s5 LIKE 'LikePattern{pattern='test', escape=\\}'",
+ "root.test.sg1.s5 LIKE pattern = 'test'",
"root.test.sg1.s2 IN (1,2)",
"root.test.sg1.s2 BETWEEN 1 AND 3",
};
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/query/IoTDBFuzzyQueryTableIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/query/IoTDBFuzzyQueryTableIT.java
index b6d807a2cf8..f3b5ef2ecb2 100644
--- a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/query/IoTDBFuzzyQueryTableIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/query/IoTDBFuzzyQueryTableIT.java
@@ -23,29 +23,22 @@ import org.apache.iotdb.it.env.EnvFactory;
import org.apache.iotdb.it.framework.IoTDBTestRunner;
import org.apache.iotdb.itbase.category.TableClusterIT;
import org.apache.iotdb.itbase.category.TableLocalStandaloneIT;
+import org.apache.iotdb.itbase.env.BaseEnv;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import java.sql.Connection;
import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
-import java.sql.Types;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import static org.junit.Assert.fail;
-
-@Ignore // TODO in V2
@RunWith(IoTDBTestRunner.class)
@Category({TableLocalStandaloneIT.class, TableClusterIT.class})
public class IoTDBFuzzyQueryTableIT {
@@ -64,37 +57,20 @@ public class IoTDBFuzzyQueryTableIT {
}
private static void initCreateSQLStatement() {
- sqls.add("CREATE DATABASE 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("CREATE DATABASE TestFuzzyQuery");
+ sqls.add("USE TestFuzzyQuery");
sqls.add(
- "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509465900000,'6%16',10.3)");
+ "CREATE TABLE likeTest(device_id STRING ID, s1 TEXT MEASUREMENT, s2 STRING MEASUREMENT, s3 STRING MEASUREMENT)");
sqls.add(
- "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509465960000,'8[sS]*',11.3)");
+ "INSERT INTO likeTest(time, device_id, s1, s2, s3) VALUES(1,'d1', 'abcdef', 'a%', '\\')");
sqls.add(
- "insert into root.t1.wf01.wt01 (time,status,temperature) values (1509466020000,'%123',18.3)");
+ "INSERT INTO likeTest(time, device_id, s1, s2, s3) VALUES(2,'d1', '_abcdef', '\\_a%','\\')");
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')");
+ "INSERT INTO likeTest(time, device_id, s1, s2, s3) VALUES(3,'d1', 'abcdef%', '%_\\%','\\')");
}
private static void insertData() throws SQLException {
-
- Connection connection = EnvFactory.getEnv().getConnection();
+ Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
Statement statement = connection.createStatement();
for (String sql : sqls) {
@@ -105,171 +81,27 @@ public class IoTDBFuzzyQueryTableIT {
@Test
public void testLike() throws SQLException {
- Connection connection = EnvFactory.getEnv().getConnection();
- Statement st0 = connection.createStatement();
- ResultSet resultSet =
- st0.executeQuery("select status from root.t1.wf01.wt01 where status like '1'");
-
- Assert.assertEquals("1", outputResultStr(resultSet));
-
- resultSet = st0.executeQuery("select status from root.t1.wf01.wt01 where status like '%'");
-
- Assert.assertEquals("1,14,616,626,6116,6%16,8[sS]*,%123,123%,\\\\", outputResultStr(resultSet));
-
- resultSet = st0.executeQuery("select status from root.t1.wf01.wt01 where status like '1%'");
-
- Assert.assertEquals("1,14,123%", outputResultStr(resultSet));
-
- resultSet = st0.executeQuery("select status from root.t1.wf01.wt01 where status like '%1%'");
-
- Assert.assertEquals("1,14,616,6116,6%16,%123,123%", outputResultStr(resultSet));
-
- resultSet = st0.executeQuery("select status from root.t1.wf01.wt01 where status like '6%6'");
-
- Assert.assertEquals("616,626,6116,6%16", outputResultStr(resultSet));
-
- resultSet = st0.executeQuery("select status from root.t1.wf01.wt01 where status like '1_'");
-
- Assert.assertEquals("14", outputResultStr(resultSet));
-
- resultSet = st0.executeQuery("select status from root.t1.wf01.wt01 where status like '6_1%'");
-
- Assert.assertEquals("6116,6%16", outputResultStr(resultSet));
-
- resultSet = st0.executeQuery("select status from root.t1.wf01.wt01 where status like '6\\%%'");
-
- Assert.assertEquals("6%16", outputResultStr(resultSet));
-
- resultSet = st0.executeQuery("select status from root.t1.wf01.wt01 where status like '\\%%'");
-
- Assert.assertEquals("%123", outputResultStr(resultSet));
-
- resultSet = st0.executeQuery("select status from root.t1.wf01.wt01 where status like '%\\%'");
-
- Assert.assertEquals("123%", outputResultStr(resultSet));
-
- resultSet =
- st0.executeQuery("select status from root.t1.wf01.wt01 where status like '%\\\\\\\\%'");
-
- Assert.assertEquals("\\\\", outputResultStr(resultSet));
- }
-
- @Test(expected = Exception.class)
- public void testLikeNonTextCloumn() throws SQLException {
- Connection connection = EnvFactory.getEnv().getConnection();
- Statement st1 = connection.createStatement();
- st1.executeQuery("select * from root.t1.wf01.wt01 where temperature like '1'");
- }
-
- 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);
- }
-
- 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;
- }
-
- @Test
- public void selectLikeAlignByDevice() throws ClassNotFoundException {
- String[] retArray =
- new String[] {"1509465660000,root.t1.wf01.wt01,14,", "1509465600000,root.t1.wf01.wt02,14"};
- try (Connection connection = EnvFactory.getEnv().getConnection();
- Statement statement = connection.createStatement()) {
-
- try (ResultSet resultSet =
- statement.executeQuery(
- "select status from root.t1.wf01.wt0* where status like '14%' align by device")) {
- ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
- List<Integer> actualIndexToExpectedIndexList =
- checkHeader(
- resultSetMetaData,
- "Time,Device,status,",
- new int[] {Types.TIMESTAMP, Types.VARCHAR, Types.VARCHAR});
-
- int cnt = 0;
- while (resultSet.next()) {
- String[] expectedStrings = retArray[cnt].split(",");
- StringBuilder expectedBuilder = new StringBuilder();
- StringBuilder actualBuilder = new StringBuilder();
- for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
- actualBuilder.append(resultSet.getString(i)).append(",");
- expectedBuilder
- .append(expectedStrings[actualIndexToExpectedIndexList.get(i - 1)])
- .append(",");
- }
- Assert.assertEquals(expectedBuilder.toString(), actualBuilder.toString());
- cnt++;
- }
- Assert.assertEquals(2, cnt);
+ Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+ Statement statement = connection.createStatement();
+ statement.execute("USE TestFuzzyQuery");
+ String[] ans = new String[] {"abcdef"};
+ String query = "SELECT s1 FROM likeTest where s1 LIKE s2";
+ try (ResultSet rs = statement.executeQuery(query)) {
+ for (int i = 0; i < 1; i++) {
+ Assert.assertTrue(rs.next());
+ Assert.assertEquals(ans[i], rs.getString(1));
}
- } catch (Exception e) {
- e.printStackTrace();
- fail(e.getMessage());
+ Assert.assertFalse(rs.next());
}
- }
-
- @Test
- public void selectRegexpAlignByDevice() throws ClassNotFoundException {
- String[] retArray =
- new String[] {
- "1509465600000,root.t1.wf01.wt01,1,",
- "1509465660000,root.t1.wf01.wt01,14,",
- "1509466080000,root.t1.wf01.wt01,123%,",
- "1509465600000,root.t1.wf01.wt02,14,"
- };
-
- try (Connection connection = EnvFactory.getEnv().getConnection();
- Statement statement = connection.createStatement()) {
-
- try (ResultSet resultSet =
- statement.executeQuery(
- "select status from root.t1.wf01.wt0* where status regexp '^1.*' align by device"); ) {
- ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
- List<Integer> actualIndexToExpectedIndexList =
- checkHeader(
- resultSetMetaData,
- "Time,Device,status,",
- new int[] {Types.TIMESTAMP, Types.VARCHAR, Types.VARCHAR});
- int cnt = 0;
- while (resultSet.next()) {
- String[] expectedStrings = retArray[cnt].split(",");
- StringBuilder expectedBuilder = new StringBuilder();
- StringBuilder actualBuilder = new StringBuilder();
- for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
- actualBuilder.append(resultSet.getString(i)).append(",");
- expectedBuilder
- .append(expectedStrings[actualIndexToExpectedIndexList.get(i - 1)])
- .append(",");
- }
- Assert.assertEquals(expectedBuilder.toString(), actualBuilder.toString());
- cnt++;
- }
- Assert.assertEquals(4, cnt);
+ ans = new String[] {"abcdef", "_abcdef", "abcdef%"};
+ query = "SELECT s1 FROM likeTest where s1 LIKE s2 ESCAPE s3";
+ try (ResultSet rs = statement.executeQuery(query)) {
+ for (int i = 0; i < 3; i++) {
+ Assert.assertTrue(rs.next());
+ Assert.assertEquals(ans[i], rs.getString(1));
}
- } catch (Exception e) {
- e.printStackTrace();
- fail(e.getMessage());
+ Assert.assertFalse(rs.next());
}
}
}
diff --git a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4 b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
index fac1ad4b46e..bb528c001e2 100644
--- a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
+++ b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
@@ -96,6 +96,7 @@ keyWords
| ELSE
| END
| ENDTIME
+ | ESCAPE
| EVERY
| EXPLAIN
| EXTRACTOR
diff --git a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
index 25bff7e5499..4bbe56b06d5 100644
--- a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
+++ b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
@@ -1274,7 +1274,8 @@ expression
| leftExpression=expression (STAR | DIV | MOD) rightExpression=expression
| leftExpression=expression (PLUS | MINUS) rightExpression=expression
| leftExpression=expression (OPERATOR_GT | OPERATOR_GTE | OPERATOR_LT | OPERATOR_LTE | OPERATOR_SEQ | OPERATOR_DEQ | OPERATOR_NEQ) rightExpression=expression
- | unaryBeforeRegularOrLikeExpression=expression operator_not? (REGEXP | LIKE) STRING_LITERAL
+ | unaryBeforeRegularOrLikeExpression=expression operator_not? REGEXP pattern=STRING_LITERAL
+ | unaryBeforeRegularOrLikeExpression=expression operator_not? LIKE pattern=STRING_LITERAL (ESCAPE escapeSet=STRING_LITERAL)?
| firstExpression=expression operator_not? operator_between secondExpression=expression operator_and thirdExpression=expression
| unaryBeforeIsNullExpression=expression operator_is operator_not? null_literal
| unaryBeforeInExpression=expression operator_not? (operator_in | operator_contains) LR_BRACKET constant (COMMA constant)* RR_BRACKET
diff --git a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4 b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
index 58a35d494f2..a2803be52a4 100644
--- a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
+++ b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
@@ -286,6 +286,10 @@ ENDTIME
: E N D T I M E
;
+ESCAPE
+ : E S C A P E
+ ;
+
EVERY
: E V E R Y
;
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java
index fce36442462..6fa27f8ba3c 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java
@@ -76,6 +76,7 @@ import org.apache.iotdb.db.queryengine.transformation.dag.column.binary.CompareG
import org.apache.iotdb.db.queryengine.transformation.dag.column.binary.CompareLessEqualColumnTransformer;
import org.apache.iotdb.db.queryengine.transformation.dag.column.binary.CompareLessThanColumnTransformer;
import org.apache.iotdb.db.queryengine.transformation.dag.column.binary.CompareNonEqualColumnTransformer;
+import org.apache.iotdb.db.queryengine.transformation.dag.column.binary.Like2ColumnTransformer;
import org.apache.iotdb.db.queryengine.transformation.dag.column.leaf.ConstantColumnTransformer;
import org.apache.iotdb.db.queryengine.transformation.dag.column.leaf.IdentityColumnTransformer;
import org.apache.iotdb.db.queryengine.transformation.dag.column.leaf.LeafColumnTransformer;
@@ -92,6 +93,7 @@ import org.apache.iotdb.db.queryengine.transformation.dag.column.multi.InMultiCo
import org.apache.iotdb.db.queryengine.transformation.dag.column.multi.LogicalAndMultiColumnTransformer;
import org.apache.iotdb.db.queryengine.transformation.dag.column.multi.LogicalOrMultiColumnTransformer;
import org.apache.iotdb.db.queryengine.transformation.dag.column.ternary.BetweenColumnTransformer;
+import org.apache.iotdb.db.queryengine.transformation.dag.column.ternary.Like3ColumnTransformer;
import org.apache.iotdb.db.queryengine.transformation.dag.column.unary.IsNullColumnTransformer;
import org.apache.iotdb.db.queryengine.transformation.dag.column.unary.LikeColumnTransformer;
import org.apache.iotdb.db.queryengine.transformation.dag.column.unary.LogicNotColumnTransformer;
@@ -174,10 +176,10 @@ import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
+import static org.apache.iotdb.db.queryengine.plan.expression.unary.LikeExpression.getEscapeCharacter;
import static org.apache.iotdb.db.queryengine.plan.relational.analyzer.predicate.PredicatePushIntoMetadataChecker.isStringLiteral;
import static org.apache.iotdb.db.queryengine.plan.relational.type.InternalTypeManager.getTSDataType;
import static org.apache.iotdb.db.queryengine.plan.relational.type.TypeSignatureTranslator.toTypeSignature;
-import static org.apache.tsfile.common.regexp.LikePattern.getEscapeCharacter;
import static org.apache.tsfile.read.common.type.BlobType.BLOB;
import static org.apache.tsfile.read.common.type.BooleanType.BOOLEAN;
import static org.apache.tsfile.read.common.type.DoubleType.DOUBLE;
@@ -1155,19 +1157,37 @@ public class ColumnTransformerBuilder
context.inputDataTypes.add(TSDataType.BOOLEAN);
context.cache.put(node, identity);
} else {
+ ColumnTransformer likeColumnTransformer = null;
ColumnTransformer childColumnTransformer = process(node.getValue(), context);
- Optional<String> escapeValueOpt =
- node.getEscape().isPresent()
- ? Optional.ofNullable(((StringLiteral) node.getEscape().get()).getValue())
- : Optional.empty();
- context.cache.put(
- node,
- new LikeColumnTransformer(
- BOOLEAN,
- childColumnTransformer,
- LikePattern.compile(
- ((StringLiteral) node.getPattern()).getValue(),
- getEscapeCharacter(escapeValueOpt))));
+ if ((isStringLiteral(node.getPattern()) && !node.getEscape().isPresent())
+ || (isStringLiteral(node.getPattern()) && isStringLiteral(node.getEscape().get()))) {
+ Optional<Character> escapeSet =
+ node.getEscape().isPresent()
+ ? getEscapeCharacter(((StringLiteral) node.getEscape().get()).getValue())
+ : Optional.empty();
+ likeColumnTransformer =
+ new LikeColumnTransformer(
+ BOOLEAN,
+ childColumnTransformer,
+ LikePattern.compile(((StringLiteral) node.getPattern()).getValue(), escapeSet));
+ } else {
+ ColumnTransformer patternColumnTransformer = process(node.getPattern(), context);
+ if (node.getEscape().isPresent()) {
+ ColumnTransformer escapeColumnTransformer = process(node.getEscape().get(), context);
+ likeColumnTransformer =
+ new Like3ColumnTransformer(
+ BOOLEAN,
+ childColumnTransformer,
+ patternColumnTransformer,
+ escapeColumnTransformer);
+ } else {
+ likeColumnTransformer =
+ new Like2ColumnTransformer(
+ BOOLEAN, childColumnTransformer, patternColumnTransformer);
+ }
+ }
+
+ context.cache.put(node, likeColumnTransformer);
}
}
ColumnTransformer res = context.cache.get(node);
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/ExpressionUtils.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/ExpressionUtils.java
index 41175c08c9d..6d76384c1c8 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/ExpressionUtils.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/ExpressionUtils.java
@@ -170,8 +170,8 @@ public class ExpressionUtils {
resultExpression =
new LikeExpression(
childExpression,
- ((LikeExpression) rawExpression).getPatternString(),
((LikeExpression) rawExpression).getPattern(),
+ ((LikeExpression) rawExpression).getEscape(),
((LikeExpression) rawExpression).isNot());
break;
case LOGIC_NOT:
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/unary/LikeExpression.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/unary/LikeExpression.java
index 69b788cf3a4..f9cdf0427bf 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/unary/LikeExpression.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/unary/LikeExpression.java
@@ -19,12 +19,12 @@
package org.apache.iotdb.db.queryengine.plan.expression.unary;
+import org.apache.iotdb.db.exception.sql.SemanticException;
import org.apache.iotdb.db.queryengine.execution.MemoryEstimationHelper;
import org.apache.iotdb.db.queryengine.plan.expression.Expression;
import org.apache.iotdb.db.queryengine.plan.expression.ExpressionType;
import org.apache.iotdb.db.queryengine.plan.expression.visitor.ExpressionVisitor;
-import org.apache.tsfile.common.regexp.LikePattern;
import org.apache.tsfile.utils.RamUsageEstimator;
import org.apache.tsfile.utils.ReadWriteIOUtils;
@@ -33,46 +33,48 @@ import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Optional;
-import static org.apache.tsfile.common.regexp.LikePattern.getEscapeCharacter;
-
public class LikeExpression extends UnaryExpression {
private static final long INSTANCE_SIZE =
RamUsageEstimator.shallowSizeOfInstance(LikeExpression.class);
- private final String patternString;
- private final LikePattern pattern;
+ private final String pattern;
+ private final Optional<Character> escape;
private final boolean isNot;
- public LikeExpression(Expression expression, String patternString, boolean isNot) {
+ public LikeExpression(
+ Expression expression, String pattern, Optional<Character> escape, boolean isNot) {
super(expression);
- this.patternString = patternString;
+ this.pattern = pattern;
+ this.escape = escape;
this.isNot = isNot;
- pattern = LikePattern.compile(patternString, getEscapeCharacter(Optional.of("\\")));
}
- public LikeExpression(
- Expression expression, String patternString, LikePattern pattern, boolean isNot) {
+ public LikeExpression(Expression expression, String pattern, boolean isNot) {
super(expression);
- this.patternString = patternString;
this.pattern = pattern;
+ this.escape = Optional.empty();
this.isNot = isNot;
}
public LikeExpression(ByteBuffer byteBuffer) {
super(Expression.deserialize(byteBuffer));
- patternString = ReadWriteIOUtils.readString(byteBuffer);
+ pattern = ReadWriteIOUtils.readString(byteBuffer);
+ if (ReadWriteIOUtils.readBool(byteBuffer)) {
+ escape = Optional.of(ReadWriteIOUtils.readString(byteBuffer).charAt(0));
+ } else {
+ escape = Optional.empty();
+ }
isNot = ReadWriteIOUtils.readBool(byteBuffer);
- pattern = LikePattern.compile(patternString, getEscapeCharacter(Optional.of("\\")));
}
- public String getPatternString() {
- return patternString;
+ public String getPattern() {
+ return pattern;
}
- public LikePattern getPattern() {
- return pattern;
+ public Optional<Character> getEscape() {
+ return escape;
}
public boolean isNot() {
@@ -81,7 +83,17 @@ public class LikeExpression extends UnaryExpression {
@Override
protected String getExpressionStringInternal() {
- return expression.getExpressionString() + (isNot ? " NOT" : "") + " LIKE '" + pattern + "'";
+ String res =
+ expression.getExpressionString()
+ + (isNot ? " NOT" : "")
+ + " LIKE "
+ + "pattern = '"
+ + pattern
+ + "'";
+ if (escape.isPresent()) {
+ res = res + " escape = '" + escape.get() + "'";
+ }
+ return res;
}
@Override
@@ -92,20 +104,38 @@ public class LikeExpression extends UnaryExpression {
@Override
protected void serialize(ByteBuffer byteBuffer) {
super.serialize(byteBuffer);
- ReadWriteIOUtils.write(patternString, byteBuffer);
+ ReadWriteIOUtils.write(pattern, byteBuffer);
+ ReadWriteIOUtils.write(escape.isPresent(), byteBuffer);
+ if (escape.isPresent()) {
+ ReadWriteIOUtils.write(escape.get().toString(), byteBuffer);
+ }
ReadWriteIOUtils.write(isNot, byteBuffer);
}
@Override
protected void serialize(DataOutputStream stream) throws IOException {
super.serialize(stream);
- ReadWriteIOUtils.write(patternString, stream);
+ ReadWriteIOUtils.write(pattern, stream);
+ ReadWriteIOUtils.write(escape.isPresent(), stream);
+ if (escape.isPresent()) {
+ ReadWriteIOUtils.write(escape.get().toString(), stream);
+ }
ReadWriteIOUtils.write(isNot, stream);
}
@Override
public String getOutputSymbolInternal() {
- return expression.getOutputSymbol() + (isNot ? " NOT" : "") + " LIKE '" + pattern + "'";
+ String res =
+ expression.getOutputSymbol()
+ + (isNot ? " NOT" : "")
+ + " LIKE "
+ + "pattern = '"
+ + pattern
+ + "'";
+ if (escape.isPresent()) {
+ res = res + " escape = '" + escape.get() + "'";
+ }
+ return res;
}
@Override
@@ -117,6 +147,14 @@ public class LikeExpression extends UnaryExpression {
public long ramBytesUsed() {
return INSTANCE_SIZE
+ MemoryEstimationHelper.getEstimatedSizeOfAccountableObject(expression)
- + RamUsageEstimator.sizeOf(patternString);
+ + RamUsageEstimator.sizeOf(pattern);
+ }
+
+ public static Optional<Character> getEscapeCharacter(String escape) {
+ if (escape.length() == 1) {
+ return Optional.of(escape.charAt(0));
+ } else {
+ throw new SemanticException("Escape string must be a single character");
+ }
}
}
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/ColumnTransformerVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/ColumnTransformerVisitor.java
index bbc12fc7cb3..498cac300fb 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/ColumnTransformerVisitor.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/ColumnTransformerVisitor.java
@@ -71,6 +71,7 @@ import org.apache.iotdb.db.queryengine.transformation.dag.udf.UDTFContext;
import org.apache.iotdb.db.queryengine.transformation.dag.udf.UDTFExecutor;
import org.apache.iotdb.db.queryengine.transformation.dag.util.TransformUtils;
+import org.apache.tsfile.common.regexp.LikePattern;
import org.apache.tsfile.enums.TSDataType;
import org.apache.tsfile.read.common.type.LongType;
import org.apache.tsfile.read.common.type.Type;
@@ -443,8 +444,9 @@ public class ColumnTransformerVisitor
return new ArithmeticNegationColumnTransformer(returnType, childColumnTransformer);
case LIKE:
LikeExpression likeExpression = (LikeExpression) expression;
- return new LikeColumnTransformer(
- returnType, childColumnTransformer, likeExpression.getPattern());
+ LikePattern pattern =
+ LikePattern.compile(likeExpression.getPattern(), likeExpression.getEscape());
+ return new LikeColumnTransformer(returnType, childColumnTransformer, pattern);
case REGEXP:
RegularExpression regularExpression = (RegularExpression) expression;
return new RegularColumnTransformer(
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/IntermediateLayerVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/IntermediateLayerVisitor.java
index 889e90f14e7..b2ab7c6e10f 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/IntermediateLayerVisitor.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/IntermediateLayerVisitor.java
@@ -75,6 +75,7 @@ import org.apache.iotdb.db.queryengine.transformation.dag.udf.UDTFContext;
import org.apache.iotdb.db.queryengine.transformation.dag.udf.UDTFExecutor;
import org.apache.iotdb.udf.api.customizer.strategy.AccessStrategy;
+import org.apache.tsfile.common.regexp.LikePattern;
import org.apache.tsfile.enums.TSDataType;
import java.io.IOException;
@@ -312,7 +313,9 @@ public class IntermediateLayerVisitor
return new ArithmeticNegationTransformer(parentReader);
case LIKE:
LikeExpression likeExpression = (LikeExpression) expression;
- return new LikeTransformer(parentReader, likeExpression.getPattern());
+ LikePattern pattern =
+ LikePattern.compile(likeExpression.getPattern(), likeExpression.getEscape());
+ return new LikeTransformer(parentReader, pattern);
case REGEXP:
RegularExpression regularExpression = (RegularExpression) expression;
return new RegularTransformer(parentReader, regularExpression.getPattern());
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/TransformToViewExpressionVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/TransformToViewExpressionVisitor.java
index 28e1a19c087..27befb28c90 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/TransformToViewExpressionVisitor.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/TransformToViewExpressionVisitor.java
@@ -137,10 +137,7 @@ public class TransformToViewExpressionVisitor extends ExpressionVisitor<ViewExpr
public ViewExpression visitLikeExpression(LikeExpression likeExpression, Void context) {
ViewExpression child = this.process(likeExpression.getExpression(), context);
return new LikeViewExpression(
- child,
- likeExpression.getPatternString(),
- likeExpression.getPattern(),
- likeExpression.isNot());
+ child, likeExpression.getPattern(), likeExpression.getEscape(), likeExpression.isNot());
}
@Override
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/predicate/ConvertPredicateToFilterVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/predicate/ConvertPredicateToFilterVisitor.java
index 126313a46f0..a11f2064243 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/predicate/ConvertPredicateToFilterVisitor.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/predicate/ConvertPredicateToFilterVisitor.java
@@ -45,6 +45,7 @@ import org.apache.iotdb.db.utils.DateTimeUtils;
import com.google.common.io.BaseEncoding;
import org.apache.tsfile.common.conf.TSFileConfig;
+import org.apache.tsfile.common.regexp.LikePattern;
import org.apache.tsfile.enums.TSDataType;
import org.apache.tsfile.read.filter.basic.Filter;
import org.apache.tsfile.read.filter.factory.FilterFactory;
@@ -159,10 +160,12 @@ public class ConvertPredicateToFilterVisitor
PartialPath path = ((TimeSeriesOperand) operand).getPath();
int measurementIndex = context.getMeasurementIndex(path.getMeasurement());
TSDataType dataType = context.getType(path);
+ LikePattern pattern =
+ LikePattern.compile(likeExpression.getPattern(), likeExpression.getEscape());
if (likeExpression.isNot()) {
- return ValueFilterApi.notLike(measurementIndex, likeExpression.getPattern(), dataType);
+ return ValueFilterApi.notLike(measurementIndex, pattern, dataType);
} else {
- return ValueFilterApi.like(measurementIndex, likeExpression.getPattern(), dataType);
+ return ValueFilterApi.like(measurementIndex, pattern, dataType);
}
}
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/predicate/ReversePredicateVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/predicate/ReversePredicateVisitor.java
index 0188a247d57..e9b5c715fb4 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/predicate/ReversePredicateVisitor.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/predicate/ReversePredicateVisitor.java
@@ -59,8 +59,8 @@ public class ReversePredicateVisitor extends PredicateVisitor<Expression, Void>
public Expression visitLikeExpression(LikeExpression likeExpression, Void context) {
return new LikeExpression(
likeExpression.getExpression(),
- likeExpression.getPatternString(),
likeExpression.getPattern(),
+ likeExpression.getEscape(),
!likeExpression.isNot());
}
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
index 2a59e685793..2139fe40d74 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
@@ -248,6 +248,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@@ -255,6 +256,7 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static org.apache.iotdb.commons.schema.SchemaConstant.ALL_RESULT_NODES;
+import static org.apache.iotdb.db.queryengine.plan.expression.unary.LikeExpression.getEscapeCharacter;
import static org.apache.iotdb.db.queryengine.plan.optimization.LimitOffsetPushDown.canPushDownLimitOffsetToGroupByTime;
import static org.apache.iotdb.db.queryengine.plan.optimization.LimitOffsetPushDown.pushDownLimitOffsetToTimeParameter;
import static org.apache.iotdb.db.utils.TimestampPrecisionUtils.TIMESTAMP_PRECISION;
@@ -3135,15 +3137,18 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
private Expression parseRegularExpression(ExpressionContext context, boolean canUseFullPath) {
return new RegularExpression(
parseExpression(context.unaryBeforeRegularOrLikeExpression, canUseFullPath),
- parseStringLiteral(context.STRING_LITERAL().getText()),
- false);
+ parseStringLiteral(String.valueOf(context.pattern.getText())),
+ context.operator_not() != null);
}
private Expression parseLikeExpression(ExpressionContext context, boolean canUseFullPath) {
return new LikeExpression(
parseExpression(context.unaryBeforeRegularOrLikeExpression, canUseFullPath),
- parseStringLiteral(context.STRING_LITERAL().getText()),
- false);
+ parseStringLiteral(String.valueOf(context.pattern.getText())),
+ context.ESCAPE() == null
+ ? Optional.empty()
+ : getEscapeCharacter(parseStringLiteral(String.valueOf(context.escapeSet.getText()))),
+ context.operator_not() != null);
}
private Expression parseIsNullExpression(ExpressionContext context, boolean canUseFullPath) {
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/ConvertPredicateToFilterVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/ConvertPredicateToFilterVisitor.java
index 7d046af30ec..a4ccc8885e6 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/ConvertPredicateToFilterVisitor.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/ConvertPredicateToFilterVisitor.java
@@ -64,11 +64,11 @@ import java.util.Set;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkArgument;
+import static org.apache.iotdb.db.queryengine.plan.expression.unary.LikeExpression.getEscapeCharacter;
import static org.apache.iotdb.db.queryengine.plan.relational.analyzer.predicate.ConvertPredicateToTimeFilterVisitor.getLongValue;
import static org.apache.iotdb.db.queryengine.plan.relational.analyzer.predicate.ConvertPredicateToTimeFilterVisitor.isTimeColumn;
import static org.apache.iotdb.db.queryengine.plan.relational.analyzer.predicate.PredicatePushIntoScanChecker.isLiteral;
import static org.apache.iotdb.db.queryengine.plan.relational.analyzer.predicate.PredicatePushIntoScanChecker.isSymbolReference;
-import static org.apache.tsfile.common.regexp.LikePattern.getEscapeCharacter;
public class ConvertPredicateToFilterVisitor
extends PredicateVisitor<Filter, ConvertPredicateToFilterVisitor.Context> {
@@ -211,16 +211,15 @@ public class ConvertPredicateToFilterVisitor
SymbolReference operand = (SymbolReference) node.getValue();
checkArgument(context.isMeasurementColumn(operand));
int measurementIndex = context.getMeasurementIndex(operand.getName());
- Optional<String> escapeValueOpt =
+ Optional<Character> escapeSet =
node.getEscape().isPresent()
- ? Optional.ofNullable(((StringLiteral) node.getEscape().get()).getValue())
+ ? getEscapeCharacter(((StringLiteral) node.getEscape().get()).getValue())
: Optional.empty();
Type type = context.getType(Symbol.from(operand));
TSDataType dataType = InternalTypeManager.getTSDataType(type);
return ValueFilterApi.like(
measurementIndex,
- LikePattern.compile(
- ((StringLiteral) node.getPattern()).getValue(), getEscapeCharacter(escapeValueOpt)),
+ LikePattern.compile(((StringLiteral) node.getPattern()).getValue(), escapeSet),
dataType);
}
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/schema/ConvertSchemaPredicateToFilterVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/schema/ConvertSchemaPredicateToFilterVisitor.java
index afc0fb769f8..816a546b390 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/schema/ConvertSchemaPredicateToFilterVisitor.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/predicate/schema/ConvertSchemaPredicateToFilterVisitor.java
@@ -62,8 +62,8 @@ import java.util.Optional;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkArgument;
+import static org.apache.iotdb.db.queryengine.plan.expression.unary.LikeExpression.getEscapeCharacter;
import static org.apache.iotdb.db.queryengine.plan.relational.analyzer.predicate.PredicatePushIntoScanChecker.isSymbolReference;
-import static org.apache.tsfile.common.regexp.LikePattern.getEscapeCharacter;
/**
* The {@link ConvertSchemaPredicateToFilterVisitor} will convert a predicate to {@link
@@ -120,8 +120,7 @@ public class ConvertSchemaPredicateToFilterVisitor
new LikeFilter(
(((StringLiteral) node.getPattern()).getValue()),
node.getEscape().isPresent()
- ? getEscapeCharacter(
- Optional.ofNullable(((StringLiteral) node.getEscape().get()).getValue()))
+ ? getEscapeCharacter(((StringLiteral) node.getEscape().get()).getValue())
: Optional.empty()),
((SymbolReference) node.getValue()).getName(),
context);
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/binary/Like2ColumnTransformer.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/binary/Like2ColumnTransformer.java
new file mode 100644
index 00000000000..6f8bd9764db
--- /dev/null
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/binary/Like2ColumnTransformer.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.queryengine.transformation.dag.column.binary;
+
+import org.apache.iotdb.db.queryengine.transformation.dag.column.ColumnTransformer;
+
+import org.apache.tsfile.block.column.Column;
+import org.apache.tsfile.block.column.ColumnBuilder;
+import org.apache.tsfile.common.conf.TSFileConfig;
+import org.apache.tsfile.common.regexp.LikePattern;
+import org.apache.tsfile.read.common.type.Type;
+
+import java.util.Optional;
+
+import static org.apache.iotdb.db.queryengine.plan.relational.metadata.TableMetadataImpl.isCharType;
+
+public class Like2ColumnTransformer extends BinaryColumnTransformer {
+
+ public Like2ColumnTransformer(
+ Type returnType, ColumnTransformer leftTransformer, ColumnTransformer rightTransformer) {
+ super(returnType, leftTransformer, rightTransformer);
+ }
+
+ @Override
+ protected void checkType() {
+ if (!isCharType(leftTransformer.getType())) {
+ throw new UnsupportedOperationException(
+ "Unsupported Type: " + leftTransformer.getType().getTypeEnum());
+ }
+ if (!isCharType(rightTransformer.getType())) {
+ throw new UnsupportedOperationException(
+ "Unsupported Type: " + rightTransformer.getType().getTypeEnum());
+ }
+ }
+
+ @Override
+ protected void doTransform(
+ Column leftColumn, Column rightColumn, ColumnBuilder builder, int positionCount) {
+ for (int i = 0; i < positionCount; i++) {
+ transforme(leftColumn, rightColumn, builder, i);
+ }
+ }
+
+ @Override
+ protected void doTransform(
+ Column leftColumn,
+ Column rightColumn,
+ ColumnBuilder builder,
+ int positionCount,
+ boolean[] selection) {
+ for (int i = 0; i < positionCount; i++) {
+ if (selection[i]) {
+ transforme(leftColumn, rightColumn, builder, i);
+ } else {
+ builder.appendNull();
+ }
+ }
+ }
+
+ private void transforme(Column leftColumn, Column rightColumn, ColumnBuilder builder, int i) {
+ if (!leftColumn.isNull(i) && !rightColumn.isNull(i)) {
+ LikePattern pattern =
+ LikePattern.compile(
+ rightColumn.getBinary(i).getStringValue(TSFileConfig.STRING_CHARSET),
+ Optional.empty(),
+ false);
+ builder.writeBoolean(
+ pattern
+ .getMatcher()
+ .match(leftColumn.getBinary(i).getValues(), 0, leftColumn.getBinary(i).getLength()));
+ } else {
+ builder.appendNull();
+ }
+ }
+}
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/ternary/Like3ColumnTransformer.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/ternary/Like3ColumnTransformer.java
new file mode 100644
index 00000000000..34000e227c6
--- /dev/null
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/ternary/Like3ColumnTransformer.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.queryengine.transformation.dag.column.ternary;
+
+import org.apache.iotdb.db.queryengine.transformation.dag.column.ColumnTransformer;
+
+import org.apache.tsfile.block.column.Column;
+import org.apache.tsfile.block.column.ColumnBuilder;
+import org.apache.tsfile.common.conf.TSFileConfig;
+import org.apache.tsfile.common.regexp.LikePattern;
+import org.apache.tsfile.read.common.type.Type;
+
+import static org.apache.iotdb.db.queryengine.plan.expression.unary.LikeExpression.getEscapeCharacter;
+import static org.apache.iotdb.db.queryengine.plan.relational.metadata.TableMetadataImpl.isCharType;
+
+public class Like3ColumnTransformer extends TernaryColumnTransformer {
+ public Like3ColumnTransformer(
+ Type retuenType,
+ ColumnTransformer firstColumnTransformer,
+ ColumnTransformer secondColumnTransformer,
+ ColumnTransformer thirdColumnTransformer) {
+ super(retuenType, firstColumnTransformer, secondColumnTransformer, thirdColumnTransformer);
+ }
+
+ @Override
+ protected void checkType() {
+ if (!isCharType(firstColumnTransformer.getType())) {
+ throw new UnsupportedOperationException(
+ "Unsupported Type: " + firstColumnTransformer.getType().getTypeEnum());
+ }
+ if (!isCharType(secondColumnTransformer.getType())) {
+ throw new UnsupportedOperationException(
+ "Unsupported Type: " + secondColumnTransformer.getType().getTypeEnum());
+ }
+ if (!isCharType(thirdColumnTransformer.getType())) {
+ throw new UnsupportedOperationException(
+ "Unsupported Type: " + thirdColumnTransformer.getType().getTypeEnum());
+ }
+ }
+
+ @Override
+ protected void doTransform(
+ Column firstColumn,
+ Column secondColumn,
+ Column thirdColumn,
+ ColumnBuilder builder,
+ int positionCount) {
+ for (int i = 0; i < positionCount; i++) {
+ transform(firstColumn, secondColumn, thirdColumn, builder, i);
+ }
+ }
+
+ @Override
+ protected void doTransform(
+ Column firstColumn,
+ Column secondColumn,
+ Column thirdColumn,
+ ColumnBuilder builder,
+ int positionCount,
+ boolean[] selection) {
+ for (int i = 0; i < positionCount; i++) {
+ if (selection[i]) {
+ transform(firstColumn, secondColumn, thirdColumn, builder, i);
+ } else {
+ builder.appendNull();
+ }
+ }
+ }
+
+ private void transform(
+ Column firstColumn, Column secondColumn, Column thirdColumn, ColumnBuilder builder, int i) {
+ if (!firstColumn.isNull(i) && !secondColumn.isNull(i) && !thirdColumn.isNull(i)) {
+ LikePattern pattern =
+ LikePattern.compile(
+ secondColumn.getBinary(i).getStringValue(TSFileConfig.STRING_CHARSET),
+ getEscapeCharacter(
+ thirdColumn.getBinary(i).getStringValue(TSFileConfig.STRING_CHARSET)),
+ false);
+ builder.writeBoolean(
+ pattern
+ .getMatcher()
+ .match(
+ firstColumn.getBinary(i).getValues(), 0, firstColumn.getBinary(i).getLength()));
+ } else {
+ builder.appendNull();
+ }
+ }
+}
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/transformer/unary/LikeTransformer.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/transformer/unary/LikeTransformer.java
index 61d896847cf..80690826d74 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/transformer/unary/LikeTransformer.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/transformer/unary/LikeTransformer.java
@@ -37,7 +37,6 @@ public class LikeTransformer extends UnaryTransformer {
public LikeTransformer(LayerReader layerReader, LikePattern pattern) {
super(layerReader);
this.pattern = pattern;
-
if (layerReaderDataType != TSDataType.TEXT) {
throw new UnSupportedDataTypeException("Unsupported data type: " + layerReaderDataType);
}
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/view/visitor/TransformToExpressionVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/view/visitor/TransformToExpressionVisitor.java
index 7ad1de7a5cb..8bedc236c27 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/view/visitor/TransformToExpressionVisitor.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/view/visitor/TransformToExpressionVisitor.java
@@ -152,10 +152,7 @@ public class TransformToExpressionVisitor extends ViewExpressionVisitor<Expressi
public Expression visitLikeExpression(LikeViewExpression likeExpression, Void context) {
Expression child = this.process(likeExpression.getExpression(), context);
return new org.apache.iotdb.db.queryengine.plan.expression.unary.LikeExpression(
- child,
- likeExpression.getPatternString(),
- likeExpression.getPattern(),
- likeExpression.isNot());
+ child, likeExpression.getPattern(), likeExpression.getEscape(), likeExpression.isNot());
}
@Override
diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/filter/impl/values/LikeFilter.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/filter/impl/values/LikeFilter.java
index 168e0b7c88a..b810c91fd80 100644
--- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/filter/impl/values/LikeFilter.java
+++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/filter/impl/values/LikeFilter.java
@@ -32,9 +32,6 @@ import java.nio.ByteBuffer;
import java.util.Objects;
import java.util.Optional;
-import static org.apache.tsfile.common.regexp.LikePattern.getEscapeCharacter;
-
-// Does not support escape now
public class LikeFilter extends SchemaFilter {
private final LikePattern pattern;
@@ -47,7 +44,7 @@ public class LikeFilter extends SchemaFilter {
LikePattern.compile(
ReadWriteIOUtils.readString(byteBuffer),
ReadWriteIOUtils.readBool(byteBuffer)
- ? getEscapeCharacter(Optional.of(ReadWriteIOUtils.readString(byteBuffer)))
+ ? Optional.of(ReadWriteIOUtils.readString(byteBuffer).charAt(0))
: Optional.empty());
}
diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/view/viewExpression/unary/LikeViewExpression.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/view/viewExpression/unary/LikeViewExpression.java
index 063116db0b8..e52f436f23e 100644
--- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/view/viewExpression/unary/LikeViewExpression.java
+++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/view/viewExpression/unary/LikeViewExpression.java
@@ -23,7 +23,6 @@ import org.apache.iotdb.commons.schema.view.viewExpression.ViewExpression;
import org.apache.iotdb.commons.schema.view.viewExpression.ViewExpressionType;
import org.apache.iotdb.commons.schema.view.viewExpression.visitor.ViewExpressionVisitor;
-import org.apache.tsfile.common.regexp.LikePattern;
import org.apache.tsfile.utils.ReadWriteIOUtils;
import java.io.IOException;
@@ -32,44 +31,49 @@ import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.Optional;
-import static org.apache.tsfile.common.regexp.LikePattern.getEscapeCharacter;
-
public class LikeViewExpression extends UnaryViewExpression {
// region member variables and init functions
- private final String patternString;
- private final LikePattern pattern;
-
+ private final String pattern;
+ private final Optional<Character> escape;
private final boolean isNot;
- public LikeViewExpression(ViewExpression expression, String patternString, boolean isNot) {
+ public LikeViewExpression(
+ ViewExpression expression, String pattern, Optional<Character> escape, boolean isNot) {
super(expression);
- this.patternString = patternString;
+ this.pattern = pattern;
+ this.escape = escape;
this.isNot = isNot;
- pattern = LikePattern.compile(patternString, getEscapeCharacter(Optional.of("\\")));
}
- public LikeViewExpression(
- ViewExpression expression, String patternString, LikePattern pattern, boolean isNot) {
+ public LikeViewExpression(ViewExpression expression, String pattern, boolean isNot) {
super(expression);
- this.patternString = patternString;
this.pattern = pattern;
+ this.escape = Optional.empty();
this.isNot = isNot;
}
public LikeViewExpression(ByteBuffer byteBuffer) {
super(ViewExpression.deserialize(byteBuffer));
- patternString = ReadWriteIOUtils.readString(byteBuffer);
+ pattern = ReadWriteIOUtils.readString(byteBuffer);
+ if (ReadWriteIOUtils.readBool(byteBuffer)) {
+ escape = Optional.of(ReadWriteIOUtils.readString(byteBuffer).charAt(0));
+ } else {
+ escape = Optional.empty();
+ }
isNot = ReadWriteIOUtils.readBool(byteBuffer);
- pattern = LikePattern.compile(patternString, getEscapeCharacter(Optional.of("\\")));
}
public LikeViewExpression(InputStream inputStream) {
super(ViewExpression.deserialize(inputStream));
try {
- patternString = ReadWriteIOUtils.readString(inputStream);
+ pattern = ReadWriteIOUtils.readString(inputStream);
+ if (ReadWriteIOUtils.readBool(inputStream)) {
+ escape = Optional.of(ReadWriteIOUtils.readString(inputStream).charAt(0));
+ } else {
+ escape = Optional.empty();
+ }
isNot = ReadWriteIOUtils.readBool(inputStream);
- pattern = LikePattern.compile(patternString, getEscapeCharacter(Optional.of("\\")));
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -91,7 +95,14 @@ public class LikeViewExpression extends UnaryViewExpression {
@Override
public String toString(boolean isRoot) {
String basicString =
- this.expression.toString(false) + (isNot ? "NOT LIKE " : "LIKE ") + this.patternString;
+ this.expression.toString(false)
+ + (isNot ? "NOT LIKE " : "LIKE ")
+ + "pattern = '"
+ + this.pattern
+ + "'";
+ if (escape.isPresent()) {
+ basicString += " escape = '" + escape.get() + "'";
+ }
if (isRoot) {
return basicString;
}
@@ -101,25 +112,33 @@ public class LikeViewExpression extends UnaryViewExpression {
@Override
protected void serialize(ByteBuffer byteBuffer) {
super.serialize(byteBuffer);
- ReadWriteIOUtils.write(patternString, byteBuffer);
+ ReadWriteIOUtils.write(pattern, byteBuffer);
+ ReadWriteIOUtils.write(escape.isPresent(), byteBuffer);
+ if (escape.isPresent()) {
+ ReadWriteIOUtils.write(escape.get().toString(), byteBuffer);
+ }
ReadWriteIOUtils.write(isNot, byteBuffer);
}
@Override
protected void serialize(OutputStream stream) throws IOException {
super.serialize(stream);
- ReadWriteIOUtils.write(patternString, stream);
+ ReadWriteIOUtils.write(pattern, stream);
+ ReadWriteIOUtils.write(escape.isPresent(), stream);
+ if (escape.isPresent()) {
+ ReadWriteIOUtils.write(escape.get().toString(), stream);
+ }
ReadWriteIOUtils.write(isNot, stream);
}
// endregion
- public String getPatternString() {
- return patternString;
+ public String getPattern() {
+ return pattern;
}
- public LikePattern getPattern() {
- return pattern;
+ public Optional<Character> getEscape() {
+ return escape;
}
public boolean isNot() {
diff --git a/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4 b/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
index 407361db0b4..1a3c4a5817f 100644
--- a/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
+++ b/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
@@ -167,7 +167,7 @@ dropTableStatement
showTableStatement
: SHOW TABLES ((FROM | IN) database=identifier)?
- // ((LIKE pattern=string) | (WHERE expression))?
+ // ((LIKE pattern=string (ESCAPE escape=string)) | (WHERE expression))?
;
descTableStatement
@@ -370,7 +370,7 @@ showClusterStatement
showRegionsStatement
: SHOW (SCHEMA | DATA)? REGIONS ((FROM | IN) identifier)?
- // ((LIKE pattern=string) | (WHERE expression))?
+ // ((LIKE pattern=string (ESCAPE escape=string)) | (WHERE expression))?
;
showDataNodesStatement
@@ -650,7 +650,6 @@ relationPrimary
| '(' relation ')' #parenthesizedRelation
;
-
expression
: booleanExpression
;