This is an automated email from the ASF dual-hosted git repository.
rong 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 6ec70deb51 [IOTDB-3230] Change characters allowed in identifier (#6039)
6ec70deb51 is described below
commit 6ec70deb51f6cb033f2e60ea22c57204b3dac5d7
Author: Liao Lanyu <[email protected]>
AuthorDate: Sun May 29 15:19:48 2022 +0800
[IOTDB-3230] Change characters allowed in identifier (#6039)
---
docs/UserGuide/Reference/Syntax-Conventions.md | 4 +-
docs/zh/UserGuide/Reference/Syntax-Conventions.md | 7 +-
.../IoTDBSyntaxConventionIdentifierIT.java | 8 ---
.../iotdb/db/mpp/plan/parser/ASTVisitor.java | 27 +++++++-
.../apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java | 76 +++++++++++++++++++++-
.../tsfile/common/constant/TsFileConstant.java | 5 +-
.../tsfile/read/common/parser/PathVisitor.java | 2 +-
7 files changed, 109 insertions(+), 20 deletions(-)
diff --git a/docs/UserGuide/Reference/Syntax-Conventions.md
b/docs/UserGuide/Reference/Syntax-Conventions.md
index 1b202d4b7d..cb00ab9706 100644
--- a/docs/UserGuide/Reference/Syntax-Conventions.md
+++ b/docs/UserGuide/Reference/Syntax-Conventions.md
@@ -287,11 +287,11 @@ Certain objects within IoTDB, including `TRIGGER`,
`FUNCTION`(UDF), `CONTINUOUS
Below are basic constraints of identifiers, specific identifiers may have
other constraints, for example, `user` should consists of more than 4
characters.
- Permitted characters in unquoted identifiers:
- - [0-9 a-z A-Z _ : @ # $ { }] (letters, digits, some special characters)
+ - [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 are case sensitive.
-- Key words can be used as an identifier.
+- Key words can be used as an identifier.
**You need to quote the identifier with back quote(`) in the following cases:**
diff --git a/docs/zh/UserGuide/Reference/Syntax-Conventions.md
b/docs/zh/UserGuide/Reference/Syntax-Conventions.md
index de39e2c74d..1bdfda42e0 100644
--- a/docs/zh/UserGuide/Reference/Syntax-Conventions.md
+++ b/docs/zh/UserGuide/Reference/Syntax-Conventions.md
@@ -286,10 +286,9 @@ MySQL 对字符串的定义可以参考:[MySQL :: MySQL 8.0 Reference Manual :
**标识符命名有以下约束:**
- 不使用反引号括起的标识符中,允许出现以下字符:
- - [ 0-9 a-z A-Z _ : @ # $ { } ] (字母,数字,部分特殊字符)
-
-- ['\u2E80'..'\u9FFF'] (UNICODE 中文字符)
-
+ - [ 0-9 a-z A-Z _ ] (字母,数字,下划线)
+ - ['\u2E80'..'\u9FFF'] (UNICODE 中文字符)
+
- 标识符允许使用数字开头、不使用反引号括起的标识符不能全部为数字。
- 标识符是大小写敏感的。
diff --git
a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBSyntaxConventionIdentifierIT.java
b/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBSyntaxConventionIdentifierIT.java
index 643a29c048..7f6d682ada 100644
---
a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBSyntaxConventionIdentifierIT.java
+++
b/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBSyntaxConventionIdentifierIT.java
@@ -144,7 +144,6 @@ public class IoTDBSyntaxConventionIdentifierIT {
public void testNodeName() {
String[] createNodeNames = {
"a_1",
- "A@#{}:",
"aaa",
"`select`",
"`a.b`",
@@ -155,12 +154,10 @@ public class IoTDBSyntaxConventionIdentifierIT {
"````",
"`c.d.```",
"`abc`",
- "a1_:@#${}"
};
String[] resultTimeseries = {
"root.sg1.d1.a_1",
- "root.sg1.d1.A@#{}:",
"root.sg1.d1.aaa",
"root.sg1.d1.select",
"root.sg1.d1.`a.b`",
@@ -171,12 +168,10 @@ public class IoTDBSyntaxConventionIdentifierIT {
"root.sg1.d1.````",
"root.sg1.d1.`c.d.```",
"root.sg1.d1.abc",
- "root.sg1.d1.a1_:@#${}",
};
String[] selectNodeNames = {
"a_1",
- "A@#{}:",
"aaa",
"`select`",
"`a.b`",
@@ -187,12 +182,10 @@ public class IoTDBSyntaxConventionIdentifierIT {
"````",
"`c.d.```",
"abc",
- "a1_:@#${}",
};
String[] suffixInResultColumns = {
"a_1",
- "A@#{}:",
"aaa",
"select",
"`a.b`",
@@ -203,7 +196,6 @@ public class IoTDBSyntaxConventionIdentifierIT {
"````",
"`c.d.```",
"abc",
- "a1_:@#${}",
};
try (Connection connection = EnvFactory.getEnv().getConnection();
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 f01b7b1a61..25f2c5bce1 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
@@ -1273,18 +1273,42 @@ public class ASTVisitor extends
IoTDBSqlParserBaseVisitor<Statement> {
}
private String parseNodeString(String nodeName) {
+ if (nodeName.equals(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD)
+ || nodeName.equals(IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD)) {
+ return nodeName;
+ }
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)
- || !TsFileConstant.NODE_NAME_PATTERN.matcher(unWrapped).matches()) {
+ || !TsFileConstant.IDENTIFIER_PATTERN.matcher(unWrapped).matches()) {
return nodeName;
}
return unWrapped;
}
+ checkNodeName(nodeName);
return nodeName;
}
+ private void checkNodeName(String src) {
+ // node name could start with * and end with *
+ if (!TsFileConstant.NODE_NAME_PATTERN.matcher(src).matches()) {
+ throw new SQLParserException(
+ String.format(
+ "%s is illegal, unquoted node name can only consist of digits,
characters and underscore, or start or end with wildcard",
+ src));
+ }
+ }
+
+ private void checkIdentifier(String src) {
+ if (!TsFileConstant.IDENTIFIER_PATTERN.matcher(src).matches()) {
+ throw new SQLParserException(
+ String.format(
+ "%s is illegal, unquoted identifier can only consist of digits,
characters and underscore",
+ src));
+ }
+ }
+
// Literals
========================================================================
public long parseDateFormat(String timestampStr) throws SQLParserException {
@@ -1377,6 +1401,7 @@ public class ASTVisitor extends
IoTDBSqlParserBaseVisitor<Statement> {
return src.substring(1, src.length() - 1)
.replace(TsFileConstant.DOUBLE_BACK_QUOTE_STRING,
TsFileConstant.BACK_QUOTE_STRING);
}
+ checkIdentifier(src);
return src;
}
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 6c25ddd637..d6008497e5 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
@@ -195,6 +195,10 @@ public class IoTDBSqlVisitor extends
IoTDBSqlParserBaseVisitor<Operator> {
// for create-cq clause and select-into clause.
private static final Pattern leveledPathNodePattern =
Pattern.compile("\\$\\{\\w+}");
+ // ${} are allowed
+ private static final Pattern NODE_NAME_IN_SELECT_INTO_PATTERN =
+ Pattern.compile("([a-zA-Z0-9_${}\\u2E80-\\u9FFF]+)");
+
private ZoneId zoneId;
private QueryOperator queryOp;
@@ -1287,7 +1291,7 @@ public class IoTDBSqlVisitor extends
IoTDBSqlParserBaseVisitor<Operator> {
PartialPath intoPath = null;
if (intoPathContext.fullPath() != null) {
- intoPath = parseFullPath(intoPathContext.fullPath());
+ intoPath = parseFullPathInSelectInto(intoPathContext.fullPath());
Matcher m = leveledPathNodePattern.matcher(intoPath.getFullPath());
while (m.find()) {
@@ -1315,7 +1319,7 @@ public class IoTDBSqlVisitor extends
IoTDBSqlParserBaseVisitor<Operator> {
}
for (int i = 1; i <= nodeNameWithoutStars.size(); ++i) {
intoPathNodes[levelLimitOfSourcePrefixPath + i] =
- parseNodeNameWithoutWildCard(nodeNameWithoutStars.get(i - 1));
+
parseNodeNameWithoutWildCardInSelectInto(nodeNameWithoutStars.get(i - 1));
}
intoPath = new PartialPath(intoPathNodes);
@@ -2518,6 +2522,21 @@ public class IoTDBSqlVisitor extends
IoTDBSqlParserBaseVisitor<Operator> {
return new PartialPath(path);
}
+ private PartialPath parseFullPathInSelectInto(IoTDBSqlParser.FullPathContext
ctx) {
+ List<IoTDBSqlParser.NodeNameWithoutWildcardContext> nodeNamesWithoutStar =
+ ctx.nodeNameWithoutWildcard();
+ String[] path = new String[nodeNamesWithoutStar.size() + 1];
+ int i = 0;
+ if (ctx.ROOT() != null) {
+ path[0] = ctx.ROOT().getText();
+ }
+ for (IoTDBSqlParser.NodeNameWithoutWildcardContext nodeNameWithoutStar :
nodeNamesWithoutStar) {
+ i++;
+ path[i] = parseNodeNameWithoutWildCardInSelectInto(nodeNameWithoutStar);
+ }
+ return new PartialPath(path);
+ }
+
/** path of expression in withoutNull clause can start with root. */
private PartialPath parseFullPathInExpression(
IoTDBSqlParser.FullPathInExpressionContext ctx, boolean inWithoutNull)
@@ -2578,19 +2597,69 @@ public class IoTDBSqlVisitor extends
IoTDBSqlParserBaseVisitor<Operator> {
return parseNodeString(ctx.getText());
}
+ /** in select into, $ and {} are allowed */
+ private String parseNodeNameWithoutWildCardInSelectInto(
+ IoTDBSqlParser.NodeNameWithoutWildcardContext ctx) {
+ String nodeName = ctx.getText();
+ if (nodeName.equals(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD)
+ || nodeName.equals(IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD)) {
+ return nodeName;
+ }
+ 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)
+ || !TsFileConstant.IDENTIFIER_PATTERN.matcher(unWrapped).matches()) {
+ return nodeName;
+ }
+ return unWrapped;
+ }
+ if (!NODE_NAME_IN_SELECT_INTO_PATTERN.matcher(nodeName).matches()) {
+ throw new SQLParserException(
+ String.format(
+ "%s is illegal, unquoted node name in select into clause can
only consist of digits, characters, $, { and }",
+ nodeName));
+ }
+ return nodeName;
+ }
+
private String parseNodeString(String nodeName) {
+ if (nodeName.equals(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD)
+ || nodeName.equals(IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD)) {
+ return nodeName;
+ }
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)
- || !TsFileConstant.NODE_NAME_PATTERN.matcher(unWrapped).matches()) {
+ || !TsFileConstant.IDENTIFIER_PATTERN.matcher(unWrapped).matches()) {
return nodeName;
}
return unWrapped;
}
+ checkNodeName(nodeName);
return nodeName;
}
+ private void checkNodeName(String src) {
+ // node name could start with * and end with *
+ if (!TsFileConstant.NODE_NAME_PATTERN.matcher(src).matches()) {
+ throw new SQLParserException(
+ String.format(
+ "%s is illegal, unquoted node name can only consist of digits,
characters and underscore, or start or end with wildcard",
+ src));
+ }
+ }
+
+ private void checkIdentifier(String src) {
+ if (!TsFileConstant.IDENTIFIER_PATTERN.matcher(src).matches()) {
+ throw new SQLParserException(
+ String.format(
+ "%s is illegal, unquoted identifier can only consist of digits,
characters and underscore",
+ src));
+ }
+ }
+
// alias
/** function for parsing Alias. */
@@ -3189,6 +3258,7 @@ public class IoTDBSqlVisitor extends
IoTDBSqlParserBaseVisitor<Operator> {
return src.substring(1, src.length() - 1)
.replace(TsFileConstant.DOUBLE_BACK_QUOTE_STRING,
TsFileConstant.BACK_QUOTE_STRING);
}
+ checkIdentifier(src);
return src;
}
diff --git
a/tsfile/src/main/java/org/apache/iotdb/tsfile/common/constant/TsFileConstant.java
b/tsfile/src/main/java/org/apache/iotdb/tsfile/common/constant/TsFileConstant.java
index 9b496b9445..86ea19abcd 100644
---
a/tsfile/src/main/java/org/apache/iotdb/tsfile/common/constant/TsFileConstant.java
+++
b/tsfile/src/main/java/org/apache/iotdb/tsfile/common/constant/TsFileConstant.java
@@ -38,7 +38,10 @@ public class TsFileConstant {
public static final byte TIME_COLUMN_MASK = (byte) 0x80;
public static final byte VALUE_COLUMN_MASK = (byte) 0x40;
- private static final String NODE_NAME_MATCHER =
"([a-zA-Z0-9_:@#${}\\u2E80-\\u9FFF]+)";
+ private static final String IDENTIFIER_MATCHER =
"([a-zA-Z0-9_\\u2E80-\\u9FFF]+)";
+ public static final Pattern IDENTIFIER_PATTERN =
Pattern.compile(IDENTIFIER_MATCHER);
+
+ private static final String NODE_NAME_MATCHER =
"(\\*{0,2}[a-zA-Z0-9_\\u2E80-\\u9FFF]+\\*{0,2})";
public static final Pattern NODE_NAME_PATTERN =
Pattern.compile(NODE_NAME_MATCHER);
private TsFileConstant() {}
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 8ab23507a3..537fd5b9a1 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
@@ -65,7 +65,7 @@ public class PathVisitor extends
PathParserBaseVisitor<String[]> {
&& nodeName.endsWith(TsFileConstant.BACK_QUOTE_STRING)) {
String unWrapped = nodeName.substring(1, nodeName.length() - 1);
if (StringUtils.isNumeric(unWrapped)
- || !TsFileConstant.NODE_NAME_PATTERN.matcher(unWrapped).matches()) {
+ || !TsFileConstant.IDENTIFIER_PATTERN.matcher(unWrapped).matches()) {
return nodeName;
}
return unWrapped;