diff --git a/docs/en/12-taos-sql/06-select.md b/docs/en/12-taos-sql/06-select.md index 2d6c1469b6..e30e476ba4 100755 --- a/docs/en/12-taos-sql/06-select.md +++ b/docs/en/12-taos-sql/06-select.md @@ -459,7 +459,7 @@ SELECT ... FROM (SELECT ... FROM ...) ...; :::info - The result of a nested query is returned as a virtual table used by the outer query. It's recommended to give an alias to this table for the convenience of using it in the outer query. -- Outer queries support directly referencing columns or pseudo-columns of inner queries in the form of column names or `column names`. +- Outer queries support directly referencing columns or pseudo-columns of inner queries in the form of column names or \`column names\`. - JOIN operation is allowed between tables/STables inside both inner and outer queries. Join operation can be performed on the result set of the inner query. - The features that can be used in the inner query are the same as those that can be used in a non-nested query. - `ORDER BY` inside the inner query is unnecessary and will slow down the query performance significantly. It is best to avoid the use of `ORDER BY` inside the inner query. diff --git a/docs/en/12-taos-sql/18-escape.md b/docs/en/12-taos-sql/18-escape.md index 2d067b2ad9..a14591b0da 100644 --- a/docs/en/12-taos-sql/18-escape.md +++ b/docs/en/12-taos-sql/18-escape.md @@ -18,7 +18,7 @@ description: This document describes the usage of escape characters in TDengine. ## Restrictions -1. If there are escape characters in identifiers (database name, table name, column name) +1. If there are escape characters in identifiers (database name, table name, column name, alias Name) - Identifier without ``: Error will be returned because identifier must be constituted of digits, ASCII characters or underscore and can't be started with digits - Identifier quoted with ``: Original content is kept, no escaping 2. If there are escape characters in values diff --git a/docs/zh/12-taos-sql/06-select.md b/docs/zh/12-taos-sql/06-select.md index acf42a3b8f..f10c5ebb69 100755 --- a/docs/zh/12-taos-sql/06-select.md +++ b/docs/zh/12-taos-sql/06-select.md @@ -459,7 +459,7 @@ SELECT ... FROM (SELECT ... FROM ...) ...; :::info - 内层查询的返回结果将作为“虚拟表”供外层查询使用,此虚拟表建议起别名,以便于外层查询中方便引用。 -- 外层查询支持直接通过列名或`列名`的形式引用内层查询的列或伪列。 +- 外层查询支持直接通过列名或\`列名\`的形式引用内层查询的列或伪列。 - 在内层和外层查询中,都支持普通的表间/超级表间 JOIN。内层查询的计算结果也可以再参与数据子表的 JOIN 操作。 - 内层查询支持的功能特性与非嵌套的查询语句能力是一致的。 - 内层查询的 ORDER BY 子句一般没有意义,建议避免这样的写法以免无谓的资源消耗。 diff --git a/docs/zh/12-taos-sql/18-escape.md b/docs/zh/12-taos-sql/18-escape.md index 81e4179042..6bd20abf36 100644 --- a/docs/zh/12-taos-sql/18-escape.md +++ b/docs/zh/12-taos-sql/18-escape.md @@ -20,7 +20,7 @@ description: TDengine 中使用转义字符的详细规则 ## 转义字符使用规则 -1. 标识符里有转义字符(数据库名、表名、列名) +1. 标识符里有转义字符(数据库名、表名、列名、别名) 1. 普通标识符: 直接提示错误的标识符,因为标识符规定必须是数字、字母和下划线,并且不能以数字开头。 2. 反引号``标识符: 保持原样,不转义 2. 数据里有转义字符 diff --git a/source/libs/parser/inc/parAst.h b/source/libs/parser/inc/parAst.h index dc42245d93..579317a2fc 100644 --- a/source/libs/parser/inc/parAst.h +++ b/source/libs/parser/inc/parAst.h @@ -139,7 +139,7 @@ SNode* createCastFunctionNode(SAstCreateContext* pCxt, SNode* pExpr, SDataTy SNode* createNodeListNode(SAstCreateContext* pCxt, SNodeList* pList); SNode* createNodeListNodeEx(SAstCreateContext* pCxt, SNode* p1, SNode* p2); SNode* createRealTableNode(SAstCreateContext* pCxt, SToken* pDbName, SToken* pTableName, SToken* pTableAlias); -SNode* createTempTableNode(SAstCreateContext* pCxt, SNode* pSubquery, const SToken* pTableAlias); +SNode* createTempTableNode(SAstCreateContext* pCxt, SNode* pSubquery, SToken* pTableAlias); SNode* createJoinTableNode(SAstCreateContext* pCxt, EJoinType type, EJoinSubType stype, SNode* pLeft, SNode* pRight, SNode* pJoinCond); SNode* createViewNode(SAstCreateContext* pCxt, SToken* pDbName, SToken* pViewName); diff --git a/source/libs/parser/src/parAstCreater.c b/source/libs/parser/src/parAstCreater.c index 0497e7a0e2..7c2f504a4f 100644 --- a/source/libs/parser/src/parAstCreater.c +++ b/source/libs/parser/src/parAstCreater.c @@ -949,8 +949,11 @@ SNode* createRealTableNode(SAstCreateContext* pCxt, SToken* pDbName, SToken* pTa return (SNode*)realTable; } -SNode* createTempTableNode(SAstCreateContext* pCxt, SNode* pSubquery, const SToken* pTableAlias) { +SNode* createTempTableNode(SAstCreateContext* pCxt, SNode* pSubquery, SToken* pTableAlias) { CHECK_PARSER_STATUS(pCxt); + if (!checkTableName(pCxt, pTableAlias)) { + return NULL; + } STempTableNode* tempTable = (STempTableNode*)nodesMakeNode(QUERY_NODE_TEMP_TABLE); CHECK_OUT_OF_MEM(tempTable); tempTable->pSubquery = pSubquery; diff --git a/tests/system-test/0-others/backquote_check.py b/tests/system-test/0-others/backquote_check.py index 7c91fd9e8c..d5b5d2ef1a 100644 --- a/tests/system-test/0-others/backquote_check.py +++ b/tests/system-test/0-others/backquote_check.py @@ -26,6 +26,8 @@ class TDTestCase: self.dbname = 'db' self.setsql = TDSetSql() self.stbname = 'stb' + self.ntbname1 = 'ntb1' + self.ntbname2 = 'ntb2' self.streamname = 'stm' self.streamtb = 'stm_stb' def topic_name_check(self): @@ -74,11 +76,33 @@ class TDTestCase: tdSql.checkEqual(tdSql.queryResult[0][0],self.streamname) tdSql.execute(f'drop stream `{self.streamname}`') tdSql.execute(f'drop database {self.dbname}') - + + def table_name_check(self): + tdSql.execute(f'create database if not exists {self.dbname} wal_retention_period 3600') + tdSql.execute(f'use {self.dbname}') + tdSql.execute(f'create table {self.ntbname1} (ts timestamp,c0 int,c1 int)') + tdSql.execute(f'create table {self.ntbname2} (ts timestamp,c0 int,c1 int)') + tdSql.execute(f'insert into {self.ntbname1} values(now(),1,1)') + tdSql.execute(f'insert into {self.ntbname2} values(now(),2,2)') + tdSql.query(f'select `{self.ntbname1}`.`c0`, `{self.ntbname1}`.`c1` from `{self.ntbname1}`') + tdSql.checkEqual(tdSql.queryResult[0][0], 1) + tdSql.query(f'select `{self.ntbname1}`.`c0`, `{self.ntbname1}`.`c1` from `{self.dbname}`.`{self.ntbname1}`') + tdSql.checkEqual(tdSql.queryResult[0][0], 1) + tdSql.query(f'select `{self.ntbname1}`.`c0` from `{self.ntbname2}` `{self.ntbname1}`') + tdSql.checkEqual(tdSql.queryResult[0][0], 2) + tdSql.query(f'select `{self.ntbname1}`.`c0` from (select * from `{self.ntbname2}`) `{self.ntbname1}`') + tdSql.checkEqual(tdSql.queryResult[0][0], 2) + # select `t1`.`col1`, `col2`, `col3` from (select ts `col1`, 123 `col2`, c0 + c1 as `col3` from t2) `t1`; + tdSql.query(f'select `{self.ntbname1}`.`col1`, `col2`, `col3` from (select ts `col1`, 123 `col2`, c0 + c1 as `col3` from {self.ntbname2}) `{self.ntbname1}`') + tdSql.checkEqual(tdSql.queryResult[0][1], 123) + tdSql.checkEqual(tdSql.queryResult[0][2], 4) + + tdSql.execute(f'drop database {self.dbname}') def run(self): self.topic_name_check() self.db_name_check() self.stream_name_check() + self.table_name_check() def stop(self): tdSql.close() tdLog.success("%s successfully executed" % __file__)