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 2022/08/25 08:17:08 UTC
[iotdb] branch master updated: [IOTDB-4133] Throw illegal path exception contains number which has been surrounded with quote (#7017)
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 4108e7c6f9 [IOTDB-4133] Throw illegal path exception contains number which has been surrounded with quote (#7017)
4108e7c6f9 is described below
commit 4108e7c6f9aaa5b0215e4c512867dab6895922a3
Author: Liao Lanyu <10...@users.noreply.github.com>
AuthorDate: Thu Aug 25 16:17:01 2022 +0800
[IOTDB-4133] Throw illegal path exception contains number which has been surrounded with quote (#7017)
---
docs/UserGuide/Reference/Syntax-Conventions.md | 14 ++++----
docs/zh/Download/README.md | 6 ++--
docs/zh/UserGuide/Reference/Syntax-Conventions.md | 18 +++++-----
.../db/it/IoTDBSyntaxConventionIdentifierIT.java | 40 ++++++++++++++++++++++
.../org/apache/iotdb/commons/utils/PathUtils.java | 10 ++++--
.../iotdb/db/mpp/plan/parser/ASTVisitor.java | 4 +--
.../apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java | 3 +-
.../tsfile/read/common/parser/PathVisitor.java | 29 ++++++++++++++--
8 files changed, 97 insertions(+), 27 deletions(-)
diff --git a/docs/UserGuide/Reference/Syntax-Conventions.md b/docs/UserGuide/Reference/Syntax-Conventions.md
index fbf0d3503c..cc5b3ef057 100644
--- a/docs/UserGuide/Reference/Syntax-Conventions.md
+++ b/docs/UserGuide/Reference/Syntax-Conventions.md
@@ -309,14 +309,14 @@ Below are basic constraints of identifiers, specific identifiers may have other
- Permitted characters in unquoted identifiers:
- [0-9 a-z A-Z _ ] (letters, digits and underscore)
- ['\u2E80'..'\u9FFF'] (UNICODE Chinese characters)
-- Identifiers may begin with a digit, unquoted identifiers can not consists of solely digits.
+- Identifiers may begin with a digit, unquoted identifiers can not be a real number.
- Identifiers are case sensitive.
- Key words can be used as an identifier.
**You need to quote the identifier with back quote(`) in the following cases:**
- Identifier contains special characters.
-- Identifier consists of solely digits.
+- Identifier that is a real number.
### How to use quotations marks in quoted identifiers
@@ -355,14 +355,14 @@ Examples of case in which quoted identifier is used :
- UDF name should be quoted in cases described above :
```sql
- # create a funciton named 111, 111 consists of solely digits.
+ # create a funciton named 111, 111 is a real number.
CREATE FUNCTION `111` AS 'org.apache.iotdb.udf.UDTFExample'
```
- Template name should be quoted in cases described above :
```sql
- # create a template named 111, 111 consists of solely digits.
+ # create a template named 111, 111 is a real number.
create schema template `111`
(temperature FLOAT encoding=RLE, status BOOLEAN encoding=PLAIN compression=SNAPPY)
```
@@ -461,7 +461,7 @@ When node name is not wildcard, it is a identifier, which means the constraints
# Node name contains special characters like ` and .,all nodes of this timeseries are: ["root","sg","www.`baidu.com"]
create timeseries root.sg.`www.``baidu.com`.a with datatype=FLOAT,encoding=PLAIN;
-# Node name consists of solely digits.
+# Node name is a real number.
create timeseries root.sg.`111` with datatype=FLOAT,encoding=PLAIN;
```
@@ -482,7 +482,7 @@ After executing above statments, execute "show timeseries",below is the result
# Node name contains special characters like . and `
insert into root.sg.`www.``baidu.com`(timestamp, a) values(1, 2);
-# Node name consists of solely digits.
+# Node name is a real number.
insert into root.sg(timestamp, `111`) values (1, 2);
```
@@ -492,7 +492,7 @@ insert into root.sg(timestamp, `111`) values (1, 2);
# Node name contains special characters like . and `
select a from root.sg.`www.``baidu.com`;
-# Node name consists of solely digits.
+# Node name is a real number.
select `111` from root.sg
```
diff --git a/docs/zh/Download/README.md b/docs/zh/Download/README.md
index 1e1aef4d36..0272a1a038 100644
--- a/docs/zh/Download/README.md
+++ b/docs/zh/Download/README.md
@@ -110,9 +110,9 @@
- 如何从 v0.13.x 升级到 v0.14.x?
- **0.14 版本进行了 SQL 语法约定的改动(请参考用户手册语法约定章节),不兼容之处如下:**
- - **不使用反引号引用的标识符不允许为纯数字,不使用反引号引用的标识符,只允许包含字母、中文字符、下划线。如果标识符中出现上述情况,请使用反引号将标识符括起。**
+ - **不使用反引号引用的标识符不允许为实数,不使用反引号引用的标识符,只允许包含字母、中文字符、下划线。如果标识符中出现上述情况,请使用反引号将标识符括起。**
- **标识符不再支持使用单引号和双引号进行引用,请统一改为使用反引号引用。**
- - **Session 接口中使用路径结点名时,写法需要与 SQL 语句中的一致。如路径结点为纯数字111,在 SQL 语句中需要使用反引号括起,写作\`111\`, 那么使用 Session 接口时,相应参数也需要写作\`111\`。**
+ - **Session 接口中使用路径结点名时,写法需要与 SQL 语句中的一致。如路径结点为实数111,在 SQL 语句中需要使用反引号括起,写作\`111\`, 那么使用 Session 接口时,相应参数也需要写作\`111\`。**
- 为了保证 UDF 相关 API 的稳定性,0.14 版本中 UDF 相关 API 被独立为一个单独的 module,不再依赖 tsfile 包,已经实现的 UDF 需要改写代码,将 `TsDataType` 替换为 `Type`,将 `org.apache.iotdb.tsfile.utils.Binary` 替换成 `org.apache.iotdb.udf.api.type.Binary`,并重新进行打包装载流程。
# 如何升级
@@ -135,7 +135,7 @@
* **0.13 进行了 SQL 语法的改动,不使用反引号括起的标识符中仅能包含如下字符,否则需要使用反引号括起。**
* **[0-9 a-z A-Z _ : @ # $ { }] (字母,数字,部分特殊字符)**
* **['\u2E80'..'\u9FFF'] (UNICODE 中文字符)**
- * **0.13 中 `SELECT` 子句中路径结点名如果是纯数字,需要使用反引号引起,用于与表达式中的常数区分。如语句 "select 123 + \`123\` from root.sg",前一个123表示常数,后一个 \`123\`会和 root.sg 拼接,表示路径 root.sg.\`123\`。**
+ * **0.13 中 `SELECT` 子句中路径结点名如果是实数,需要使用反引号引起,用于与表达式中的常数区分。如语句 "select 123 + \`123\` from root.sg",前一个123表示常数,后一个 \`123\`会和 root.sg 拼接,表示路径 root.sg.\`123\`。**
- 如何从 v0.11.x 或 v0.10.x 升级到 v0.12.x?
* 从 0.11 或 0.10 升级到 0.12 的过程与 v0.9 升级到 v0.10 类似,升级工具会自动进行数据文件的升级。
diff --git a/docs/zh/UserGuide/Reference/Syntax-Conventions.md b/docs/zh/UserGuide/Reference/Syntax-Conventions.md
index 8337ed3d57..1f543a4c6b 100644
--- a/docs/zh/UserGuide/Reference/Syntax-Conventions.md
+++ b/docs/zh/UserGuide/Reference/Syntax-Conventions.md
@@ -27,7 +27,7 @@
### 标识符限制增强
-在0.13及之前版本中,不使用反引号引用的标识符(包括路径结点)允许为纯数字(纯数字路径名在 `SELECT` 子句中需要用反引号括起),且允许包含部分特殊字符,**在0.14版本中,不使用反引号引用的标识符不允许为纯数字,不使用反引号引用的标识符,只允许包含字母、中文字符、下划线。**
+在0.13及之前版本中,不使用反引号引用的标识符(包括路径结点)允许为实数(实数路径名在 `SELECT` 子句中需要用反引号括起),且允许包含部分特殊字符,**在0.14版本中,不使用反引号引用的标识符不允许为实数,不使用反引号引用的标识符,只允许包含字母、中文字符、下划线。**
### 路径名使用的相关问题
@@ -319,7 +319,7 @@ MySQL 对字符串的定义可以参考:[MySQL :: MySQL 8.0 Reference Manual :
**如果出现如下情况,标识符需要使用反引号进行引用:**
- 标识符包含不允许的特殊字符。
-- 标识符为纯数字。
+- 标识符为实数。
### 如何在反引号引起的标识符中使用引号
@@ -358,14 +358,14 @@ create schema template `t1't"t`
- UDF 名称出现上述特殊情况时需使用反引号引用:
```sql
- # 创建名为 111 的 UDF,111 为纯数字,所以需要用反引号引用。
+ # 创建名为 111 的 UDF,111 为实数,所以需要用反引号引用。
CREATE FUNCTION `111` AS 'org.apache.iotdb.udf.UDTFExample'
```
- 元数据模板名称出现上述特殊情况时需使用反引号引用:
```sql
- # 创建名为 111 的元数据模板,111 为纯数字,需要用反引号引用。
+ # 创建名为 111 的元数据模板,111 为实数,需要用反引号引用。
create schema template `111`
(temperature FLOAT encoding=RLE, status BOOLEAN encoding=PLAIN compression=SNAPPY)
```
@@ -464,7 +464,7 @@ select a*b from root.sg
# 路径结点名中包含特殊字符,时间序列各结点为["root","sg","www.`baidu.com"]
create timeseries root.sg.`www.``baidu.com`.a with datatype=FLOAT,encoding=PLAIN;
-# 路径结点名为纯数字
+# 路径结点名为实数
create timeseries root.sg.`111` with datatype=FLOAT,encoding=PLAIN;
```
@@ -485,7 +485,7 @@ create timeseries root.sg.`111` with datatype=FLOAT,encoding=PLAIN;
# 路径结点名中包含特殊字符
insert into root.sg.`www.``baidu.com`(timestamp, a) values(1, 2);
-# 路径结点名为纯数字
+# 路径结点名为实数
insert into root.sg(timestamp, `111`) values (1, 2);
```
@@ -495,7 +495,7 @@ insert into root.sg(timestamp, `111`) values (1, 2);
# 路径结点名中包含特殊字符
select a from root.sg.`www.``baidu.com`;
-# 路径结点名为纯数字
+# 路径结点名为实数
select `111` from root.sg
```
@@ -645,7 +645,7 @@ create timeseries root.sg.a with datatype=FLOAT,encoding=PLAIN,compressor=SNAPPY
# 路径结点名中包含特殊字符,时间序列各结点为["root","sg","a.`\"b"]
create timeseries root.sg.`a.``"b` with datatype=FLOAT,encoding=PLAIN,compressor=SNAPPY;
-# 路径结点名为纯数字
+# 路径结点名为实数
create timeseries root.sg.`111` with datatype=FLOAT,encoding=PLAIN,compressor=SNAPPY;
```
@@ -709,7 +709,7 @@ select a from root.sg
# 路径结点名中包含特殊字符
select `a.``"b` from root.sg;
-# 路径结点名为纯数字
+# 路径结点名为实数
select `111` from root.sg
```
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSyntaxConventionIdentifierIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSyntaxConventionIdentifierIT.java
index 9969d2e699..7af57028af 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSyntaxConventionIdentifierIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSyntaxConventionIdentifierIT.java
@@ -152,6 +152,16 @@ public class IoTDBSyntaxConventionIdentifierIT {
"````",
"`c.d.```",
"`abc`",
+ "`+12`",
+ "`1e3`",
+ "`001`",
+ "`-1.0`",
+ "`01e-3`",
+ "`+0001`",
+ "`-0001`",
+ "`++1`",
+ "`+-1`",
+ "`--1`"
};
String[] resultTimeseries = {
@@ -166,6 +176,16 @@ public class IoTDBSyntaxConventionIdentifierIT {
"root.sg1.d1.````",
"root.sg1.d1.`c.d.```",
"root.sg1.d1.abc",
+ "root.sg1.d1.`+12`",
+ "root.sg1.d1.`1e3`",
+ "root.sg1.d1.`001`",
+ "root.sg1.d1.`-1.0`",
+ "root.sg1.d1.`01e-3`",
+ "root.sg1.d1.`+0001`",
+ "root.sg1.d1.`-0001`",
+ "root.sg1.d1.`++1`",
+ "root.sg1.d1.`+-1`",
+ "root.sg1.d1.`--1`"
};
String[] selectNodeNames = {
@@ -180,6 +200,16 @@ public class IoTDBSyntaxConventionIdentifierIT {
"````",
"`c.d.```",
"abc",
+ "`+12`",
+ "`1e3`",
+ "`001`",
+ "`-1.0`",
+ "`01e-3`",
+ "`+0001`",
+ "`-0001`",
+ "`++1`",
+ "`+-1`",
+ "`--1`"
};
String[] suffixInResultColumns = {
@@ -194,6 +224,16 @@ public class IoTDBSyntaxConventionIdentifierIT {
"````",
"`c.d.```",
"abc",
+ "`+12`",
+ "`1e3`",
+ "`001`",
+ "`-1.0`",
+ "`01e-3`",
+ "`+0001`",
+ "`-0001`",
+ "`++1`",
+ "`+-1`",
+ "`--1`"
};
try (Connection connection = EnvFactory.getEnv().getConnection();
diff --git a/node-commons/src/main/java/org/apache/iotdb/commons/utils/PathUtils.java b/node-commons/src/main/java/org/apache/iotdb/commons/utils/PathUtils.java
index ccdf8921ca..658df351ef 100644
--- a/node-commons/src/main/java/org/apache/iotdb/commons/utils/PathUtils.java
+++ b/node-commons/src/main/java/org/apache/iotdb/commons/utils/PathUtils.java
@@ -24,8 +24,7 @@ import org.apache.iotdb.commons.exception.MetadataException;
import org.apache.iotdb.tsfile.common.constant.TsFileConstant;
import org.apache.iotdb.tsfile.exception.PathParseException;
import org.apache.iotdb.tsfile.read.common.parser.PathNodesGenerator;
-
-import org.apache.commons.lang3.StringUtils;
+import org.apache.iotdb.tsfile.read.common.parser.PathVisitor;
import java.util.List;
@@ -90,7 +89,7 @@ public class PathUtils {
}
}
if (IoTDBConstant.reservedWords.contains(measurement.toUpperCase())
- || StringUtils.isNumeric(measurement)
+ || isRealNumber(measurement)
|| !TsFileConstant.NODE_NAME_PATTERN.matcher(measurement).matches()) {
throw new IllegalPathException(measurement);
}
@@ -126,6 +125,11 @@ public class PathUtils {
}
}
+ /** Return true if the str is a real number. Examples: 1.0; +1.0; -1.0; 0011; 011e3; +23e-3 */
+ public static boolean isRealNumber(String str) {
+ return PathVisitor.isRealNumber(str);
+ }
+
public static boolean isStartWith(String deviceName, String storageGroup) {
return deviceName.equals(storageGroup) || deviceName.startsWith(storageGroup + ".");
}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
index 0c51b1a958..7b598c96ae 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
@@ -24,6 +24,7 @@ import org.apache.iotdb.commons.auth.entity.PrivilegeType;
import org.apache.iotdb.commons.conf.IoTDBConstant;
import org.apache.iotdb.commons.exception.IllegalPathException;
import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.commons.utils.PathUtils;
import org.apache.iotdb.db.conf.IoTDBConfig;
import org.apache.iotdb.db.conf.IoTDBDescriptor;
import org.apache.iotdb.db.exception.sql.SQLParserException;
@@ -156,7 +157,6 @@ import org.apache.iotdb.tsfile.read.common.TimeRange;
import org.apache.iotdb.tsfile.utils.Pair;
import org.apache.commons.lang.StringEscapeUtils;
-import org.apache.commons.lang3.StringUtils;
import java.net.URI;
import java.net.URISyntaxException;
@@ -1463,7 +1463,7 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
if (nodeName.startsWith(TsFileConstant.BACK_QUOTE_STRING)
&& nodeName.endsWith(TsFileConstant.BACK_QUOTE_STRING)) {
String unWrapped = nodeName.substring(1, nodeName.length() - 1);
- if (StringUtils.isNumeric(unWrapped)
+ if (PathUtils.isRealNumber(unWrapped)
|| !TsFileConstant.IDENTIFIER_PATTERN.matcher(unWrapped).matches()) {
return nodeName;
}
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 03bb951a74..e4c2673a34 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
@@ -22,6 +22,7 @@ import org.apache.iotdb.commons.auth.entity.PrivilegeType;
import org.apache.iotdb.commons.conf.IoTDBConstant;
import org.apache.iotdb.commons.exception.IllegalPathException;
import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.commons.utils.PathUtils;
import org.apache.iotdb.db.conf.IoTDBConfig;
import org.apache.iotdb.db.conf.IoTDBDescriptor;
import org.apache.iotdb.db.engine.trigger.executor.TriggerEvent;
@@ -2674,7 +2675,7 @@ public class IoTDBSqlVisitor extends IoTDBSqlParserBaseVisitor<Operator> {
if (nodeName.startsWith(TsFileConstant.BACK_QUOTE_STRING)
&& nodeName.endsWith(TsFileConstant.BACK_QUOTE_STRING)) {
String unWrapped = nodeName.substring(1, nodeName.length() - 1);
- if (StringUtils.isNumeric(unWrapped)
+ if (PathUtils.isRealNumber(unWrapped)
|| !TsFileConstant.IDENTIFIER_PATTERN.matcher(unWrapped).matches()) {
return nodeName;
}
diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/parser/PathVisitor.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/parser/PathVisitor.java
index 537fd5b9a1..d804f6ef1b 100644
--- a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/parser/PathVisitor.java
+++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/parser/PathVisitor.java
@@ -23,7 +23,7 @@ import org.apache.iotdb.db.qp.sql.PathParser.NodeNameContext;
import org.apache.iotdb.db.qp.sql.PathParserBaseVisitor;
import org.apache.iotdb.tsfile.common.constant.TsFileConstant;
-import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
import java.util.List;
@@ -64,7 +64,7 @@ public class PathVisitor extends PathParserBaseVisitor<String[]> {
if (nodeName.startsWith(TsFileConstant.BACK_QUOTE_STRING)
&& nodeName.endsWith(TsFileConstant.BACK_QUOTE_STRING)) {
String unWrapped = nodeName.substring(1, nodeName.length() - 1);
- if (StringUtils.isNumeric(unWrapped)
+ if (isRealNumber(unWrapped)
|| !TsFileConstant.IDENTIFIER_PATTERN.matcher(unWrapped).matches()) {
return nodeName;
}
@@ -72,4 +72,29 @@ public class PathVisitor extends PathParserBaseVisitor<String[]> {
}
return nodeName;
}
+
+ /** Return true if the str is a real number. Examples: 1.0; +1.0; -1.0; 0011; 011e3; +23e-3 */
+ public static boolean isRealNumber(String str) {
+ if (str.startsWith("+") || str.startsWith("-")) {
+ String removeSign = str.substring(1);
+ if (removeSign.startsWith("+") || removeSign.startsWith("-")) {
+ return false;
+ } else {
+ str = removeSign;
+ }
+ }
+ int index = 0;
+ // remove zeros
+ for (int i = 0, n = str.length(); i < n; i++) {
+ if (str.charAt(i) != '0') {
+ index = i;
+ break;
+ }
+ }
+ return NumberUtils.isCreatable(str.substring(index));
+ }
+
+ public static void main(String[] args) {
+ System.out.println(isRealNumber("+-1"));
+ }
}