diff --git a/docs/en/06-advanced/03-stream.md b/docs/en/06-advanced/03-stream.md index f37742367864..2fb1d2478509 100644 --- a/docs/en/06-advanced/03-stream.md +++ b/docs/en/06-advanced/03-stream.md @@ -22,7 +22,7 @@ For detailed usage instructions, see [SQL Manual](../14-reference/03-taos-sql/41 ## Create a Stream ```sql -CREATE STREAM [IF NOT EXISTS] [db_name.]stream_name options [INTO [db_name.]table_name] [OUTPUT_SUBTABLE(tbname_expr)] [(column_name1, column_name2 [COMPOSITE KEY][, ...])] [TAGS (tag_definition [, ...])] [AS subquery] +CREATE STREAM [IF NOT EXISTS] [db_name.]stream_name options [INTO [db_name.]table_name] [NODELAY_CREATE_SUBTABLE] [OUTPUT_SUBTABLE(tbname_expr)] [(column_name1, column_name2 [COMPOSITE KEY][, ...])] [TAGS (tag_definition [, ...])] [AS subquery] options: { trigger_type [FROM [db_name.]table_name] [PARTITION BY col1 [, ...]] [STREAM_OPTIONS(stream_option [|...])] [notification_definition] diff --git a/docs/en/14-reference/03-taos-sql/41-stream.md b/docs/en/14-reference/03-taos-sql/41-stream.md index 35d5f2ac4a74..b7f08761eb80 100755 --- a/docs/en/14-reference/03-taos-sql/41-stream.md +++ b/docs/en/14-reference/03-taos-sql/41-stream.md @@ -19,7 +19,7 @@ TDengine TSDB’s stream processing engine also offers additional usability bene ## Create a Stream ```sql -CREATE STREAM [IF NOT EXISTS] [db_name.]stream_name options [INTO [db_name.]table_name] [OUTPUT_SUBTABLE(tbname_expr)] [(column_name1, column_name2 [COMPOSITE KEY][, ...])] [TAGS (tag_definition [, ...])] [AS subquery] +CREATE STREAM [IF NOT EXISTS] [db_name.]stream_name options [INTO [db_name.]table_name] [NODELAY_CREATE_SUBTABLE] [OUTPUT_SUBTABLE(tbname_expr)] [(column_name1, column_name2 [COMPOSITE KEY][, ...])] [TAGS (tag_definition [, ...])] [AS subquery] options: { trigger_type [FROM [db_name.]table_name] [PARTITION BY col1 [, ...]] [STREAM_OPTIONS(stream_option [|...])] [notification_definition] @@ -300,7 +300,7 @@ Specifies the columns used for trigger grouping. Multiple columns are supported, By default, the results of a stream are stored in an output table. Each output table contains only the results that have been triggered and computed up to the current time. You can define the structure of the output table, and if grouping is used, you can also specify the tag values for each subtable. ```sql -[INTO [db_name.]table_name] [OUTPUT_SUBTABLE(tbname_expr)] [(column_name1, column_name2 [COMPOSITE KEY][, ...])] [TAGS (tag_definition [, ...])] +[INTO [db_name.]table_name] [NODELAY_CREATE_SUBTABLE] [OUTPUT_SUBTABLE(tbname_expr)] [(column_name1, column_name2 [COMPOSITE KEY][, ...])] [TAGS (tag_definition [, ...])] tag_definition: tag_name type_name [COMMENT 'string_value'] AS expr @@ -312,6 +312,7 @@ Details are as follows: - If trigger grouping is used, this table will be a supertable. - If no trigger grouping is used, this table will be a regular table. - If the trigger only sends notifications without computation, or if computation results are only sent as notifications without being stored, this option does not need to be specified. +- `[NODELAY_CREATE_SUBTABLE]`: Optional. Specifies that the calculation output subtables for each group are created immediately when the stream is created. By default, output subtables are created only when the first calculated data is written. If this option is added, subtables are created asynchronously after the stream is created. If not all subtables are created successfully, the stream status remains `Idle`; if creation succeeds, the status changes to `Running`. For regular tables and supertables as output tables, they are created automatically when the stream is created by default, and no configuration is needed. - `[OUTPUT_SUBTABLE(tbname_expr)]`: Optional. Specifies the name of the calculation output table (subtable) for each trigger group. This cannot be specified if there is no trigger grouping. If not specified, a unique output table (subtable) name will be automatically generated for each group. tbname_expr can be any output string expression, and may include trigger group partition columns (from [PARTITION BY col1[, ...]]). The output length must not exceed the maximum table name length; if it does, it will be truncated. If you do not want different groups to output to the same subtable, you must ensure each group's output table name is unique. - `[(column_name1, column_name2 [COMPOSITE KEY][, ...])]`: Optional. Specifies the column names for each column in the output table. If not specified, each column name will be the same as the corresponding column name in the calculation result. You can use [COMPOSITE KEY] to indicate that the second column is a primary key column, forming a composite primary key together with the first column. - `[TAGS (tag_definition [, ...])]`: Optional. Specifies the list of tag column definitions and values for the output supertable. This can only be specified if trigger grouping is present. If not specified, the tag column definitions and values are derived from all grouping columns, and in this case, grouping columns cannot have duplicate names. When grouping by subtable, the default generated tag column name is tag_tbname, with the type VARCHAR(270). The tag_definition parameters are as follows: diff --git a/docs/en/14-reference/03-taos-sql/92-keywords.md b/docs/en/14-reference/03-taos-sql/92-keywords.md index f03fc2ad169a..4d8094678eec 100644 --- a/docs/en/14-reference/03-taos-sql/92-keywords.md +++ b/docs/en/14-reference/03-taos-sql/92-keywords.md @@ -332,6 +332,7 @@ The list of keywords is as follows: | NE | | | NEXT | | | NMATCH | | +| NODELAY_CREATE_SUBTABLE | 3.5.0.0+ | | NONE | | | NORMAL | | | NOT | | diff --git a/docs/stream_create_deploy_sequence.md b/docs/stream_create_deploy_sequence.md new file mode 100644 index 000000000000..d78f75740feb --- /dev/null +++ b/docs/stream_create_deploy_sequence.md @@ -0,0 +1,71 @@ +# 建流与部署时序:正常 vs 异常 + +## 1. 正常情况(流先落 SDB,再被部署) + +```mermaid +sequenceDiagram + participant Client + participant MND as Mnode(trans) + participant SDB as SDB + participant MSTM as Mnode(StreamMgmt) + participant Snode + + Client->>MND: create stream 请求 + MND->>MND: trans 创建 (prepare) + MND->>MND: redoAction: vnode-create-stb (x6) + Note over MND: 所有 redoAction 完成 + MND->>MND: stage → commit, propose(seq:40) + MND->>MND: 其他节点 apply commit + MND->>SDB: commitAction:0 (stb) + MND->>SDB: commitAction:1 (stream 写入) + Note over MND,SDB: 流已持久化到 SDB + MND->>MSTM: (建流事务 commit 完成后) post DEPLOY 入队 + MND->>Client: create-stream-rsp + + Snode->>MSTM: stream 心跳 + MSTM->>MSTM: 处理 deploy action + MSTM->>SDB: mndAcquireStream(streamName) + SDB-->>MSTM: 返回 stream 对象 (存在) + MSTM->>MSTM: msmDeployStreamTasks() + MSTM->>Snode: 部署 / 调度 +``` + +**要点**:DEPLOY 入队发生在 **commitAction 执行之后**(即 stream 已写入 SDB 之后),心跳处理 deploy 时 `mndAcquireStream` 能查到流。 + +--- + +## 2. 本次异常情况(DEPLOY 先入队,流尚未落 SDB) + +```mermaid +sequenceDiagram + participant Client + participant MND as Mnode(trans) + participant SDB as SDB + participant MSTM as Mnode(StreamMgmt) + participant Snode + + Client->>MND: create stream 请求 + MND->>MND: trans 创建 (prepare), propose(seq:39) + MND->>MND: redoAction: vnode-create-stb (x6) + Note over MND: 部分/全部 redoAction 完成 + MND->>MSTM: "half completed" 时 post DEPLOY 入队 + Note over MND,MSTM: 此时 stream 尚未写入 SDB + MND->>MND: redoAction 全部完成 → stage commit + MND->>MND: propose(seq:40),等待 apply + + Snode->>MSTM: stream 心跳 (约 230ms 后) + MSTM->>MSTM: 处理 deploy action + MSTM->>SDB: mndAcquireStream(streamName) + SDB-->>MSTM: NULL (stream 不存在) + MSTM->>MSTM: "stream no longer exists, ignore deploy" + MSTM->>Snode: 心跳响应 (未部署) + + Note over MND: 约 110ms 后 + MND->>MND: process sync proposal, apply index:40 + MND->>SDB: commitAction:0 (stb) + MND->>SDB: commitAction:1 (stream 写入) + Note over MND,SDB: 流此时才落库,但 deploy 已被忽略 + MND->>Client: create-stream-rsp +``` + +**要点**:DEPLOY 在 **redoAction 阶段 / half completed** 就入队,而 stream 要等到 **commit 被 apply 后** 才写入 SDB。心跳先于 commit 处理了 deploy,此时 SDB 里还没有该流,于是 “no longer exists, ignore deploy”,导致该流本次不会再被部署。 diff --git a/docs/zh/06-advanced/03-stream.md b/docs/zh/06-advanced/03-stream.md index 6d3bae736818..bc5a26401cd1 100644 --- a/docs/zh/06-advanced/03-stream.md +++ b/docs/zh/06-advanced/03-stream.md @@ -23,7 +23,7 @@ TDengine TSDB 的流计算引擎还提供了其他使用上的便利。针对结 ## 流式计算的创建 ```sql -CREATE STREAM [IF NOT EXISTS] [db_name.]stream_name options [INTO [db_name.]table_name] [OUTPUT_SUBTABLE(tbname_expr)] [(column_name1, column_name2 [COMPOSITE KEY][, ...])] [TAGS (tag_definition [, ...])] [AS subquery] +CREATE STREAM [IF NOT EXISTS] [db_name.]stream_name options [INTO [db_name.]table_name] [NODELAY_CREATE_SUBTABLE] [OUTPUT_SUBTABLE(tbname_expr)] [(column_name1, column_name2 [COMPOSITE KEY][, ...])] [TAGS (tag_definition [, ...])] [AS subquery] options: { trigger_type [FROM [db_name.]table_name] [PARTITION BY col1 [, ...]] [STREAM_OPTIONS(stream_option [|...])] [notification_definition] diff --git a/docs/zh/14-reference/03-taos-sql/41-stream.md b/docs/zh/14-reference/03-taos-sql/41-stream.md index d3fed59bcec3..420661d4d75a 100755 --- a/docs/zh/14-reference/03-taos-sql/41-stream.md +++ b/docs/zh/14-reference/03-taos-sql/41-stream.md @@ -18,7 +18,7 @@ TDengine TSDB 的流计算引擎还提供了其他使用上的便利。针对结 ## 创建流式计算 ```sql -CREATE STREAM [IF NOT EXISTS] [db_name.]stream_name options [INTO [db_name.]table_name] [OUTPUT_SUBTABLE(tbname_expr)] [(column_name1, column_name2 [COMPOSITE KEY][, ...])] [TAGS (tag_definition [, ...])] [AS subquery] +CREATE STREAM [IF NOT EXISTS] [db_name.]stream_name options [INTO [db_name.]table_name] [NODELAY_CREATE_SUBTABLE] [OUTPUT_SUBTABLE(tbname_expr)] [(column_name1, column_name2 [COMPOSITE KEY][, ...])] [TAGS (tag_definition [, ...])] [AS subquery] options: { trigger_type [FROM [db_name.]table_name] [PARTITION BY col1 [, ...]] [STREAM_OPTIONS(stream_option [|...])] [notification_definition] @@ -299,7 +299,7 @@ COUNT_WINDOW(count_val[, sliding_val][, col1[, ...]]) 流计算的计算结果默认会保存到输出表中,每个输出表中的计算结果是截至当前时刻已经触发和计算完成的输出。可以指定输出表的结构定义,如果存在分组还可以指定子表的标签值。 ```sql -[INTO [db_name.]table_name] [OUTPUT_SUBTABLE(tbname_expr)] [(column_name1, column_name2 [COMPOSITE KEY][, ...])] [TAGS (tag_definition [, ...])] +[INTO [db_name.]table_name] [NODELAY_CREATE_SUBTABLE] [OUTPUT_SUBTABLE(tbname_expr)] [(column_name1, column_name2 [COMPOSITE KEY][, ...])] [TAGS (tag_definition [, ...])] tag_definition: tag_name type_name [COMMENT 'string_value'] AS expr @@ -311,6 +311,7 @@ tag_definition: - 存在触发分组时该表为超级表。 - 不存在触发分组时该表为普通表。 - 只触发通知不计算,或计算结果只通知不保存时,不需要指定。 +- [NODELAY_CREATE_SUBTABLE]:可选,指定在建流的时候立即创建每个分组的计算输出子表,默认情况下计算输出子表在有一条计算数据写入时才创建。如果添加该选项,创建流之后,子表会异步的创建,如果未全部创建成功,则流的状态会是 `Idle` ;如果创建成功,则状态会变更为 `Running` 。输出表为普通表和超级表默认会在建流的时候自动建立,无需进行配置。 - [OUTPUT_SUBTABLE(tbname_expr)]:可选,指定每个触发分组的计算输出表(子表)名,没有触发分组时不可以指定。未指定时自动为每个分组生成唯一的输出表(子表)名。`tbname_expr` 为任意输出字符串的表达式,可根据需要选择触发表分组列(来自 `[PARTITION BY col1[, ...]]`),输出长度不能超过表名最大长度,超过时截断处理。如果不希望不同分组输出到同一子表中,用户需确保每个分组输出表名都是唯一的。 - [(column_name1, column_name2 [COMPOSITE KEY][, ...])]:可选,指定输出表的每列列名,未指定时每列列名与计算结果的每列列名相同。可以通过 `[COMPOSITE KEY]` 指定第二列为主键列,与第一列共同组成复合主键。 - [TAGS (tag_definition [, ...])]:可选,指定输出超级表的标签列定义与值的列表,只有存在触发分组时才可以指定。未指定时,标签列的定义和值来自于所有分组列,此时分组列中不可以存在相同的列名。当按子表分组时,默认产生的标签列名为 `tag_tbname`,类型为 `VARCHAR(270)`。具体的 `tag_definition` 参数说明如下: diff --git a/docs/zh/14-reference/03-taos-sql/92-keywords.md b/docs/zh/14-reference/03-taos-sql/92-keywords.md index ea2363ea7594..f0fcccba52d0 100644 --- a/docs/zh/14-reference/03-taos-sql/92-keywords.md +++ b/docs/zh/14-reference/03-taos-sql/92-keywords.md @@ -333,6 +333,7 @@ description: TDengine TSDB 保留关键字的详细列表 | NE | | | NEXT | | | NMATCH | | +| NODELAY_CREATE_SUBTABLE | 3.5.0.0+ | | NONE | | | NORMAL | | | NOT | | diff --git a/include/common/streamMsg.h b/include/common/streamMsg.h index 9f2e0aca6f9e..dbbc6ef93a8f 100644 --- a/include/common/streamMsg.h +++ b/include/common/streamMsg.h @@ -227,6 +227,7 @@ typedef struct { SArray* forceOutCols; // array of SStreamOutCol, only available when forceOutput is true SArray* colCids; // array of SStreamCidCol, only available when colCids is not empty SArray* tagCids; // array of SStreamCidTag, only available when tagCids is not empty + int8_t nodelayCreateSubtable; // 1 = create sub-tables at stream create time; 0 = default } SCMCreateStreamReq; typedef enum SStreamMsgType { @@ -507,7 +508,8 @@ typedef struct { SArray* runnerList; // SArray int32_t leaderSnodeId; - char* streamName; + char* streamName; + int8_t nodelayCreateSubtable; // 1 = create sub-tables at stream create time; 0 = create on the fly during trigger } SStreamTriggerDeployMsg; typedef struct SStreamRunnerDeployMsg { diff --git a/include/libs/nodes/cmdnodes.h b/include/libs/nodes/cmdnodes.h index 91ec43740230..52cd43bab00b 100644 --- a/include/libs/nodes/cmdnodes.h +++ b/include/libs/nodes/cmdnodes.h @@ -1070,6 +1070,7 @@ typedef struct SCreateStreamStmt { SNode* pSubtable; SNodeList* pTags; // SStreamTagDefNode SNodeList* pCols; // SColumnDefNode + int8_t nodelayCreateSubtable; // 1 = create sub-tables at stream create; 0 = default } SCreateStreamStmt; typedef struct SDropStreamStmt { diff --git a/include/libs/nodes/querynodes.h b/include/libs/nodes/querynodes.h index e54ce4aa6ef0..06dafa10c49c 100644 --- a/include/libs/nodes/querynodes.h +++ b/include/libs/nodes/querynodes.h @@ -540,6 +540,7 @@ typedef struct SStreamOutTableNode { SNode* pSubtable; SNodeList* pTags; // SStreamTagDefNode SNodeList* pCols; // SColumnDefNode + int8_t nodelayCreateSubtable; // 1 = create sub-tables at stream create time; 0 = default, do not } SStreamOutTableNode; typedef struct SStreamCalcRangeNode { diff --git a/source/common/src/msg/streamJson.c b/source/common/src/msg/streamJson.c index 008f25cc0c57..b22385fc559d 100644 --- a/source/common/src/msg/streamJson.c +++ b/source/common/src/msg/streamJson.c @@ -474,6 +474,7 @@ static const char* jkCreateStreamReqForceOutCols = "forceOutCols"; static const char* jkCreateStreamReqColCids = "colCids"; static const char* jkCreateStreamReqTagCids = "tagCids"; +static const char* jkCreateStreamReqNodelayCreateSubtable = "nodelayCreateSubtable"; static int32_t scmCreateStreamReqToJsonImpl(const void* pObj, void* pJson) { const SCMCreateStreamReq* pReq = (const SCMCreateStreamReq*)pObj; @@ -706,6 +707,8 @@ static int32_t scmCreateStreamReqToJsonImpl(const void* pObj, void* pJson) { pReq->tagCids ? TARRAY_GET_ELEM(pReq->tagCids, 0) : NULL, pReq->tagCids ? pReq->tagCids->elemSize : 0, pReq->tagCids ? pReq->tagCids->size : 0)); + TAOS_CHECK_RETURN( + tjsonAddIntegerToObject(pJson, jkCreateStreamReqNodelayCreateSubtable, pReq->nodelayCreateSubtable)); return TSDB_CODE_SUCCESS; } @@ -926,6 +929,7 @@ int32_t jsonToSCMCreateStreamReq(const void* pJson, void* pObj) { jsonToSStreamOutCol, &pReq->forceOutCols, sizeof(SStreamOutCol))); TAOS_CHECK_RETURN(tjsonToTArray(pJson, jkCreateStreamReqColCids, jsonToInt16, &pReq->colCids, sizeof(int16_t))); TAOS_CHECK_RETURN(tjsonToTArray(pJson, jkCreateStreamReqTagCids, jsonToInt16, &pReq->tagCids, sizeof(int16_t))); + (void)tjsonGetTinyIntValue(pJson, jkCreateStreamReqNodelayCreateSubtable, &pReq->nodelayCreateSubtable); return TSDB_CODE_SUCCESS; } diff --git a/source/common/src/msg/streamMsg.c b/source/common/src/msg/streamMsg.c index ffc9b3ec22aa..0250b8de259a 100644 --- a/source/common/src/msg/streamMsg.c +++ b/source/common/src/msg/streamMsg.c @@ -720,6 +720,7 @@ int32_t tEncodeSStreamTriggerDeployMsg(SEncoder* pEncoder, const SStreamTriggerD TAOS_CHECK_EXIT(tEncodeI32(pEncoder, pMsg->leaderSnodeId)); TAOS_CHECK_EXIT(tEncodeBinary(pEncoder, pMsg->streamName, (int32_t)strlen(pMsg->streamName) + 1)); TAOS_CHECK_EXIT(tEncodeI8(pEncoder, pMsg->precision)); + TAOS_CHECK_EXIT(tEncodeI8(pEncoder, pMsg->nodelayCreateSubtable)); _exit: @@ -1298,6 +1299,9 @@ int32_t tDecodeSStreamTriggerDeployMsg(SDecoder* pDecoder, SStreamTriggerDeployM if (!tDecodeIsEnd(pDecoder)) { TAOS_CHECK_EXIT(tDecodeI8(pDecoder, &pMsg->precision)); } + if (!tDecodeIsEnd(pDecoder)) { + TAOS_CHECK_EXIT(tDecodeI8(pDecoder, &pMsg->nodelayCreateSubtable)); + } _exit: diff --git a/source/dnode/mgmt/mgmt_mnode/src/mmHandle.c b/source/dnode/mgmt/mgmt_mnode/src/mmHandle.c index 8a803aac25e8..ad1f730b1a16 100644 --- a/source/dnode/mgmt/mgmt_mnode/src/mmHandle.c +++ b/source/dnode/mgmt/mgmt_mnode/src/mmHandle.c @@ -240,6 +240,7 @@ SArray *mmGetMsgHandles() { if (dmSetMgmtHandle(pArray, TDMT_MND_DROP_TB_WITH_TSMA, mmPutMsgToWriteQueue, 0) == NULL) goto _OVER; if (dmSetMgmtHandle(pArray, TDMT_VND_FETCH_TTL_EXPIRED_TBS_RSP, mmPutMsgToWriteQueue, 0) == NULL) goto _OVER; if (dmSetMgmtHandle(pArray, TDMT_VND_DROP_TABLE_RSP, mmPutMsgToWriteQueue, 0) == NULL) goto _OVER; + if (dmSetMgmtHandle(pArray, TDMT_VND_CREATE_TABLE_RSP, mmPutMsgToWriteQueue, 0) == NULL) goto _OVER; if (dmSetMgmtHandle(pArray, TDMT_MND_GET_DB_INFO, mmPutMsgToReadQueue, 0) == NULL) goto _OVER; if (dmSetMgmtHandle(pArray, TDMT_MND_CREATE_MOUNT, mmPutMsgToReadQueue, 0) == NULL) goto _OVER; if (dmSetMgmtHandle(pArray, TDMT_MND_DROP_MOUNT, mmPutMsgToWriteQueue, 0) == NULL) goto _OVER; diff --git a/source/dnode/mnode/impl/src/mndStb.c b/source/dnode/mnode/impl/src/mndStb.c index a948ecde3dd6..1896dab85218 100644 --- a/source/dnode/mnode/impl/src/mndStb.c +++ b/source/dnode/mnode/impl/src/mndStb.c @@ -98,6 +98,8 @@ int32_t mndInitStb(SMnode *pMnode) { mndSetMsgHandle(pMnode, TDMT_MND_DROP_TB_WITH_TSMA, mndProcessDropTbWithTsma); mndSetMsgHandle(pMnode, TDMT_VND_FETCH_TTL_EXPIRED_TBS_RSP, mndProcessFetchTtlExpiredTbs); mndSetMsgHandle(pMnode, TDMT_VND_DROP_TABLE_RSP, mndTransProcessRsp); + mndSetMsgHandle(pMnode, TDMT_VND_CREATE_TABLE_RSP, mndTransProcessRsp); + // mndSetMsgHandle(pMnode, TDMT_MND_SYSTABLE_RETRIEVE, mndProcessRetrieveStbReq); // mndSetMsgHandle(pMnode, TDMT_MND_CREATE_INDEX, mndProcessCreateIndexReq); diff --git a/source/dnode/mnode/impl/src/mndStream.c b/source/dnode/mnode/impl/src/mndStream.c index 9a6508162d6c..15361e6abe20 100644 --- a/source/dnode/mnode/impl/src/mndStream.c +++ b/source/dnode/mnode/impl/src/mndStream.c @@ -21,6 +21,7 @@ #include "mndStb.h" #include "mndTrans.h" #include "mndUser.h" +#include "mndVgroup.h" #include "osMemory.h" #include "parser.h" #include "taoserror.h" @@ -33,8 +34,8 @@ typedef struct { int8_t placeHolder; // // to fix windows compile error, define place holder } SMStreamNodeCheckMsg; -static int32_t mndNodeCheckSentinel = 0; -SStmRuntime mStreamMgmt = {0}; +static int32_t mndNodeCheckSentinel = 0; +SStmRuntime mStreamMgmt = {0}; static int32_t mndStreamActionInsert(SSdb *pSdb, SStreamObj *pStream); static int32_t mndStreamActionDelete(SSdb *pSdb, SStreamObj *pStream); @@ -62,9 +63,9 @@ static int32_t mndProcessCreateStreamReq(SRpcMsg *pReq); void mndCleanupStream(SMnode *pMnode) { mDebug("try to clean up stream"); - + msmHandleBecomeNotLeader(pMnode); - + mDebug("mnd stream runtime info cleanup"); } @@ -144,7 +145,7 @@ static int32_t mndStreamActionUpdate(SSdb *pSdb, SStreamObj *pOldStream, SStream atomic_store_8(&pOldStream->userStopped, atomic_load_8(&pNewStream->userStopped)); pOldStream->ownerId = pNewStream->ownerId; pOldStream->updateTime = pNewStream->updateTime; - + return 0; } @@ -159,10 +160,10 @@ int32_t mndAcquireStream(SMnode *pMnode, char *streamName, SStreamObj **pStream) } static bool mndStreamGetNameFromId(SMnode *pMnode, void *pObj, void *p1, void *p2, void *p3) { - SStreamObj* pStream = pObj; + SStreamObj *pStream = pObj; - if (pStream->pCreate->streamId == *(int64_t*)p1) { - strncpy((char*)p2, pStream->name, TSDB_STREAM_NAME_LEN); + if (pStream->pCreate->streamId == *(int64_t *)p1) { + strncpy((char *)p2, pStream->name, TSDB_STREAM_NAME_LEN); return false; } @@ -172,9 +173,9 @@ static bool mndStreamGetNameFromId(SMnode *pMnode, void *pObj, void *p1, void *p int32_t mndAcquireStreamById(SMnode *pMnode, int64_t streamId, SStreamObj **pStream) { int32_t code = 0; SSdb *pSdb = pMnode->pSdb; - char streamName[TSDB_STREAM_NAME_LEN]; + char streamName[TSDB_STREAM_NAME_LEN]; streamName[0] = 0; - + sdbTraverse(pSdb, SDB_STREAM, mndStreamGetNameFromId, &streamId, streamName, NULL); if (streamName[0]) { (*pStream) = sdbAcquire(pSdb, SDB_STREAM, streamName); @@ -182,7 +183,7 @@ int32_t mndAcquireStreamById(SMnode *pMnode, int64_t streamId, SStreamObj **pStr code = TSDB_CODE_MND_STREAM_NOT_EXIST; } } - + return code; } @@ -216,7 +217,8 @@ static void mndStreamBuildObj(SMnode *pMnode, SStreamObj *pObj, SCMCreateStreamR mstLogSStreamObj("create stream", pObj); } -static int32_t mndStreamCreateOutStb(SMnode *pMnode, STrans *pTrans, const SCMCreateStreamReq *pStream, const char *user) { +static int32_t mndStreamCreateOutStb(SMnode *pMnode, STrans *pTrans, const SCMCreateStreamReq *pStream, + const char *user) { SStbObj *pStb = NULL; SDbObj *pDb = NULL; int32_t code = 0; @@ -225,7 +227,7 @@ static int32_t mndStreamCreateOutStb(SMnode *pMnode, STrans *pTrans, const SCMCr SMCreateStbReq createReq = {0}; TAOS_STRNCAT(createReq.name, pStream->outDB, TSDB_DB_FNAME_LEN); TAOS_STRNCAT(createReq.name, ".", 2); - TAOS_STRNCAT(createReq.name, pStream->outTblName, TSDB_TABLE_NAME_LEN); + TAOS_STRNCAT(createReq.name, pStream->outTblName, TSDB_TABLE_NAME_LEN); createReq.numOfColumns = taosArrayGetSize(pStream->outCols); createReq.numOfTags = pStream->outTags ? taosArrayGetSize(pStream->outTags) : 1; createReq.pColumns = taosArrayInit_s(sizeof(SFieldWithOptions), createReq.numOfColumns); @@ -337,7 +339,265 @@ static int32_t mndStreamCreateOutStb(SMnode *pMnode, STrans *pTrans, const SCMCr return code; } -static int32_t mndStreamValidateCreate(SMnode *pMnode, SRpcMsg *pReq, SCMCreateStreamReq* pCreate) { +static int32_t mndStreamCreateOutTable(SMnode *pMnode, STrans *pTrans, const SCMCreateStreamReq *pStream) { + int32_t code = 0; + int32_t lino = 0; + SVgObj *pVgroup = NULL; + SDbObj *pDb = NULL; + SName name = {0}; + char dbFName[TSDB_DB_FNAME_LEN] = {0}; + + // Parse database and table name + if ((code = tNameFromString(&name, pStream->outDB, T_NAME_ACCT | T_NAME_DB)) != 0) { + mError("stream:%s failed to parse outDB:%s, code:%s", pStream->name, pStream->outDB, tstrerror(code)); + return code; + } + if ((code = tNameGetFullDbName(&name, dbFName)) != 0) { + mError("stream:%s failed to get full db name, code:%s", pStream->name, tstrerror(code)); + return code; + } + + // Get database object + pDb = mndAcquireDb(pMnode, dbFName); + if (pDb == NULL) { + code = TSDB_CODE_MND_DB_NOT_SELECTED; + mError("stream:%s failed to acquire db:%s, code:%s", pStream->name, dbFName, tstrerror(code)); + return code; + } + + // Set transaction db name and check conflict (similar to mndAddStbToTrans) + mndTransSetDbName(pTrans, pDb->name, pStream->outTblName); + code = mndTransCheckConflict(pMnode, pTrans); + if (code != TSDB_CODE_SUCCESS) { + mError("stream:%s failed to check conflict, code:%s", pStream->name, tstrerror(code)); + goto _OVER; + } + + // Get vgroup by vgId + if (pStream->outTblVgId <= 0) { + mError("stream:%s invalid outTblVgId:%d", pStream->name, pStream->outTblVgId); + code = TSDB_CODE_MND_VGROUP_NOT_EXIST; + goto _OVER; + } + + pVgroup = mndAcquireVgroup(pMnode, pStream->outTblVgId); + if (pVgroup == NULL) { + code = TSDB_CODE_MND_VGROUP_NOT_EXIST; + mError("stream:%s failed to acquire vgroup:%d, code:%s", pStream->name, pStream->outTblVgId, tstrerror(code)); + goto _OVER; + } + + // Verify vgroup belongs to the database + if (pVgroup->dbUid != pDb->uid) { + code = TSDB_CODE_MND_VGROUP_NOT_EXIST; + mError("stream:%s vgroup:%d does not belong to db:%s", pStream->name, pStream->outTblVgId, dbFName); + goto _OVER; + } + + // Build SVCreateTbReq (reusing logic from buildNormalTableCreateReq) + SVCreateTbReq createReq = {0}; + createReq.type = TSDB_NORMAL_TABLE; + createReq.flags = TD_CREATE_NORMAL_TB_IN_STREAM | TD_CREATE_IF_NOT_EXISTS; + createReq.uid = mndGenerateUid(pStream->outTblName, strlen(pStream->outTblName)); + createReq.btime = taosGetTimestampMs(); + createReq.ttl = TSDB_DEFAULT_TABLE_TTL; + createReq.commentLen = -1; + createReq.name = taosStrdup(pStream->outTblName); + if (createReq.name == NULL) { + code = terrno; + goto _OVER; + } + + // Build schema from outCols (same logic as buildNormalTableCreateReq) + int32_t numOfCols = taosArrayGetSize(pStream->outCols); + createReq.ntb.schemaRow.nCols = numOfCols; + createReq.ntb.schemaRow.version = 1; + createReq.ntb.schemaRow.pSchema = taosMemoryCalloc(numOfCols, sizeof(SSchema)); + if (createReq.ntb.schemaRow.pSchema == NULL) { + code = terrno; + goto _OVER; + } + + for (int32_t i = 0; i < numOfCols; i++) { + SFieldWithOptions *pField = taosArrayGet(pStream->outCols, i); + if (pField == NULL) { + code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR; + goto _OVER; + } + + createReq.ntb.schemaRow.pSchema[i].colId = i + 1; + createReq.ntb.schemaRow.pSchema[i].type = pField->type; + createReq.ntb.schemaRow.pSchema[i].bytes = pField->bytes; + createReq.ntb.schemaRow.pSchema[i].flags = pField->flags; + tstrncpy(createReq.ntb.schemaRow.pSchema[i].name, pField->name, TSDB_COL_NAME_LEN); + + if (IS_DECIMAL_TYPE(pField->type)) { + if (createReq.pExtSchemas == NULL) { + createReq.pExtSchemas = taosMemoryCalloc(numOfCols, sizeof(SExtSchema)); + if (createReq.pExtSchemas == NULL) { + code = terrno; + goto _OVER; + } + } + createReq.pExtSchemas[i].typeMod = pField->typeMod; + } + } + + // Initialize colCmpr + code = tInitDefaultSColCmprWrapperByCols(&createReq.colCmpr, numOfCols); + if (code != TSDB_CODE_SUCCESS) { + goto _OVER; + } + + // Build SVCreateTbBatchReq (vnode expects batch request) + SVCreateTbBatchReq batchReq = {0}; + batchReq.nReqs = 1; + batchReq.pArray = taosArrayInit(1, sizeof(SVCreateTbReq)); + if (batchReq.pArray == NULL) { + code = terrno; + goto _OVER; + } + if (taosArrayPush(batchReq.pArray, &createReq) == NULL) { + code = terrno; + taosArrayDestroy(batchReq.pArray); + goto _OVER; + } + batchReq.source = TD_REQ_FROM_APP; + + // Serialize the batch request + int32_t contLen = 0; + int32_t ret = 0; + tEncodeSize(tEncodeSVCreateTbBatchReq, &batchReq, contLen, ret); + if (ret < 0) { + code = terrno; + taosArrayDestroy(batchReq.pArray); + goto _OVER; + } + + contLen += sizeof(SMsgHead); + + SMsgHead *pHead = taosMemoryCalloc(1, contLen); + if (pHead == NULL) { + code = terrno; + taosArrayDestroy(batchReq.pArray); + goto _OVER; + } + pHead->contLen = htonl(contLen); + pHead->vgId = htonl(pVgroup->vgId); + + SEncoder encoder = {0}; + void *pBuf = POINTER_SHIFT(pHead, sizeof(SMsgHead)); + tEncoderInit(&encoder, pBuf, contLen - sizeof(SMsgHead)); + code = tEncodeSVCreateTbBatchReq(&encoder, &batchReq); + tEncoderClear(&encoder); + taosArrayDestroy(batchReq.pArray); + if (code < 0) { + taosMemoryFree(pHead); + goto _OVER; + } + + // Add to transaction redo actions + STransAction action = {0}; + action.mTraceId = pTrans->mTraceId; + action.epSet = mndGetVgroupEpset(pMnode, pVgroup); + action.pCont = pHead; + action.contLen = contLen; + action.msgType = TDMT_VND_CREATE_TABLE; + action.acceptableCode = TSDB_CODE_TDB_TABLE_ALREADY_EXIST; + action.retryCode = TSDB_CODE_TDB_TABLE_NOT_EXIST; + action.groupId = pVgroup->vgId; + + code = mndTransAppendRedoAction(pTrans, &action); + if (code != TSDB_CODE_SUCCESS) { + taosMemoryFree(pHead); + goto _OVER; + } + + // Build undo action (drop table if transaction fails) + SVDropTbReq dropReq = {0}; + dropReq.uid = createReq.uid; + dropReq.igNotExists = 1; // Ignore if table doesn't exist + dropReq.isVirtual = 0; + + SVDropTbBatchReq dropBatchReq = {0}; + dropBatchReq.nReqs = 1; + dropBatchReq.pArray = taosArrayInit(1, sizeof(SVDropTbReq)); + if (dropBatchReq.pArray == NULL) { + code = terrno; + goto _OVER; + } + if (taosArrayPush(dropBatchReq.pArray, &dropReq) == NULL) { + code = terrno; + taosArrayDestroy(dropBatchReq.pArray); + goto _OVER; + } + + // Serialize drop batch request + int32_t dropContLen = 0; + int32_t dropRet = 0; + tEncodeSize(tEncodeSVDropTbBatchReq, &dropBatchReq, dropContLen, dropRet); + if (dropRet < 0) { + code = terrno; + taosArrayDestroy(dropBatchReq.pArray); + goto _OVER; + } + + dropContLen += sizeof(SMsgHead); + SMsgHead *pDropHead = taosMemoryCalloc(1, dropContLen); + if (pDropHead == NULL) { + code = terrno; + taosArrayDestroy(dropBatchReq.pArray); + goto _OVER; + } + pDropHead->contLen = htonl(dropContLen); + pDropHead->vgId = htonl(pVgroup->vgId); + + SEncoder dropEncoder = {0}; + void *pDropBuf = POINTER_SHIFT(pDropHead, sizeof(SMsgHead)); + tEncoderInit(&dropEncoder, pDropBuf, dropContLen - sizeof(SMsgHead)); + code = tEncodeSVDropTbBatchReq(&dropEncoder, &dropBatchReq); + tEncoderClear(&dropEncoder); + taosArrayDestroy(dropBatchReq.pArray); + if (code < 0) { + taosMemoryFree(pDropHead); + goto _OVER; + } + + // Add undo action + STransAction undoAction = {0}; + undoAction.epSet = mndGetVgroupEpset(pMnode, pVgroup); + undoAction.pCont = pDropHead; + undoAction.contLen = dropContLen; + undoAction.msgType = TDMT_VND_DROP_TABLE; + undoAction.acceptableCode = TSDB_CODE_TDB_TABLE_NOT_EXIST; + + code = mndTransAppendUndoAction(pTrans, &undoAction); + if (code != TSDB_CODE_SUCCESS) { + taosMemoryFree(pDropHead); + goto _OVER; + } + + mInfo("stream:%s created output normal table:%s in vgroup:%d", pStream->name, pStream->outTblName, pVgroup->vgId); + +_OVER: + // Free resources (note: pHead is owned by transaction, don't free it here) + if (createReq.name) taosMemoryFree(createReq.name); + if (createReq.ntb.schemaRow.pSchema) taosMemoryFree(createReq.ntb.schemaRow.pSchema); + if (createReq.pExtSchemas) taosMemoryFree(createReq.pExtSchemas); + if (createReq.colCmpr.pColCmpr) taosMemoryFreeClear(createReq.colCmpr.pColCmpr); + + mndReleaseVgroup(pMnode, pVgroup); + mndReleaseDb(pMnode, pDb); + + if (code != TSDB_CODE_SUCCESS) { + mError("stream:%s failed to create output normal table:%s, line:%d code:%s", pStream->name, pStream->outTblName, + lino, tstrerror(code)); + } + + return code; +} + +static int32_t mndStreamValidateCreate(SMnode *pMnode, SRpcMsg *pReq, SCMCreateStreamReq *pCreate) { int32_t code = 0, lino = 0; int64_t streamId = pCreate->streamId; char *pUser = RPC_MSG_USER(pReq); @@ -428,15 +688,15 @@ int32_t mndDropStreamByDb(SMnode *pMnode, STrans *pTrans, SDbObj *pDb) { if (0 == strcmp(pStream->pCreate->streamDB, pDb->name)) { mInfo("start to drop stream %s in db %s", pStream->pCreate->name, pDb->name); - + pStream->updateTime = taosGetTimestampMs(); - + atomic_store_8(&pStream->userDropped, 1); - + MND_STREAM_SET_LAST_TS(STM_EVENT_DROP_STREAM, pStream->updateTime); - + msmUndeployStream(pMnode, pStream->pCreate->streamId, pStream->pCreate->name); - + // drop stream code = mndStreamTransAppend(pStream, pTrans, SDB_STATUS_DROPPED); if (code) { @@ -527,7 +787,8 @@ static void mndCancelGetNextStreamTask(SMnode *pMnode, void *pIter) { sdbCancelFetchByType(pSdb, pIter, SDB_STREAM); } -static int32_t mndRetrieveStreamRecalculates(SRpcMsg *pReq, SShowObj *pShow, SSDataBlock *pBlock, int32_t rowsCapacity) { +static int32_t mndRetrieveStreamRecalculates(SRpcMsg *pReq, SShowObj *pShow, SSDataBlock *pBlock, + int32_t rowsCapacity) { SMnode *pMnode = pReq->info.node; SSdb *pSdb = pMnode->pSdb; int32_t numOfRows = 0; @@ -554,20 +815,18 @@ static void mndCancelGetNextStreamRecalculates(SMnode *pMnode, void *pIter) { sdbCancelFetchByType(pSdb, pIter, SDB_STREAM); } - static bool mndStreamUpdateTagsFlag(SMnode *pMnode, void *pObj, void *p1, void *p2, void *p3) { SStreamObj *pStream = pObj; if (atomic_load_8(&pStream->userDropped)) { return true; } - if (TSDB_SUPER_TABLE != pStream->pCreate->triggerTblType && - TSDB_CHILD_TABLE != pStream->pCreate->triggerTblType && + if (TSDB_SUPER_TABLE != pStream->pCreate->triggerTblType && TSDB_CHILD_TABLE != pStream->pCreate->triggerTblType && TSDB_VIRTUAL_CHILD_TABLE != pStream->pCreate->triggerTblType) { return true; } - if (pStream->pCreate->triggerTblSuid != *(uint64_t*)p1) { + if (pStream->pCreate->triggerTblSuid != *(uint64_t *)p1) { return true; } @@ -575,20 +834,21 @@ static bool mndStreamUpdateTagsFlag(SMnode *pMnode, void *pObj, void *p1, void * return true; } - SNodeList* pList = NULL; - int32_t code = nodesStringToList(pStream->pCreate->partitionCols, &pList); + SNodeList *pList = NULL; + int32_t code = nodesStringToList(pStream->pCreate->partitionCols, &pList); if (code) { nodesDestroyList(pList); - mstError("partitionCols [%s] nodesStringToList failed with error:%s", (char*)pStream->pCreate->partitionCols, tstrerror(code)); + mstError("partitionCols [%s] nodesStringToList failed with error:%s", (char *)pStream->pCreate->partitionCols, + tstrerror(code)); return true; } - SSchema* pTags = (SSchema*)p2; - int32_t* tagNum = (int32_t*)p3; + SSchema *pTags = (SSchema *)p2; + int32_t *tagNum = (int32_t *)p3; - SNode* pNode = NULL; + SNode *pNode = NULL; FOREACH(pNode, pList) { - SColumnNode* pCol = (SColumnNode*)pNode; + SColumnNode *pCol = (SColumnNode *)pNode; for (int32_t i = 0; i < *tagNum; ++i) { if (pCol->colId == pTags[i].colId) { pTags[i].flags |= COL_REF_BY_STM; @@ -598,12 +858,11 @@ static bool mndStreamUpdateTagsFlag(SMnode *pMnode, void *pObj, void *p1, void * } nodesDestroyList(pList); - + return true; } - -void mndStreamUpdateTagsRefFlag(SMnode *pMnode, int64_t suid, SSchema* pTags, int32_t tagNum) { +void mndStreamUpdateTagsRefFlag(SMnode *pMnode, int64_t suid, SSchema *pTags, int32_t tagNum) { int32_t streamNum = sdbGetSize(pMnode->pSdb, SDB_STREAM); if (streamNum <= 0) { return; @@ -639,11 +898,11 @@ static int32_t mndProcessStopStreamReq(SRpcMsg *pReq) { taosMemoryFree(pauseReq.name); int64_t streamId = pStream->pCreate->streamId; - + mstsInfo("start to stop stream %s", pStream->name); // code = mndCheckDbPrivilegeByName(pMnode, RPC_MSG_USER(pReq), MND_OPER_WRITE_DB, pStream->pCreate->streamDB); - if((code = mndAcquireUser(pMnode, RPC_MSG_USER(pReq), &pOperUser))) { + if ((code = mndAcquireUser(pMnode, RPC_MSG_USER(pReq), &pOperUser))) { mstsError("user %s failed to stop stream %s since %s", RPC_MSG_USER(pReq), pStream->name, tstrerror(code)); sdbRelease(pMnode->pSdb, pStream); return code; @@ -661,7 +920,7 @@ static int32_t mndProcessStopStreamReq(SRpcMsg *pReq) { return code; } - mndReleaseUser(pMnode, pOperUser); // release user after privilege check + mndReleaseUser(pMnode, pOperUser); // release user after privilege check if (atomic_load_8(&pStream->userDropped)) { code = TSDB_CODE_MND_STREAM_DROPPING; @@ -708,7 +967,6 @@ static int32_t mndProcessStopStreamReq(SRpcMsg *pReq) { return TSDB_CODE_ACTION_IN_PROGRESS; } - static int32_t mndProcessStartStreamReq(SRpcMsg *pReq) { SMnode *pMnode = pReq->info.node; SStreamObj *pStream = NULL; @@ -763,7 +1021,7 @@ static int32_t mndProcessStartStreamReq(SRpcMsg *pReq) { return code; } - mndReleaseUser(pMnode, pOperUser); // release user after privilege check + mndReleaseUser(pMnode, pOperUser); // release user after privilege check if (atomic_load_8(&pStream->userDropped)) { code = TSDB_CODE_MND_STREAM_DROPPING; @@ -778,7 +1036,7 @@ static int32_t mndProcessStartStreamReq(SRpcMsg *pReq) { sdbRelease(pMnode->pSdb, pStream); return code; } - + atomic_store_8(&pStream->userStopped, 0); pStream->updateTime = taosGetTimestampMs(); @@ -997,15 +1255,15 @@ static int32_t mndProcessDropStreamReq(SRpcMsg *pReq) { } static int32_t mndProcessCreateStreamReq(SRpcMsg *pReq) { - SMnode *pMnode = pReq->info.node; - SStreamObj *pStream = NULL; - SStreamObj streamObj = {0}; - SUserObj *pOperUser = NULL; - int32_t code = TSDB_CODE_SUCCESS; - int32_t lino = 0; - STrans *pTrans = NULL; - uint64_t streamId = 0; - SCMCreateStreamReq* pCreate = NULL; + SMnode *pMnode = pReq->info.node; + SStreamObj *pStream = NULL; + SStreamObj streamObj = {0}; + SUserObj *pOperUser = NULL; + int32_t code = TSDB_CODE_SUCCESS; + int32_t lino = 0; + STrans *pTrans = NULL; + uint64_t streamId = 0; + SCMCreateStreamReq *pCreate = NULL; int64_t tss = taosGetTimestampMs(); if ((code = grantCheck(TSDB_GRANT_STREAMS)) < 0) { @@ -1014,7 +1272,7 @@ static int32_t mndProcessCreateStreamReq(SRpcMsg *pReq) { pCreate = taosMemoryCalloc(1, sizeof(SCMCreateStreamReq)); TSDB_CHECK_NULL(pCreate, code, lino, _OVER, terrno); - + code = tDeserializeSCMCreateStreamReq(pReq->pCont, pReq->contLen, pCreate); TSDB_CHECK_CODE(code, lino, _OVER); @@ -1027,7 +1285,7 @@ static int32_t mndProcessCreateStreamReq(SRpcMsg *pReq) { code = terrno; TSDB_CHECK_CODE(code, lino, _OVER); } - + code = mndAcquireStream(pMnode, pCreate->name, &pStream); if (pStream != NULL && code == 0) { if (pCreate->igExists) { @@ -1060,11 +1318,24 @@ static int32_t mndProcessCreateStreamReq(SRpcMsg *pReq) { goto _OVER; } - // create stb for stream - if (TSDB_SUPER_TABLE == pStream->pCreate->outTblType && !pStream->pCreate->outStbExists) { - pStream->pCreate->outStbUid = mndGenerateUid(pStream->pCreate->outTblName, strlen(pStream->pCreate->outTblName)); - code = mndStreamCreateOutStb(pMnode, pTrans, pStream->pCreate, RPC_MSG_USER(pReq)); - TSDB_CHECK_CODE(code, lino, _OVER); + // create output table for stream if it doesn't exist + if (!pStream->pCreate->outStbExists) { + if (TSDB_SUPER_TABLE == pStream->pCreate->outTblType) { + // Create super table in mnode + pStream->pCreate->outStbUid = mndGenerateUid(pStream->pCreate->outTblName, strlen(pStream->pCreate->outTblName)); + code = mndStreamCreateOutStb(pMnode, pTrans, pStream->pCreate, RPC_MSG_USER(pReq)); + TSDB_CHECK_CODE(code, lino, _OVER); + mstsInfo("stream:%s created output super table:%s", pStream->pCreate->name, pStream->pCreate->outTblName); + } else if (TSDB_NORMAL_TABLE == pStream->pCreate->outTblType) { + // Create normal table in vnode + code = mndStreamCreateOutTable(pMnode, pTrans, pStream->pCreate); + TSDB_CHECK_CODE(code, lino, _OVER); + mstsInfo("stream:%s created output normal table:%s", pStream->pCreate->name, pStream->pCreate->outTblName); + } + } else { + // Table exists, schema validation should have been done in client side + mstsInfo("stream:%s output table:%s already exists, using existing table", pStream->pCreate->name, + pStream->pCreate->outTblName); } // add stream to trans @@ -1141,7 +1412,7 @@ static int32_t mndProcessRecalcStreamReq(SRpcMsg *pReq) { } int64_t streamId = pStream->pCreate->streamId; - + mstsInfo("start to recalc stream %s", recalcReq.name); // code = mndCheckDbPrivilegeByName(pMnode, RPC_MSG_USER(pReq), MND_OPER_WRITE_DB, pStream->pCreate->streamDB); @@ -1173,7 +1444,7 @@ static int32_t mndProcessRecalcStreamReq(SRpcMsg *pReq) { return code; } - mndReleaseUser(pMnode, pOperUser); // release user after privilege check + mndReleaseUser(pMnode, pOperUser); // release user after privilege check if (atomic_load_8(&pStream->userDropped)) { code = TSDB_CODE_MND_STREAM_DROPPING; @@ -1234,23 +1505,22 @@ static int32_t mndProcessRecalcStreamReq(SRpcMsg *pReq) { return code; } - if (tsAuditLevel >= AUDIT_LEVEL_DATABASE){ + if (tsAuditLevel >= AUDIT_LEVEL_DATABASE) { char buf[128]; snprintf(buf, sizeof(buf), "start:%" PRId64 ", end:%" PRId64, recalcReq.timeRange.skey, recalcReq.timeRange.ekey); int64_t tse = taosGetTimestampMs(); double duration = (double)(tse - tss); duration = duration / 1000; auditRecord(pReq, pMnode->clusterId, "recalcStream", pStream->name, recalcReq.name, buf, strlen(buf), duration, 0); - } + } sdbRelease(pMnode->pSdb, pStream); tFreeMRecalcStreamReq(&recalcReq); -// mndTransDrop(pTrans); + // mndTransDrop(pTrans); return TSDB_CODE_SUCCESS; } - int32_t mndInitStream(SMnode *pMnode) { SSdbTable table = { .sdbType = SDB_STREAM, @@ -1267,10 +1537,10 @@ int32_t mndInitStream(SMnode *pMnode) { mndSetMsgHandle(pMnode, TDMT_MND_DROP_STREAM, mndProcessDropStreamReq); mndSetMsgHandle(pMnode, TDMT_MND_START_STREAM, mndProcessStartStreamReq); mndSetMsgHandle(pMnode, TDMT_MND_STOP_STREAM, mndProcessStopStreamReq); - mndSetMsgHandle(pMnode, TDMT_MND_STREAM_HEARTBEAT, mndProcessStreamHb); + mndSetMsgHandle(pMnode, TDMT_MND_STREAM_HEARTBEAT, mndProcessStreamHb); mndSetMsgHandle(pMnode, TDMT_MND_RECALC_STREAM, mndProcessRecalcStreamReq); } - + mndAddShowRetrieveHandle(pMnode, TSDB_MGMT_TABLE_STREAMS, mndRetrieveStream); mndAddShowFreeIterHandle(pMnode, TSDB_MGMT_TABLE_STREAMS, mndCancelGetNextStream); mndAddShowRetrieveHandle(pMnode, TSDB_MGMT_TABLE_STREAM_TASKS, mndRetrieveStreamTask); @@ -1283,6 +1553,6 @@ int32_t mndInitStream(SMnode *pMnode) { return code; } - //code = sdbSetTable(pMnode->pSdb, tableSeq); + // code = sdbSetTable(pMnode->pSdb, tableSeq); return code; } diff --git a/source/dnode/mnode/impl/src/mndStreamMgmt.c b/source/dnode/mnode/impl/src/mndStreamMgmt.c index 8a744bc742ac..febebf1f4d78 100755 --- a/source/dnode/mnode/impl/src/mndStreamMgmt.c +++ b/source/dnode/mnode/impl/src/mndStreamMgmt.c @@ -892,6 +892,7 @@ int32_t msmBuildTriggerDeployInfo(SMnode* pMnode, SStmStatus* pInfo, SStmTaskDep pMsg->leaderSnodeId = pStream->mainSnodeId; pMsg->streamName = pInfo->streamName; + pMsg->nodelayCreateSubtable = pStream->pCreate->nodelayCreateSubtable; if (0 == pInfo->runnerNum) { mstsDebug("no runner task, skip set trigger's runner list, deployNum:%d", pInfo->runnerDeploys); @@ -3480,7 +3481,8 @@ int32_t msmNormalHandleStatusUpdate(SStmGrpCtx* pCtx) { SStmTaskStatus** ppStatus = taosHashGet(mStreamMgmt.taskMap, &pTask->streamId, sizeof(pTask->streamId) + sizeof(pTask->taskId)); if (NULL == ppStatus) { - msttWarn("task no longer exists in taskMap, will try to undeploy current task, taskIdx:%d", pTask->taskIdx); + msttWarn("task no longer exists in taskMap, streamId:0x%" PRIx64 " taskId:0x%" PRIx64 " type:%s status:%s taskIdx:%d", + (uint64_t)pTask->streamId, (uint64_t)pTask->taskId, gStreamTaskTypeStr[pTask->type], gStreamStatusStr[pTask->status], pTask->taskIdx); msmHandleStreamTaskErr(pCtx, STM_ERR_TASK_NOT_EXISTS, pTask); continue; } @@ -3517,6 +3519,10 @@ int32_t msmNormalHandleStatusUpdate(SStmGrpCtx* pCtx) { (*ppStatus)->status = pTask->status; (*ppStatus)->lastUpTs = pCtx->currTs; + if (STREAM_TRIGGER_TASK == pTask->type && STREAM_STATUS_RUNNING == pTask->status) { + mstInfo("streamId:0x%" PRIx64 " trigger task status updated to Running in streamMap", (uint64_t)pTask->streamId); + } + if (STREAM_STATUS_RUNNING != pTask->status) { msmHandleTaskAbnormalStatus(pCtx, pTask, *ppStatus); } diff --git a/source/dnode/mnode/impl/src/mndStreamUtil.c b/source/dnode/mnode/impl/src/mndStreamUtil.c index 2910060199b2..861a4c744b4b 100644 --- a/source/dnode/mnode/impl/src/mndStreamUtil.c +++ b/source/dnode/mnode/impl/src/mndStreamUtil.c @@ -766,8 +766,10 @@ int32_t mstGetStreamStatusStr(SStreamObj* pStream, char* status, int32_t statusS (void)mstWaitLock(&mStreamMgmt.runtimeLock, true); - SStmStatus* pStatus = (SStmStatus*)taosHashGet(mStreamMgmt.streamMap, &pStream->pCreate->streamId, sizeof(pStream->pCreate->streamId)); + int64_t streamId = pStream->pCreate->streamId; + SStmStatus* pStatus = (SStmStatus*)taosHashGet(mStreamMgmt.streamMap, &streamId, sizeof(streamId)); if (NULL == pStatus) { + mstDebug("return Undeployed: stream not in streamMap (show streams)"); STR_WITH_MAXSIZE_TO_VARSTR(status, gStreamStatusStr[STREAM_STATUS_UNDEPLOYED], statusSize); STR_WITH_MAXSIZE_TO_VARSTR(msg, "", msgSize); goto _exit; @@ -800,6 +802,9 @@ int32_t mstGetStreamStatusStr(SStreamObj* pStream, char* status, int32_t statusS goto _exit; } + mstsDebug("return Idle: pStatus=%p triggerTask=%p triggerStatus=%d (show streams view)", + (void*)pStatus, (void*)(pStatus ? pStatus->triggerTask : NULL), + (pStatus && pStatus->triggerTask) ? (int)pStatus->triggerTask->status : -1); STR_WITH_MAXSIZE_TO_VARSTR(status, gStreamStatusStr[STREAM_STATUS_INIT], statusSize); snprintf(tmpBuf, sizeof(tmpBuf), "Current deploy times: %" PRId64, pStatus->deployTimes); STR_WITH_MAXSIZE_TO_VARSTR(msg, tmpBuf, msgSize); diff --git a/source/dnode/vnode/src/vnd/vnodeStream.c b/source/dnode/vnode/src/vnd/vnodeStream.c index 53f982ccc777..9f508ef4c48b 100644 --- a/source/dnode/vnode/src/vnd/vnodeStream.c +++ b/source/dnode/vnode/src/vnd/vnodeStream.c @@ -2653,9 +2653,24 @@ static int32_t processTsNonVTable(SVnode* pVnode, SStreamTsResponse* tsRsp, SStr pTaskInner->options->suid = sStreamReaderInfo->suid; STREAM_CHECK_RET_GOTO(getAllTs(pVnode, pResBlock, pTaskInner, pList, pNum)); - STREAM_CHECK_CONDITION_GOTO(pResBlock->info.rows == 0, TDB_CODE_SUCCESS); + int32_t order = pTaskInner->options->order; + if (pResBlock->info.rows == 0 && sStreamReaderInfo->groupByTbname) { + tsRsp->tsInfo = taosArrayInit(pNum, sizeof(STsInfo)); + STREAM_CHECK_NULL_GOTO(tsRsp->tsInfo, terrno); + for (int32_t i = 0; i < pNum; i++) { + STsInfo* tsInfo = taosArrayReserve(tsRsp->tsInfo, 1); + STREAM_CHECK_NULL_GOTO(tsInfo, terrno); + tsInfo->gId = pList[i].uid; + tsInfo->ts = 0; + ST_TASK_DLOG("%s no data but return gId (uid):%" PRIu64 " for tbname partition", __func__, tsInfo->gId); + } + goto end; + } + + STREAM_CHECK_CONDITION_GOTO(pResBlock->info.rows == 0, TDB_CODE_SUCCESS); + if (sStreamReaderInfo->groupByTbname) { STREAM_CHECK_RET_GOTO(processTsOutPutAllTables(sStreamReaderInfo, tsRsp, pResBlock, order)); } else if (sStreamReaderInfo->partitionCols == NULL) { diff --git a/source/libs/new-stream/inc/streamTriggerTask.h b/source/libs/new-stream/inc/streamTriggerTask.h index 8fe0dda9c3c9..51bc7947b7e6 100644 --- a/source/libs/new-stream/inc/streamTriggerTask.h +++ b/source/libs/new-stream/inc/streamTriggerTask.h @@ -163,6 +163,12 @@ typedef struct SSTriggerWalProgress { SSDataBlock *pCalcBlock; } SSTriggerWalProgress; +// (gid, pProgress) for nodelay create-table; each gid must be pulled from its owning reader +typedef struct { + int64_t gid; + SSTriggerWalProgress *pProgress; +} SSTriggerPendingCreateTableEntry; + typedef enum ESTriggerWalMode { STRIGGER_WAL_META_ONLY, STRIGGER_WAL_META_WITH_DATA, @@ -237,6 +243,9 @@ typedef struct SSTriggerRealtimeContext { int64_t lastCheckpointTime; int64_t lastVirtTableInfoTime; int64_t lastReportTime; + + // LAST_TS create-table: need groupInfo before send create-table req; pull GROUP_COL_VALUE first + SArray *pPendingCreateTableGids; // SArray, (gid, pProgress) per reader } SSTriggerRealtimeContext; typedef struct SSTriggerTsdbProgress { @@ -403,6 +412,7 @@ typedef struct SStreamTriggerTask { SArray *pNotifyAddrUrls; int32_t addOptions; bool notifyHistory; + int8_t nodelayCreateSubtable; // 1 = sub-tables created at stream create; 0 = create on the fly // task info int32_t leaderSnodeId; diff --git a/source/libs/new-stream/src/streamTriggerTask.c b/source/libs/new-stream/src/streamTriggerTask.c index 11b7bce64971..b8ebbc64c127 100644 --- a/source/libs/new-stream/src/streamTriggerTask.c +++ b/source/libs/new-stream/src/streamTriggerTask.c @@ -20,6 +20,7 @@ #include "plannodes.h" #include "scalar.h" #include "streamInt.h" +#include "streamReader.h" #include "taos.h" #include "taoserror.h" #include "tarray.h" @@ -2303,6 +2304,7 @@ int32_t stTriggerTaskDeploy(SStreamTriggerTask *pTask, SStreamTriggerDeployMsg * } pTask->leaderSnodeId = pMsg->leaderSnodeId; + pTask->nodelayCreateSubtable = pMsg->nodelayCreateSubtable; TSWAP(pTask->readerList, pMsg->readerList); if (pTask->isVirtualTable) { pTask->virtReaderList = taosArrayInit(0, sizeof(SStreamTaskAddr)); @@ -3403,6 +3405,11 @@ static void stRealtimeContextDestroy(void *ptr) { tdListEmpty(&pContext->retryCalcReqs); tdListEmpty(&pContext->dropTableReqs); + if (pContext->pPendingCreateTableGids != NULL) { + taosArrayDestroy(pContext->pPendingCreateTableGids); + pContext->pPendingCreateTableGids = NULL; + } + taosMemFreeClear(*ppContext); } @@ -3815,6 +3822,176 @@ static int32_t stRealtimeContextSendPullReq(SSTriggerRealtimeContext *pContext, return code; } +// send STRIGGER_PULL_GROUP_COL_VALUE for given (pProgress, gid); used when pulling groupInfo for pending create-table +static int32_t stRealtimeContextSendPullReqForGid(SSTriggerRealtimeContext *pContext, SSTriggerWalProgress *pProgress, + int64_t gid) { + SStreamTriggerTask *pTask = pContext->pTask; + SSTriggerPullRequest *pReq = &pProgress->pullReq.base; + SStreamTaskAddr *pReader = pProgress->pTaskAddr; + SRpcMsg msg = {.msgType = TDMT_STREAM_TRIGGER_PULL}; + int32_t code = TSDB_CODE_SUCCESS; + int32_t lino = 0; + + pReq->type = STRIGGER_PULL_GROUP_COL_VALUE; + pReq->readerTaskId = pReader->taskId; + pProgress->pullReq.groupColValueReq.gid = gid; + + QUERY_CHECK_CODE(stTriggerTaskAllocAhandle(pTask, pContext->sessionId, pReq, &msg.info.ahandle), lino, _end); + msg.contLen = tSerializeSTriggerPullRequest(NULL, 0, pReq); + QUERY_CHECK_CONDITION(msg.contLen > 0, code, lino, _end, TSDB_CODE_INTERNAL_ERROR); + msg.contLen += sizeof(SMsgHead); + msg.pCont = rpcMallocCont(msg.contLen); + QUERY_CHECK_NULL(msg.pCont, code, lino, _end, terrno); + SMsgHead *pMsgHead = (SMsgHead *)msg.pCont; + pMsgHead->contLen = htonl(msg.contLen); + pMsgHead->vgId = htonl(pReader->nodeId); + int32_t tlen = + tSerializeSTriggerPullRequest((char *)msg.pCont + sizeof(SMsgHead), msg.contLen - sizeof(SMsgHead), pReq); + QUERY_CHECK_CONDITION(tlen == msg.contLen - sizeof(SMsgHead), code, lino, _end, TSDB_CODE_INTERNAL_ERROR); + TRACE_SET_ROOTID(&msg.info.traceId, pTask->task.streamId); + TRACE_SET_MSGID(&msg.info.traceId, tGenIdPI64()); + code = tmsgSendReq(&pReader->epset, &msg); + QUERY_CHECK_CODE(code, lino, _end); + ST_TASK_DLOG("send pull GROUP_COL_VALUE for gid:%" PRId64 " to node:%d", gid, pReader->nodeId); + return code; +_end: + if (code != TSDB_CODE_SUCCESS && msg.info.ahandle != NULL) { + destroyAhandle(msg.info.ahandle); + } + return code; +} + +// send one "create table only" calc request to runner for the given gid (uses reader response info) +static int32_t stTriggerTaskSendCreateTableReq(SStreamTriggerTask *pTask, SSTriggerRealtimeContext *pContext, + int64_t sessionId, int64_t gid) { + int32_t code = TSDB_CODE_SUCCESS; + int32_t lino = 0; + SSTriggerCalcRequest *pCalcReq = NULL; + SStreamRunnerTarget *pCalcRunner = NULL; + SRpcMsg msg = {.msgType = TDMT_STREAM_TRIGGER_CALC}; + bool needTagValue = false; + bool needDestroyAhandle = false; + + code = stTriggerTaskAcquireRequest(pTask, sessionId, gid, &pCalcReq); + if (code != TSDB_CODE_SUCCESS || pCalcReq == NULL) { + return TSDB_CODE_SUCCESS; // no slot or busy, skip + } + pCalcReq->createTable = 1; + SSTriggerCalcParam param = {0}; + param.triggerTime = taosGetTimestampNs(); + param.wstart = 0; + param.wend = 0; + param.notifyType = STRIGGER_EVENT_WINDOW_NONE; + if (taosArrayPush(pCalcReq->params, ¶m) == NULL) { + code = terrno; + lino = __LINE__; + goto _end; + } + if (pTask->hasPartitionBy || (pTask->placeHolderBitmap & PLACE_HOLDER_PARTITION_IDX) || + (pTask->placeHolderBitmap & PLACE_HOLDER_PARTITION_TBNAME)) { + needTagValue = true; + } + if (needTagValue && pContext != NULL && pContext->pGroupColVals != NULL && taosArrayGetSize(pCalcReq->groupColVals) == 0) { + void *px = tSimpleHashGet(pContext->pGroupColVals, &gid, sizeof(int64_t)); + if (px != NULL) { + SArray *pGroupColVals = *(SArray **)px; + if (pGroupColVals != NULL) { + for (int32_t i = 0; i < TARRAY_SIZE(pGroupColVals); i++) { + SStreamGroupValue *pValue = TARRAY_GET_ELEM(pGroupColVals, i); + SStreamGroupValue *pDst = taosArrayPush(pCalcReq->groupColVals, pValue); + if (pDst == NULL) { + code = terrno; + lino = __LINE__; + goto _end; + } + if (IS_VAR_DATA_TYPE(pValue->data.type) || pValue->data.type == TSDB_DATA_TYPE_DECIMAL) { + pDst->data.pData = taosMemoryMalloc(pDst->data.nData); + if (pDst->data.pData == NULL) { + code = terrno; + lino = __LINE__; + goto _end; + } + TAOS_MEMCPY(pDst->data.pData, pValue->data.pData, pDst->data.nData); + } + } + } + } + } + int32_t nRunners = taosArrayGetSize(pTask->runnerList); + for (int32_t i = 0; i < nRunners; i++) { + pCalcRunner = TARRAY_GET_ELEM(pTask->runnerList, i); + if (pCalcRunner->addr.taskId == pCalcReq->runnerTaskId) { + break; + } + pCalcRunner = NULL; + } + if (pCalcRunner == NULL) { + code = TSDB_CODE_INTERNAL_ERROR; + lino = __LINE__; + goto _end; + } + code = stTriggerTaskAllocAhandle(pTask, sessionId, pCalcReq, &msg.info.ahandle); + if (code != TSDB_CODE_SUCCESS) { + lino = __LINE__; + goto _end; + } + needDestroyAhandle = true; + msg.contLen = tSerializeSTriggerCalcRequest(NULL, 0, pCalcReq); + if (msg.contLen <= 0) { + code = TSDB_CODE_INTERNAL_ERROR; + lino = __LINE__; + goto _end; + } + msg.contLen += sizeof(SMsgHead); + msg.pCont = rpcMallocCont(msg.contLen); + if (msg.pCont == NULL) { + code = terrno; + lino = __LINE__; + goto _end; + } + SMsgHead *pMsgHead = (SMsgHead *)msg.pCont; + pMsgHead->contLen = htonl(msg.contLen); + pMsgHead->vgId = htonl(SNODE_HANDLE); + int32_t tlen = + tSerializeSTriggerCalcRequest((char *)msg.pCont + sizeof(SMsgHead), msg.contLen - sizeof(SMsgHead), pCalcReq); + if (tlen != msg.contLen - sizeof(SMsgHead)) { + code = TSDB_CODE_INTERNAL_ERROR; + lino = __LINE__; + goto _end; + } + TRACE_SET_ROOTID(&msg.info.traceId, pTask->task.streamId); + TRACE_SET_MSGID(&msg.info.traceId, tGenIdPI64()); + code = tmsgSendReq(&pCalcRunner->addr.epset, &msg); + if (code != TSDB_CODE_SUCCESS) { + lino = __LINE__; + goto _end; + } + ST_TASK_DLOG("pull rsp: send create-table-only calc request to runner task:%" PRIx64 " gid:%" PRId64, + pCalcRunner->addr.taskId, gid); + return TSDB_CODE_SUCCESS; + +_end: + if (code != TSDB_CODE_SUCCESS) { + ST_TASK_ELOG("%s failed at line %d since %s", __func__, lino, tstrerror(code)); + } + + if (msg.pCont != NULL) { + rpcFreeCont(msg.pCont); + msg.pCont = NULL; + } + if (needDestroyAhandle) { + destroyAhandle(msg.info.ahandle); + } + if (pCalcReq != NULL) { + code = stTriggerTaskReleaseRequest(pTask, &pCalcReq); + if (code != TSDB_CODE_SUCCESS) { + ST_TASK_ELOG("%s failed at line %d since %s", __func__, lino, tstrerror(code)); + return code; + } + } + return code; +} + static int32_t stRealtimeContextSendCalcReq(SSTriggerRealtimeContext *pContext) { int32_t code = TSDB_CODE_SUCCESS; int32_t lino = 0; @@ -5050,14 +5227,30 @@ static int32_t stRealtimeContextProcPullRsp(SSTriggerRealtimeContext *pContext, pProgress->doneVer = pProgress->startVer; pProgress->lastScanVer = pProgress->startVer; int32_t nrows = blockDataGetNumOfRows(pDataBlock); + int64_t *pGidData = NULL; + int64_t *pTsData = NULL; + if (nrows > 0) { int32_t iCol = 0; SColumnInfoData *pGidCol = taosArrayGet(pDataBlock->pDataBlock, iCol++); QUERY_CHECK_NULL(pGidCol, code, lino, _end, terrno); - int64_t *pGidData = (int64_t *)pGidCol->pData; + pGidData = (int64_t *)pGidCol->pData; SColumnInfoData *pTsCol = taosArrayGet(pDataBlock->pDataBlock, iCol++); QUERY_CHECK_NULL(pTsCol, code, lino, _end, terrno); - int64_t *pTsData = (int64_t *)pTsCol->pData; + pTsData = (int64_t *)pTsCol->pData; + } else if (pDataBlock->pDataBlock != NULL && pTask->nodelayCreateSubtable) { + int32_t iCol = 0; + SColumnInfoData *pGidCol = taosArrayGet(pDataBlock->pDataBlock, iCol++); + if (pGidCol != NULL && pGidCol->pData != NULL) { + pGidData = (int64_t *)pGidCol->pData; + } + SColumnInfoData *pTsCol = taosArrayGet(pDataBlock->pDataBlock, iCol++); + if (pTsCol != NULL && pTsCol->pData != NULL) { + pTsData = (int64_t *)pTsCol->pData; + } + } + + if (nrows > 0 && pGidData != NULL && pTsData != NULL) { if (pTask->isVirtualTable) { for (int32_t i = 0; i < nrows; i++) { int64_t obtUid = pGidData[i]; @@ -5091,11 +5284,52 @@ static int32_t stRealtimeContextProcPullRsp(SSTriggerRealtimeContext *pContext, } } + if (pTask->nodelayCreateSubtable && nrows > 0 && pGidData != NULL) { + if (pContext->pPendingCreateTableGids == NULL) { + pContext->pPendingCreateTableGids = + taosArrayInit(0, sizeof(SSTriggerPendingCreateTableEntry)); + QUERY_CHECK_NULL(pContext->pPendingCreateTableGids, code, lino, _end, terrno); + } + if (pTask->isVirtualTable) { + for (int32_t i = 0; i < nrows; i++) { + int64_t obtUid = pGidData[i]; + SSTriggerOrigTableInfo *pOrigTableInfo = tSimpleHashGet(pTask->pOrigTableInfos, &obtUid, sizeof(int64_t)); + if (pOrigTableInfo == NULL) continue; + for (int32_t j = 0; j < TARRAY_SIZE(pOrigTableInfo->pVtbUids); j++) { + int64_t vtbUid = *(int64_t *)TARRAY_GET_ELEM(pOrigTableInfo->pVtbUids, j); + SSTriggerVirtTableInfo *pVirtTableInfo = + tSimpleHashGet(pTask->pVirtTableInfos, &vtbUid, sizeof(int64_t)); + if (pVirtTableInfo == NULL) continue; + SSTriggerPendingCreateTableEntry entry = {.gid = pVirtTableInfo->tbGid, .pProgress = pProgress}; + void *px = taosArrayPush(pContext->pPendingCreateTableGids, &entry); + QUERY_CHECK_NULL(px, code, lino, _end, terrno); + } + } + } else { + for (int32_t i = 0; i < nrows; i++) { + SSTriggerPendingCreateTableEntry entry = {.gid = pGidData[i], .pProgress = pProgress}; + void *px = taosArrayPush(pContext->pPendingCreateTableGids, &entry); + QUERY_CHECK_NULL(px, code, lino, _end, terrno); + } + } + } + if (--pContext->curReaderIdx > 0) { // wait for responses from other readers goto _end; } + // all readers responded; send first GROUP_COL_VALUE pull for nodelay create-table if any + if (pContext->pPendingCreateTableGids != NULL && + taosArrayGetSize(pContext->pPendingCreateTableGids) > 0) { + SSTriggerPendingCreateTableEntry *pFirst = + (SSTriggerPendingCreateTableEntry *)taosArrayGet(pContext->pPendingCreateTableGids, 0); + QUERY_CHECK_NULL(pFirst, code, lino, _end, TSDB_CODE_INTERNAL_ERROR); + code = stRealtimeContextSendPullReqForGid(pContext, pFirst->pProgress, pFirst->gid); + QUERY_CHECK_CODE(code, lino, _end); + goto _end; + } + pContext->boundDetermined = true; pContext->status = STRIGGER_CONTEXT_IDLE; code = stRealtimeContextCheck(pContext); @@ -5519,9 +5753,44 @@ static int32_t stRealtimeContextProcPullRsp(SSTriggerRealtimeContext *pContext, case STRIGGER_PULL_GROUP_COL_VALUE: { QUERY_CHECK_CONDITION( - (pContext->status == STRIGGER_CONTEXT_SEND_CALC_REQ || pContext->status == STRIGGER_CONTEXT_SEND_DROP_REQ), + (pContext->status == STRIGGER_CONTEXT_DETERMINE_BOUND || pContext->status == STRIGGER_CONTEXT_SEND_CALC_REQ || + pContext->status == STRIGGER_CONTEXT_SEND_DROP_REQ), code, lino, _end, TSDB_CODE_INTERNAL_ERROR); SSTriggerGroupColValueRequest *pRequest = (SSTriggerGroupColValueRequest *)pReq; + if (pContext->status == STRIGGER_CONTEXT_DETERMINE_BOUND && pContext->pPendingCreateTableGids != NULL) { + // pending create-table: LAST_TS needed tag, we pulled groupInfo for one gid; create table then continue or finish + SStreamGroupInfo groupInfo = {0}; + if (pRsp->contLen > 0) { + code = tDeserializeSStreamGroupInfo(pRsp->pCont, pRsp->contLen, &groupInfo); + QUERY_CHECK_CODE(code, lino, _end); + } + code = tSimpleHashPut(pContext->pGroupColVals, &pRequest->gid, sizeof(int64_t), &groupInfo.gInfo, POINTER_BYTES); + if (code != TSDB_CODE_SUCCESS) { + taosArrayClearEx(groupInfo.gInfo, tDestroySStreamGroupValue); + QUERY_CHECK_CODE(code, lino, _end); + } + (void)stTriggerTaskSendCreateTableReq(pTask, pContext, pContext->sessionId, pRequest->gid); + (void)taosArrayRemove(pContext->pPendingCreateTableGids, 0); + if (taosArrayGetSize(pContext->pPendingCreateTableGids) > 0) { + SSTriggerPendingCreateTableEntry *pNext = + (SSTriggerPendingCreateTableEntry *)taosArrayGet(pContext->pPendingCreateTableGids, 0); + QUERY_CHECK_NULL(pNext, code, lino, _end, TSDB_CODE_INTERNAL_ERROR); + code = + stRealtimeContextSendPullReqForGid(pContext, pNext->pProgress, pNext->gid); + QUERY_CHECK_CODE(code, lino, _end); + } else { + taosArrayDestroy(pContext->pPendingCreateTableGids); + pContext->pPendingCreateTableGids = NULL; + if (--pContext->curReaderIdx > 0) { + goto _end; + } + pContext->boundDetermined = true; + pContext->status = STRIGGER_CONTEXT_IDLE; + code = stRealtimeContextCheck(pContext); + QUERY_CHECK_CODE(code, lino, _end); + } + break; + } switch (pContext->status) { case STRIGGER_CONTEXT_SEND_CALC_REQ: { SStreamGroupInfo groupInfo = {0}; diff --git a/source/libs/nodes/src/nodesCodeFuncs.c b/source/libs/nodes/src/nodesCodeFuncs.c index c01fc49b75f2..208553a64c8c 100644 --- a/source/libs/nodes/src/nodesCodeFuncs.c +++ b/source/libs/nodes/src/nodesCodeFuncs.c @@ -9409,6 +9409,7 @@ static const char* jkCreateStreamStmtQuery = "Query"; static const char* jkCreateStreamStmtTags = "Tags"; static const char* jkCreateStreamStmtSubtable = "Subtable"; static const char* jkCreateStreamStmtCols = "Cols"; +static const char* jkCreateStreamStmtNodelayCreateSubtable = "nodelayCreateSubtable"; static int32_t createStreamStmtToJson(const void* pObj, SJson* pJson) { const SCreateStreamStmt* pNode = (const SCreateStreamStmt*)pObj; @@ -9441,6 +9442,9 @@ static int32_t createStreamStmtToJson(const void* pObj, SJson* pJson) { if (TSDB_CODE_SUCCESS == code) { code = nodeListToJson(pJson, jkCreateStreamStmtCols, pNode->pCols); } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonAddIntegerToObject(pJson, jkCreateStreamStmtNodelayCreateSubtable, pNode->nodelayCreateSubtable); + } return code; } @@ -9475,6 +9479,9 @@ static int32_t jsonToCreateStreamStmt(const SJson* pJson, void* pObj) { if (TSDB_CODE_SUCCESS == code) { code = jsonToNodeList(pJson, jkCreateStreamStmtCols, &pNode->pCols); } + if (TSDB_CODE_SUCCESS == code) { + (void)tjsonGetTinyIntValue(pJson, jkCreateStreamStmtNodelayCreateSubtable, &pNode->nodelayCreateSubtable); + } return code; } diff --git a/source/libs/parser/inc/parAst.h b/source/libs/parser/inc/parAst.h index ac48ac615569..3ca11feb5127 100644 --- a/source/libs/parser/inc/parAst.h +++ b/source/libs/parser/inc/parAst.h @@ -477,7 +477,7 @@ SNode* createCreateStreamStmt(SAstCreateContext* pCxt, bool ignoreExists, SNode* SNode* pOutTable, SNode* pQuery); SNode* createRecalcRange(SAstCreateContext* pCxt, SNode* pStart, SNode* pEnd); SNode* createStreamOutTableNode(SAstCreateContext* pCxt, SNode* pIntoTable, SNode* pOutputSubTable, SNodeList* pColList, - SNodeList* pTagList); + SNodeList* pTagList, int32_t nodelayCreateSubtable); SNode* createStreamTriggerNode(SAstCreateContext* pCxt, SNode* pTriggerWindow, SNode* pTriggerTable, SNodeList* pPartitionList, SNode* pOptions, SNode* pNotification); SNode* createDropStreamStmt(SAstCreateContext* pCxt, bool ignoreNotExists, SNodeList* pStreamList); diff --git a/source/libs/parser/inc/sql.y b/source/libs/parser/inc/sql.y index a9c0271397d9..6f367652b75e 100755 --- a/source/libs/parser/inc/sql.y +++ b/source/libs/parser/inc/sql.y @@ -1521,8 +1521,12 @@ stream_name_list(A) ::= full_stream_name(B). stream_name_list(A) ::= stream_name_list(B) NK_COMMA full_stream_name(C). { A = addNodeToList(pCxt, B, C); } /********** stream_outtable **********/ +%type nodelay_create_subtable_opt { int32_t } +%destructor nodelay_create_subtable_opt { } +nodelay_create_subtable_opt(A) ::= . { A = 0; } +nodelay_create_subtable_opt(A) ::= NODELAY_CREATE_SUBTABLE. { A = 1; } stream_outtable_opt(A) ::= . { A = NULL; } -stream_outtable_opt(A) ::= INTO full_table_name(B) output_subtable_opt(C) column_name_opt(D) stream_tags_def_opt(E). { A = createStreamOutTableNode(pCxt, B, C, D, E); } +stream_outtable_opt(A) ::= INTO full_table_name(B) nodelay_create_subtable_opt(F) output_subtable_opt(C) column_name_opt(D) stream_tags_def_opt(E). { A = createStreamOutTableNode(pCxt, B, C, D, E, F); } /********** stream_trigger **********/ stream_trigger(A) ::= trigger_type(B) trigger_table_opt(C) stream_partition_by_opt(D) diff --git a/source/libs/parser/src/parAstCreater.c b/source/libs/parser/src/parAstCreater.c index c13a91a30b93..6a40354353b1 100644 --- a/source/libs/parser/src/parAstCreater.c +++ b/source/libs/parser/src/parAstCreater.c @@ -7029,7 +7029,7 @@ SNode* createDropViewStmt(SAstCreateContext* pCxt, bool ignoreNotExists, SNode* } SNode* createStreamOutTableNode(SAstCreateContext* pCxt, SNode* pIntoTable, SNode* pOutputSubTable, SNodeList* pColList, - SNodeList* pTagList) { + SNodeList* pTagList, int32_t nodelayCreateSubtable) { SStreamOutTableNode* pOutTable = NULL; CHECK_PARSER_STATUS(pCxt); pCxt->errCode = nodesMakeNode(QUERY_NODE_STREAM_OUT_TABLE, (SNode**)&pOutTable); @@ -7038,6 +7038,7 @@ SNode* createStreamOutTableNode(SAstCreateContext* pCxt, SNode* pIntoTable, SNod pOutTable->pSubtable = pOutputSubTable; pOutTable->pCols = pColList; pOutTable->pTags = pTagList; + pOutTable->nodelayCreateSubtable = (nodelayCreateSubtable != 0) ? 1 : 0; return (SNode*)pOutTable; _err: @@ -7363,6 +7364,7 @@ SNode* createCreateStreamStmt(SAstCreateContext* pCxt, bool ignoreExists, SNode* pStmt->pTags = pOutTable ? ((SStreamOutTableNode*)pOutTable)->pTags : NULL; pStmt->pSubtable = pOutTable ? ((SStreamOutTableNode*)pOutTable)->pSubtable : NULL; pStmt->pCols = pOutTable ? ((SStreamOutTableNode*)pOutTable)->pCols : NULL; + pStmt->nodelayCreateSubtable = pOutTable ? ((SStreamOutTableNode*)pOutTable)->nodelayCreateSubtable : 0; return (SNode*)pStmt; _err: nodesDestroyNode(pOutTable); diff --git a/source/libs/parser/src/parTokenizer.c b/source/libs/parser/src/parTokenizer.c index 7c78e7bb8057..39bf03752927 100644 --- a/source/libs/parser/src/parTokenizer.c +++ b/source/libs/parser/src/parTokenizer.c @@ -480,6 +480,7 @@ static SKeyword keywordTable[] = { {"XNODES", TK_XNODES}, {"DRAIN", TK_DRAIN}, {"REBALANCE", TK_REBALANCE}, + {"NODELAY_CREATE_SUBTABLE", TK_NODELAY_CREATE_SUBTABLE}, }; // clang-format on diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index 3d4c5d256276..2b63a5f341f2 100644 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -550,9 +550,9 @@ static int32_t insertCondIntoSelectStmt(SSelectStmt* pSelect, SNode** pCond); static int32_t extractCondFromCountWindow(STranslateContext* pCxt, SCountWindowNode* pCountWindow, SNode** pCond); static int32_t translateExprList(STranslateContext* pCxt, SNodeList* pList); static int32_t setCurrLevelNsFromParent(STranslateContext* pSrc, STranslateContext* pDst); -static bool getJoinContais(SNode* pNode); +static bool getJoinContais(SNode* pNode); static uint8_t getStmtPrecision(SNode* pStmt); -static bool stmtIsSingleTable(SNode* pStmt); +static bool stmtIsSingleTable(SNode* pStmt); static bool isWindowJoinStmt(SSelectStmt* pSelect) { return (QUERY_NODE_JOIN_TABLE == nodeType(pSelect->pFromTable)) && @@ -711,8 +711,8 @@ static int32_t rewriteDropTableWithMetaCache(STranslateContext* pCxt) { bool stopIterate = false; if (tbMetaSize > 0 || tbMetaExSize <= 0) { - parserError("QID:0x%" PRIx64 ", %s unexpected state, tbMetaSize:%d, tbMetaExSize:%d", - pParCxt->requestId, __func__ , tbMetaSize, tbMetaExSize); + parserError("QID:0x%" PRIx64 ", %s unexpected state, tbMetaSize:%d, tbMetaExSize:%d", pParCxt->requestId, __func__, + tbMetaSize, tbMetaExSize); PAR_ERR_JRET(TSDB_CODE_PAR_INTERNAL_ERROR); } if (!pMetaCache->pTableMeta && @@ -745,9 +745,9 @@ static int32_t rewriteDropTableWithMetaCache(STranslateContext* pCxt) { } tstrncpy(dbName, pDbStart + 1, pDbEnd - pDbStart); - int32_t metaSize = + int32_t metaSize = sizeof(STableMeta) + sizeof(SSchema) * (pMeta->tableInfo.numOfColumns + pMeta->tableInfo.numOfTags); - int32_t schemaExtSize = + int32_t schemaExtSize = (withExtSchema(pMeta->tableType) && pMeta->schemaExt) ? sizeof(SSchemaExt) * pMeta->tableInfo.numOfColumns : 0; int32_t colRefSize = (hasRefCol(pMeta->tableType) && pMeta->colRef) ? sizeof(SColRef) * pMeta->numOfColRefs : 0; const char* pTbName = (const char*)pMeta + metaSize + schemaExtSize + colRefSize; @@ -1113,7 +1113,8 @@ static void initStreamInfo(SParseStreamInfo* pInfo) { pInfo->triggerTbl = NULL; } -static int32_t initTranslateContext(SParseContext* pParseCxt, SParseMetaCache* pMetaCache, bool isSubCtx, STranslateContext* pCxt) { +static int32_t initTranslateContext(SParseContext* pParseCxt, SParseMetaCache* pMetaCache, bool isSubCtx, + STranslateContext* pCxt) { pCxt->pParseCxt = pParseCxt; pCxt->errCode = TSDB_CODE_SUCCESS; pCxt->msgBuf.buf = pParseCxt->pMsg; @@ -1430,7 +1431,8 @@ static int32_t isTimeLineAlignedQuery(SNode* pStmt, bool* pRes) { if (QUERY_NODE_SELECT_STMT == nodeType(((STempTableNode*)pSelect->pFromTable)->pSubquery)) { SSelectStmt* pSub = (SSelectStmt*)((STempTableNode*)pSelect->pFromTable)->pSubquery; if (pSelect->pPartitionByList) { - if (pSub->timeLineFromOrderBy == ORDER_UNKNOWN && nodesListMatch(pSelect->pPartitionByList, pSub->pPartitionByList)) { + if (pSub->timeLineFromOrderBy == ORDER_UNKNOWN && + nodesListMatch(pSelect->pPartitionByList, pSub->pPartitionByList)) { *pRes = true; return code; } @@ -1472,7 +1474,7 @@ static int32_t isTimeLineAlignedQuery(SNode* pStmt, bool* pRes) { } bool isPrimaryKeyImpl(SNode* pExpr) { - if(!pExpr) { + if (!pExpr) { return false; } if (QUERY_NODE_COLUMN == nodeType(pExpr)) { @@ -1684,11 +1686,12 @@ static SNodeList* getStreamTriggerPartition(STranslateContext* pCxt) { return pC static SNode* getStreamTriggerTable(STranslateContext* pCxt) { return pCxt->streamInfo.triggerTbl; } -static int32_t createColumnByRealTable(STranslateContext* pCxt, const STableNode* pTable, bool igTags, SNodeList* pList) { +static int32_t createColumnByRealTable(STranslateContext* pCxt, const STableNode* pTable, bool igTags, + SNodeList* pList) { int32_t code = TSDB_CODE_SUCCESS; SColumnNode* pCol = NULL; const STableMeta* pMeta = ((SRealTableNode*)pTable)->pMeta; - int32_t nums = pMeta->tableInfo.numOfColumns + + int32_t nums = pMeta->tableInfo.numOfColumns + (igTags ? 0 : ((TSDB_SUPER_TABLE == pMeta->tableType || ((SRealTableNode*)pTable)->stbRewrite) ? pMeta->tableInfo.numOfTags @@ -1715,8 +1718,8 @@ static int32_t createColumnByRealTable(STranslateContext* pCxt, const STableNode return code; } -static int32_t createColumnsByTempTable(STranslateContext* pCxt, const STableNode* pTable, bool igTags, SNodeList* pList, - bool skipProjRef) { +static int32_t createColumnsByTempTable(STranslateContext* pCxt, const STableNode* pTable, bool igTags, + SNodeList* pList, bool skipProjRef) { int32_t code = TSDB_CODE_SUCCESS; int32_t lino = 0; SColumnNode* pCol = NULL; @@ -1757,13 +1760,11 @@ static int32_t createColumnsByVirtualTable(STranslateContext* pCxt, const STable SColumnNode* pCol = NULL; SHashObj* pColRefMap = NULL; int32_t nums = pMeta->tableInfo.numOfColumns + - (igTags ? 0 - : (TSDB_SUPER_TABLE == pMeta->tableType - ? pMeta->tableInfo.numOfTags - : 0)); + (igTags ? 0 : (TSDB_SUPER_TABLE == pMeta->tableType ? pMeta->tableInfo.numOfTags : 0)); if (pMeta->numOfColRefs > 0 && pMeta->colRef) { - pColRefMap = taosHashInit(pMeta->numOfColRefs, taosGetDefaultHashFunction(TSDB_DATA_TYPE_SMALLINT), false, HASH_NO_LOCK); + pColRefMap = + taosHashInit(pMeta->numOfColRefs, taosGetDefaultHashFunction(TSDB_DATA_TYPE_SMALLINT), false, HASH_NO_LOCK); QUERY_CHECK_NULL(pColRefMap, code, lino, _return, terrno); for (int32_t i = 0; i < pMeta->numOfColRefs; ++i) { @@ -1942,8 +1943,8 @@ static int32_t findAndSetVirtualTableColumn(STranslateContext* pCxt, SColumnNode int32_t nums = pMeta->tableInfo.numOfTags + pMeta->tableInfo.numOfColumns; for (int32_t i = 0; i < nums; ++i) { if (0 == strcmp(pCol->colName, pMeta->schema[i].name)) { - setVtbColumnInfoBySchema((SVirtualTableNode*)pTable, pMeta->schema + i, (i - pMeta->tableInfo.numOfColumns), - NULL, pCol); + setVtbColumnInfoBySchema((SVirtualTableNode*)pTable, pMeta->schema + i, (i - pMeta->tableInfo.numOfColumns), NULL, + pCol); setColumnPrimTs(pCxt, pCol, pTable); *pFound = true; break; @@ -2044,9 +2045,7 @@ static EDealRes translateColumnWithPrefix(STranslateContext* pCxt, SColumnNode** /** translate column in tables without table prefix */ -static EDealRes translateColumnWithoutPrefix(STranslateContext* pCxt, - SColumnNode** pCol, - bool* pFound) { +static EDealRes translateColumnWithoutPrefix(STranslateContext* pCxt, SColumnNode** pCol, bool* pFound) { SArray* pTables = taosArrayGetP(pCxt->pNsLevel, pCxt->currLevel); size_t nums = taosArrayGetSize(pTables); bool isInternalPk = isInternalPrimaryKey(*pCol); @@ -2073,9 +2072,7 @@ static EDealRes translateColumnWithoutPrefix(STranslateContext* pCxt, return DEAL_RES_CONTINUE; } -static EDealRes translateSubQColumnWithoutPrefix(STranslateContext* pCxt, - SColumnNode** pCol, - bool* pFound) { +static EDealRes translateSubQColumnWithoutPrefix(STranslateContext* pCxt, SColumnNode** pCol, bool* pFound) { int32_t currLevel = pCxt->currLevel--; while (pCxt->currLevel >= 0) { EDealRes res = translateColumnWithoutPrefix(pCxt, pCol, pFound); @@ -2083,7 +2080,7 @@ static EDealRes translateSubQColumnWithoutPrefix(STranslateContext* pCxt, pCxt->currLevel = currLevel; return res; } - + if (false == *pFound) { pCxt->currLevel--; continue; @@ -2098,7 +2095,6 @@ static EDealRes translateSubQColumnWithoutPrefix(STranslateContext* pCxt, return DEAL_RES_CONTINUE; } - static int32_t getFuncInfo(STranslateContext* pCxt, SFunctionNode* pFunc); /** @@ -2125,9 +2121,11 @@ static EDealRes translateColumnUseAlias(STranslateContext* pCxt, SColumnNode** p } if (*pFound) { if (nodeType(pFoundNode) == QUERY_NODE_FUNCTION && fmIsPlaceHolderFunc(((SFunctionNode*)pFoundNode)->funcId)) { - if (pCxt->currClause != SQL_CLAUSE_WHERE && pCxt->currClause != SQL_CLAUSE_SELECT && pCxt->currClause != SQL_CLAUSE_ORDER_BY) { - pCxt->errCode = generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_STREAM_INVALID_PLACE_HOLDER, - "stream placeholder should only appear in select, where and order by clause"); + if (pCxt->currClause != SQL_CLAUSE_WHERE && pCxt->currClause != SQL_CLAUSE_SELECT && + pCxt->currClause != SQL_CLAUSE_ORDER_BY) { + pCxt->errCode = + generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_STREAM_INVALID_PLACE_HOLDER, + "stream placeholder should only appear in select, where and order by clause"); return DEAL_RES_ERROR; } } @@ -2406,15 +2404,12 @@ static EDealRes translateColumnInGroupByClause(STranslateContext* pCxt, SColumnN } if (!found && res != DEAL_RES_ERROR) { if (isInternalPrimaryKey(*pCol)) { - if (isSelectStmt(pCxt->pCurrStmt) && - NULL != ((SSelectStmt*)pCxt->pCurrStmt)->pWindow) { - return generateDealNodeErrMsg(pCxt, - TSDB_CODE_PAR_NOT_ALLOWED_WIN_QUERY); + if (isSelectStmt(pCxt->pCurrStmt) && NULL != ((SSelectStmt*)pCxt->pCurrStmt)->pWindow) { + return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_NOT_ALLOWED_WIN_QUERY); } return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_INVALID_INTERNAL_PK); } else { - return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_INVALID_COLUMN, - (*pCol)->colName); + return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_INVALID_COLUMN, (*pCol)->colName); } } } @@ -2463,9 +2458,7 @@ static EDealRes translateColumn(STranslateContext* pCxt, SColumnNode** pCol) { select list. If not found, then match them in all tables. */ bool alreadyCheckedAlias = false; - if (pCxt->currClause == SQL_CLAUSE_ORDER_BY && - isSelectStmt(pCxt->pCurrStmt) && - !(*pCol)->node.asParam) { + if (pCxt->currClause == SQL_CLAUSE_ORDER_BY && isSelectStmt(pCxt->pCurrStmt) && !(*pCol)->node.asParam) { res = translateColumnUseAlias(pCxt, pCol, &found); alreadyCheckedAlias = true; } @@ -2482,26 +2475,22 @@ static EDealRes translateColumn(STranslateContext* pCxt, SColumnNode** pCol) { For supported clauses, if column not found in all tables, try to match alias in select list. */ - if (!found && res != DEAL_RES_ERROR && clauseSupportAlias(pCxt->currClause) && - !alreadyCheckedAlias) { + if (!found && res != DEAL_RES_ERROR && clauseSupportAlias(pCxt->currClause) && !alreadyCheckedAlias) { res = translateColumnUseAlias(pCxt, pCol, &found); } if (!found && res != DEAL_RES_ERROR && pCxt->isExprSubQ) { res = translateSubQColumnWithoutPrefix(pCxt, pCol, &found); } - + if (!found && res != DEAL_RES_ERROR) { if (isInternalPrimaryKey(*pCol)) { - if (isSelectStmt(pCxt->pCurrStmt) && - NULL != ((SSelectStmt*)pCxt->pCurrStmt)->pWindow) { - return generateDealNodeErrMsg(pCxt, - TSDB_CODE_PAR_NOT_ALLOWED_WIN_QUERY); + if (isSelectStmt(pCxt->pCurrStmt) && NULL != ((SSelectStmt*)pCxt->pCurrStmt)->pWindow) { + return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_NOT_ALLOWED_WIN_QUERY); } return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_INVALID_INTERNAL_PK); } else { - return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_INVALID_COLUMN, - (*pCol)->colName); + return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_INVALID_COLUMN, (*pCol)->colName); } } @@ -2837,8 +2826,6 @@ static int32_t dataTypeComp(const SDataType* l, const SDataType* r) { return (l->precision == r->precision && l->scale == r->scale) ? 0 : 1; } - - static int32_t replaceExprSubQuery(STranslateContext* pCxt, SNode** pNode, SNode* pSubQuery, int32_t rewriteType) { int32_t code = TSDB_CODE_SUCCESS; @@ -2866,7 +2853,7 @@ static int32_t replaceExprSubQuery(STranslateContext* pCxt, SNode** pNode, SNode } *pNode = NULL; - + if (0 == rewriteType) { code = nodesMakeNode(QUERY_NODE_REMOTE_VALUE_LIST, pNode); if (TSDB_CODE_SUCCESS != code) { @@ -2934,13 +2921,14 @@ static int32_t getExprSubQRewriteType(EOperatorType opType, SNode* pSubq, ESubQR *pRes = E_SQ_REWRITE_TO_ZERO_ROWS; return TSDB_CODE_SUCCESS; } - + if (OP_TYPE_IN == opType || OP_TYPE_NOT_IN == opType) { *pRes = E_SQ_REWRITE_KEEP_REMAIN; return TSDB_CODE_SUCCESS; } - EQuantifyType quantifyType = (QUERY_NODE_SELECT_STMT == nodeType(pSubq)) ? ((SSelectStmt*)pSubq)->quantify : ((SSetOperator*)pSubq)->quantify; + EQuantifyType quantifyType = + (QUERY_NODE_SELECT_STMT == nodeType(pSubq)) ? ((SSelectStmt*)pSubq)->quantify : ((SSetOperator*)pSubq)->quantify; if (QU_TYPE_ANY != quantifyType && QU_TYPE_ALL != quantifyType) { parserError("invalid quantifyType %d for op [%s]'s subQ", quantifyType, operatorTypeStr(opType)); @@ -2948,7 +2936,7 @@ static int32_t getExprSubQRewriteType(EOperatorType opType, SNode* pSubq, ESubQR } switch (opType) { - case OP_TYPE_GREATER_THAN: + case OP_TYPE_GREATER_THAN: case OP_TYPE_GREATER_EQUAL: *pRes = (QU_TYPE_ANY == quantifyType) ? E_SQ_REWRITE_TO_MIN : E_SQ_REWRITE_TO_MAX; return TSDB_CODE_SUCCESS; @@ -2970,8 +2958,9 @@ static int32_t getExprSubQRewriteType(EOperatorType opType, SNode* pSubq, ESubQR return TSDB_CODE_PAR_INTERNAL_ERROR; } -static int32_t createSimpleSubQStmt(STranslateContext* pCxt, char* stmtName, SNodeList *pProjectionList, SNode* pSubQ, SSelectStmt **ppStmt) { - int32_t code = TSDB_CODE_SUCCESS; +static int32_t createSimpleSubQStmt(STranslateContext* pCxt, char* stmtName, SNodeList* pProjectionList, SNode* pSubQ, + SSelectStmt** ppStmt) { + int32_t code = TSDB_CODE_SUCCESS; STempTableNode* pTable = NULL; code = nodesMakeNode(QUERY_NODE_TEMP_TABLE, (SNode**)&pTable); if (TSDB_CODE_SUCCESS != code) { @@ -2980,9 +2969,9 @@ static int32_t createSimpleSubQStmt(STranslateContext* pCxt, char* stmtName, SNo } pTable->pSubquery = pSubQ; - + tstrncpy(pTable->table.tableAlias, stmtName, TSDB_TABLE_NAME_LEN); - + if (QUERY_NODE_SELECT_STMT == nodeType(pSubQ)) { ((SSelectStmt*)pSubQ)->isSubquery = true; } @@ -3031,25 +3020,26 @@ static int32_t createSimpleSubQStmt(STranslateContext* pCxt, char* stmtName, SNo cxt.pCurrStmt = (SNode*)pSelect; cxt.currClause = SQL_CLAUSE_SELECT; - + code = translateExprList(&cxt, pProjectionList); destroyTranslateContext(&cxt); if (TSDB_CODE_SUCCESS != code) { nodesDestroyNode((SNode*)pSelect); return code; } - + pSelect->selectFuncNum = 1; pSelect->hasAggFuncs = true; pSelect->hasSelectFunc = true; pSelect->hasSelectValFunc = true; - + return code; } -static int32_t createNewSubQProjectionList(STranslateContext* pCxt, char* stmtName, SNodeList *pSrcProjection, SNodeList** ppNew, bool isMin) { +static int32_t createNewSubQProjectionList(STranslateContext* pCxt, char* stmtName, SNodeList* pSrcProjection, + SNodeList** ppNew, bool isMin) { SFunctionNode* pFunc = NULL; - int32_t code = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&pFunc); + int32_t code = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&pFunc); if (TSDB_CODE_SUCCESS != code) { return code; } @@ -3058,7 +3048,7 @@ static int32_t createNewSubQProjectionList(STranslateContext* pCxt, char* stmtNa SColumnNode* pParam = createColumnByExpr(stmtName, (SExprNode*)pSrcProjection->pHead->pNode); if (NULL == pParam) { code = terrno; - nodesDestroyNode((SNode *)pFunc); + nodesDestroyNode((SNode*)pFunc); return code; } @@ -3067,8 +3057,8 @@ static int32_t createNewSubQProjectionList(STranslateContext* pCxt, char* stmtNa nodesDestroyNode((SNode*)pFunc); return code; } - - code = nodesListMakeStrictAppend(ppNew, (SNode *)pFunc); + + code = nodesListMakeStrictAppend(ppNew, (SNode*)pFunc); if (TSDB_CODE_SUCCESS != code) { return code; } @@ -3086,7 +3076,7 @@ static int32_t createNewSubQProjectionList(STranslateContext* pCxt, char* stmtNa return code; } - return nodesListMakeStrictAppend(ppNew, (SNode *)pFunc2); + return nodesListMakeStrictAppend(ppNew, (SNode*)pFunc2); } static int32_t rewriteExprSubQResToMinMax(STranslateContext* pCxt, SNode* pSubQuery, bool isMin) { @@ -3094,14 +3084,14 @@ static int32_t rewriteExprSubQResToMinMax(STranslateContext* pCxt, SNode* pSubQu if (TSDB_CODE_SUCCESS != code) { return code; } - + if (LIST_LENGTH(pCxt->pSubQueries) <= 0) { parserError("unexpected empty subQ list got"); return TSDB_CODE_PAR_INTERNAL_ERROR; } SNodeList* pProjection = NULL; - char* stmtName = NULL; + char* stmtName = NULL; SNodeList* pNewProjection = NULL; if (QUERY_NODE_SELECT_STMT == nodeType(pSubQuery)) { pProjection = ((SSelectStmt*)pSubQuery)->pProjectionList; @@ -3116,7 +3106,7 @@ static int32_t rewriteExprSubQResToMinMax(STranslateContext* pCxt, SNode* pSubQu nodesDestroyList(pNewProjection); return code; } - + SSelectStmt* pNewStmt = NULL; code = createSimpleSubQStmt(pCxt, stmtName, pNewProjection, pSubQuery, &pNewStmt); if (TSDB_CODE_SUCCESS != code) { @@ -3129,14 +3119,14 @@ static int32_t rewriteExprSubQResToMinMax(STranslateContext* pCxt, SNode* pSubQu pCxt->pSubQueries->pTail->pNode = (SNode*)pNewStmt; } else { parserError("translate context last subq %p is not expected %p", pCxt->pSubQueries->pTail->pNode, pSubQuery); - nodesDestroyNode((SNode *)pNewStmt); + nodesDestroyNode((SNode*)pNewStmt); } return code; } static int32_t doRewriteExprSubQuery(STranslateContext* pCxt, SOperatorNode* pOp, SNode** ppSubQ) { - ESubQRewriteType rewriteType; + ESubQRewriteType rewriteType; pCxt->errCode = getExprSubQRewriteType(pOp->opType, *ppSubQ, &rewriteType); if (TSDB_CODE_SUCCESS != pCxt->errCode) { return pCxt->errCode; @@ -3214,22 +3204,25 @@ static bool isValidSubQCompDataType(int32_t leftType, int32_t rightType, EOperat } if (TSDB_DATA_TYPE_JSON == rightType || TSDB_DATA_TYPE_JSON == leftType) { - parserError("not supported quantified compare types:%d, %d for op:%s", leftType, rightType, operatorTypeStr(opType)); + parserError("not supported quantified compare types:%d, %d for op:%s", leftType, rightType, + operatorTypeStr(opType)); return false; } - + if ((opType >= OP_TYPE_GREATER_THAN && opType <= OP_TYPE_LOWER_EQUAL) && - (TSDB_DATA_TYPE_BLOB == rightType || TSDB_DATA_TYPE_MEDIUMBLOB == rightType || TSDB_DATA_TYPE_GEOMETRY == rightType)) { - parserError("not supported quantified compare types:%d, %d for op:%s", leftType, rightType, operatorTypeStr(opType)); + (TSDB_DATA_TYPE_BLOB == rightType || TSDB_DATA_TYPE_MEDIUMBLOB == rightType || + TSDB_DATA_TYPE_GEOMETRY == rightType)) { + parserError("not supported quantified compare types:%d, %d for op:%s", leftType, rightType, + operatorTypeStr(opType)); return false; } - + return true; } static int32_t rewriteExprSubQuery(STranslateContext* pCxt, SOperatorNode* pOp) { switch (pOp->opType) { - case OP_TYPE_GREATER_THAN: + case OP_TYPE_GREATER_THAN: case OP_TYPE_GREATER_EQUAL: case OP_TYPE_LOWER_THAN: case OP_TYPE_LOWER_EQUAL: @@ -3238,7 +3231,8 @@ static int32_t rewriteExprSubQuery(STranslateContext* pCxt, SOperatorNode* pOp) case OP_TYPE_IN: case OP_TYPE_NOT_IN: { if (!isSubQueryNode(pOp->pRight)) { - parserError("pRight %d is not subQ in op %s, exprSubQType:%d", nodeType(pOp->pRight), operatorTypeStr(pOp->opType), pCxt->expSubQueryType); + parserError("pRight %d is not subQ in op %s, exprSubQType:%d", nodeType(pOp->pRight), + operatorTypeStr(pOp->opType), pCxt->expSubQueryType); pCxt->errCode = TSDB_CODE_PAR_INTERNAL_ERROR; break; } @@ -3253,14 +3247,15 @@ static int32_t rewriteExprSubQuery(STranslateContext* pCxt, SOperatorNode* pOp) pCxt->errCode = TSDB_CODE_SCALAR_CONVERT_ERROR; break; } - + pCxt->errCode = doRewriteExprSubQuery(pCxt, pOp, &pOp->pRight); break; } case OP_TYPE_EXISTS: case OP_TYPE_NOT_EXISTS: { if (!isSubQueryNode(pOp->pLeft)) { - parserError("pLeft %d is not subQ in op %s, exprSubQType:%d", nodeType(pOp->pLeft), operatorTypeStr(pOp->opType), pCxt->expSubQueryType); + parserError("pLeft %d is not subQ in op %s, exprSubQType:%d", nodeType(pOp->pLeft), + operatorTypeStr(pOp->opType), pCxt->expSubQueryType); pCxt->errCode = TSDB_CODE_PAR_INTERNAL_ERROR; break; } @@ -3270,7 +3265,7 @@ static int32_t rewriteExprSubQuery(STranslateContext* pCxt, SOperatorNode* pOp) pCxt->errCode = TSDB_CODE_PAR_INTERNAL_ERROR; break; } - + pCxt->errCode = doRewriteExprSubQuery(pCxt, pOp, &pOp->pLeft); break; } @@ -3303,7 +3298,7 @@ static EDealRes translateOperator(STranslateContext* pCxt, SOperatorNode* pOp) { if (TSDB_CODE_SUCCESS == code) { code = scalarGetOperatorResultType(pOp); } - + if (TSDB_CODE_SUCCESS != code) { pCxt->errCode = code; return DEAL_RES_ERROR; @@ -3514,7 +3509,8 @@ static int32_t getFuncInfo(STranslateContext* pCxt, SFunctionNode* pFunc) { code = getUdfInfo(pCxt, pFunc); } if (TSDB_CODE_MND_FUNC_NOT_EXIST == code) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_MND_FUNC_NOT_EXIST, "function '%s' is not defined", pFunc->functionName); + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_MND_FUNC_NOT_EXIST, "function '%s' is not defined", + pFunc->functionName); } return code; } @@ -3532,7 +3528,8 @@ static int32_t translateAggFunc(STranslateContext* pCxt, SFunctionNode* pFunc) { // The auto-generated COUNT function in the DELETE statement is legal if (isSelectStmt(pCxt->pCurrStmt) && (((SSelectStmt*)pCxt->pCurrStmt)->hasIndefiniteRowsFunc || ((SSelectStmt*)pCxt->pCurrStmt)->hasMultiRowsFunc)) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, "Aggregate func '%s' mixed with other multi-row functions", pFunc->functionName); + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, + "Aggregate func '%s' mixed with other multi-row functions", pFunc->functionName); } if (isCountStar(pFunc)) { @@ -3552,23 +3549,28 @@ static int32_t translateIndefiniteRowsFunc(STranslateContext* pCxt, SFunctionNod return TSDB_CODE_SUCCESS; } if (!isSelectStmt(pCxt->pCurrStmt) || SQL_CLAUSE_SELECT != pCxt->currClause) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, "Indefinite rows function '%s' only allowed in select clause", pFunc->functionName); + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, + "Indefinite rows function '%s' only allowed in select clause", pFunc->functionName); } SSelectStmt* pSelect = (SSelectStmt*)pCxt->pCurrStmt; if (pSelect->hasAggFuncs || pSelect->hasMultiRowsFunc) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, "Indefinite rows function '%s' mixed with other multi-row functions", pFunc->functionName); + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, + "Indefinite rows function '%s' mixed with other multi-row functions", + pFunc->functionName); } if (pSelect->hasIndefiniteRowsFunc && (FUNC_RETURN_ROWS_INDEFINITE == pSelect->returnRows || pSelect->returnRows != fmGetFuncReturnRows(pFunc)) && (pSelect->lastProcessByRowFuncId == -1 || !fmIsProcessByRowFunc(pFunc->funcId))) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, "Multiple indefinite rows functions with different return rows"); + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, + "Multiple indefinite rows functions with different return rows"); } if (pSelect->lastProcessByRowFuncId != -1 && pSelect->lastProcessByRowFuncId != pFunc->funcId) { return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_DIFFERENT_BY_ROW_FUNC); } if (NULL != pSelect->pWindow || NULL != pSelect->pGroupByList) { return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, - "Function '%s' is not supported in window query or group query", pFunc->functionName); + "Function '%s' is not supported in window query or group query", + pFunc->functionName); } if (hasInvalidFuncNesting(pFunc)) { return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AGG_FUNC_NESTING); @@ -3583,7 +3585,8 @@ static int32_t translateMultiRowsFunc(STranslateContext* pCxt, SFunctionNode* pF if (!isSelectStmt(pCxt->pCurrStmt) || SQL_CLAUSE_SELECT != pCxt->currClause || ((SSelectStmt*)pCxt->pCurrStmt)->hasIndefiniteRowsFunc || ((SSelectStmt*)pCxt->pCurrStmt)->hasAggFuncs || ((SSelectStmt*)pCxt->pCurrStmt)->hasMultiRowsFunc) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, "Multi-rows function '%s' only allowed in select clause", pFunc->functionName); + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, + "Multi-rows function '%s' only allowed in select clause", pFunc->functionName); } if (hasInvalidFuncNesting(pFunc)) { return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AGG_FUNC_NESTING); @@ -3598,25 +3601,32 @@ static int32_t translateInterpFunc(STranslateContext* pCxt, SFunctionNode* pFunc if (!isSelectStmt(pCxt->pCurrStmt) || (SQL_CLAUSE_SELECT != pCxt->currClause && SQL_CLAUSE_ORDER_BY != pCxt->currClause)) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, "Interp function '%s' only allowed in select or order by clause", pFunc->functionName); + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, + "Interp function '%s' only allowed in select or order by clause", + pFunc->functionName); } SSelectStmt* pSelect = (SSelectStmt*)pCxt->pCurrStmt; SNode* pTable = pSelect->pFromTable; if (pSelect->hasAggFuncs || pSelect->hasMultiRowsFunc || pSelect->hasIndefiniteRowsFunc) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, "Interp function '%s' is not allowed with aggregate, multi-rows, or indefinite rows functions", pFunc->functionName); + return generateSyntaxErrMsgExt( + &pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, + "Interp function '%s' is not allowed with aggregate, multi-rows, or indefinite rows functions", + pFunc->functionName); } if (pSelect->hasInterpFunc && (FUNC_RETURN_ROWS_INDEFINITE == pSelect->returnRows || pSelect->returnRows != fmGetFuncReturnRows(pFunc))) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, - "Function '%s' ignoring null value options cannot be used when applying to multiple columns", - pFunc->functionName); + return generateSyntaxErrMsgExt( + &pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, + "Function '%s' ignoring null value options cannot be used when applying to multiple columns", + pFunc->functionName); } if (NULL != pSelect->pWindow || NULL != pSelect->pGroupByList) { return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, - "Function '%s' is not supported in window query or group query", pFunc->functionName); + "Function '%s' is not supported in window query or group query", + pFunc->functionName); } if (hasInvalidFuncNesting(pFunc)) { return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AGG_FUNC_NESTING); @@ -3664,25 +3674,31 @@ static int32_t translateForecastFunc(STranslateContext* pCxt, SFunctionNode* pFu return TSDB_CODE_SUCCESS; } if (!isSelectStmt(pCxt->pCurrStmt) || SQL_CLAUSE_SELECT != pCxt->currClause) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, "Forecast function '%s' only allowed in select clause", pFunc->functionName); + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, + "Forecast function '%s' only allowed in select clause", pFunc->functionName); } SSelectStmt* pSelect = (SSelectStmt*)pCxt->pCurrStmt; SNode* pTable = pSelect->pFromTable; if (pSelect->hasAggFuncs || pSelect->hasMultiRowsFunc || pSelect->hasIndefiniteRowsFunc) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, "Forecast function '%s' is not allowed with aggregate, multi-rows, or indefinite rows functions", pFunc->functionName); + return generateSyntaxErrMsgExt( + &pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, + "Forecast function '%s' is not allowed with aggregate, multi-rows, or indefinite rows functions", + pFunc->functionName); } if (pSelect->hasForecastFunc && (FUNC_RETURN_ROWS_INDEFINITE == pSelect->returnRows || pSelect->returnRows != fmGetFuncReturnRows(pFunc))) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, - "Forecast function '%s' ignoring null value options cannot be used when applying to multiple columns", - pFunc->functionName); + return generateSyntaxErrMsgExt( + &pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, + "Forecast function '%s' ignoring null value options cannot be used when applying to multiple columns", + pFunc->functionName); } if (NULL != pSelect->pWindow || NULL != pSelect->pGroupByList) { return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, - "Forecast function '%s' is not supported in window query or group query", pFunc->functionName); + "Forecast function '%s' is not supported in window query or group query", + pFunc->functionName); } if (hasInvalidFuncNesting(pFunc)) { return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AGG_FUNC_NESTING); @@ -3707,8 +3723,8 @@ static int32_t translateAnalysisPseudoColumnFunc(STranslateContext* pCxt, SNode* } if (pCxt->currClause == SQL_CLAUSE_WHERE) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, "Function '%s' is not allowed in where clause", - pFunc->functionName); + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, + "Function '%s' is not allowed in where clause", pFunc->functionName); } FOREACH(pNode, pSelect->pProjectionList) { @@ -3825,7 +3841,8 @@ static EDealRes translatePlaceHolderFunc(STranslateContext* pCxt, SNode** pFunc) "stream placeholder should only appear in create stream's query part")); } - if (pCxt->currClause != SQL_CLAUSE_SELECT && pCxt->currClause != SQL_CLAUSE_WHERE && pCxt->currClause != SQL_CLAUSE_ORDER_BY) { + if (pCxt->currClause != SQL_CLAUSE_SELECT && pCxt->currClause != SQL_CLAUSE_WHERE && + pCxt->currClause != SQL_CLAUSE_ORDER_BY) { PAR_ERR_JRET(generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_STREAM_INVALID_PLACE_HOLDER, "stream placeholder should only appear in select, where and order by clause")); } @@ -4486,8 +4503,8 @@ static int32_t rewriteClientPseudoColumnFunc(STranslateContext* pCxt, SNode** pN default: break; } - return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_FUNC_FUNTION_ERROR, - "%s get invalid funcType: %d", ((SFunctionNode*)*pNode)->functionName, ((SFunctionNode*)*pNode)->funcType); + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_FUNC_FUNTION_ERROR, "%s get invalid funcType: %d", + ((SFunctionNode*)*pNode)->functionName, ((SFunctionNode*)*pNode)->funcType); } static int32_t translateFunctionImpl(STranslateContext* pCxt, SFunctionNode** pFunc) { @@ -4551,7 +4568,7 @@ static EDealRes translateFunction(STranslateContext* pCxt, SFunctionNode** pFunc static int32_t updateSubQResType(SNode* pNode) { int32_t code = TSDB_CODE_SUCCESS; - + switch (nodeType(pNode)) { case QUERY_NODE_SELECT_STMT: { SSelectStmt* pSelect = (SSelectStmt*)pNode; @@ -4592,7 +4609,7 @@ static EDealRes translateExprSubquery(STranslateContext* pCxt, SNode** pNode) { if (TSDB_CODE_SUCCESS == pCxt->errCode && E_SUB_QUERY_COLUMN == pCxt->expSubQueryType) { pCxt->errCode = updateSubQResType(*pNode); } - + return (TSDB_CODE_SUCCESS == pCxt->errCode) ? DEAL_RES_CONTINUE : DEAL_RES_ERROR; } @@ -5275,7 +5292,8 @@ static EDealRes doCheckAggColCoexist(SNode** pNode, void* pContext) { } if ((isScanPseudoColumnFunc(*pNode) || QUERY_NODE_COLUMN == nodeType(*pNode)) && ((!nodesIsExprNode(*pNode) || !isRelatedToOtherExpr((SExprNode*)*pNode)))) { - if (!pCxt->existColName) pCxt->existColName = getExistColName(*pNode); // Return the first disallowed column name as a prompt + if (!pCxt->existColName) + pCxt->existColName = getExistColName(*pNode); // Return the first disallowed column name as a prompt pCxt->existCol = true; } return DEAL_RES_CONTINUE; @@ -5288,7 +5306,8 @@ static EDealRes doCheckGetAggColCoexist(SNode** pNode, void* pContext) { return DEAL_RES_IGNORE_CHILD; } if (isScanPseudoColumnFunc(*pNode) || QUERY_NODE_COLUMN == nodeType(*pNode)) { - if (!pCxt->existColName) pCxt->existColName = getExistColName(*pNode); // Return the first disallowed column name as a prompt + if (!pCxt->existColName) + pCxt->existColName = getExistColName(*pNode); // Return the first disallowed column name as a prompt pCxt->existCol = true; code = nodesListMakeStrictAppend(&pCxt->pColList, *pNode); if (TSDB_CODE_SUCCESS != code) { @@ -6341,11 +6360,11 @@ static int32_t makeVtableMetaScanTable(STranslateContext* pCxt, SRealTableNode** static int32_t translateVirtualSuperTable(STranslateContext* pCxt, SNode** pTable, SName* pName, SVirtualTableNode* pVTable) { - SRealTableNode* pRealTable = (SRealTableNode*)*pTable; - STableMeta* pMeta = pRealTable->pMeta; - int32_t code = TSDB_CODE_SUCCESS; - SRealTableNode* pInsCols = NULL; - bool refTablesAdded = false; + SRealTableNode* pRealTable = (SRealTableNode*)*pTable; + STableMeta* pMeta = pRealTable->pMeta; + int32_t code = TSDB_CODE_SUCCESS; + SRealTableNode* pInsCols = NULL; + bool refTablesAdded = false; if (!pMeta->virtualStb) { PAR_ERR_JRET(TSDB_CODE_PAR_INVALID_TABLE_TYPE); @@ -6486,8 +6505,8 @@ static int32_t translateVirtualNormalChildTable(STranslateContext* pCxt, SNode** // table scan node is eliminated. const SSchema* pTsSchema = &pMeta->schema[0]; const SSchema* pRefTsSchema = &pRTNode->pMeta->schema[0]; - PAR_ERR_JRET(setColRef(&pMeta->colRef[0], pTsSchema->colId, NULL, (char*)pRefTsSchema->name, pRTNode->table.tableName, - pRTNode->table.dbName)); + PAR_ERR_JRET(setColRef(&pMeta->colRef[0], pTsSchema->colId, NULL, (char*)pRefTsSchema->name, + pRTNode->table.tableName, pRTNode->table.dbName)); } } nodesDestroyNode(*pTable); @@ -6863,7 +6882,7 @@ static bool isVirtualSTable(STableMeta* meta) { return meta->virtualStb; } static int32_t transSetSysDbPrivs(STranslateContext* pCxt, const char* qualDbName) { #ifdef TD_ENTERPRISE - SParseContext* pParCxt = pCxt->pParseCxt; + SParseContext* pParCxt = pCxt->pParseCxt; SGetUserAuthRsp authRsp = {0}; SRequestConnInfo conn = {.pTrans = pParCxt->pTransporter, .requestId = pParCxt->requestId, @@ -7439,7 +7458,7 @@ static int32_t prepareColumnExpansion(STranslateContext* pCxt, ESqlClause clause } static EDealRes checkAggFuncExist(SNode* pNode, void* found) { - if(isAggFunc(pNode)) { + if (isAggFunc(pNode)) { *(bool*)found = true; return DEAL_RES_END; } @@ -7517,21 +7536,16 @@ static int32_t convertFillValue(STranslateContext* pCxt, SDataType dt, SNodeList return code; } -static int32_t doCheckFillValues(STranslateContext* pCxt, SFillNode* pFill, - SNodeList* pProjectionList) { +static int32_t doCheckFillValues(STranslateContext* pCxt, SFillNode* pFill, SNodeList* pProjectionList) { int32_t fillNo = 0; SNodeListNode* pFillValues = (SNodeListNode*)pFill->pValues; SNode* pProject = NULL; FOREACH(pProject, pProjectionList) { if (needFill(pProject)) { - if (NULL == pFillValues || - fillNo >= LIST_LENGTH(pFillValues->pNodeList)) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, - TSDB_CODE_PAR_WRONG_VALUE_TYPE, - "Too few fill values specified"); - } - int32_t code = convertFillValue(pCxt, ((SExprNode*)pProject)->resType, - pFillValues->pNodeList, fillNo); + if (NULL == pFillValues || fillNo >= LIST_LENGTH(pFillValues->pNodeList)) { + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_WRONG_VALUE_TYPE, "Too few fill values specified"); + } + int32_t code = convertFillValue(pCxt, ((SExprNode*)pProject)->resType, pFillValues->pNodeList, fillNo); if (TSDB_CODE_SUCCESS != code) { return code; } @@ -7541,15 +7555,12 @@ static int32_t doCheckFillValues(STranslateContext* pCxt, SFillNode* pFill, } if (NULL != pFillValues && fillNo != LIST_LENGTH(pFillValues->pNodeList)) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, - TSDB_CODE_PAR_WRONG_VALUE_TYPE, - "Too many fill values specified"); + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_WRONG_VALUE_TYPE, "Too many fill values specified"); } return TSDB_CODE_SUCCESS; } -static int32_t checkFillValues(STranslateContext* pCxt, SFillNode* pFill, - SSelectStmt* pSelect) { +static int32_t checkFillValues(STranslateContext* pCxt, SFillNode* pFill, SSelectStmt* pSelect) { /* Do check fill values if: - FILL MODE is VALUE or VALUE_F @@ -7565,16 +7576,14 @@ static int32_t checkFillValues(STranslateContext* pCxt, SFillNode* pFill, static int32_t translateFillValues(STranslateContext* pCxt, SSelectStmt* pSelect) { SFillNode* pFill = NULL; - if (NULL != pSelect->pWindow && - QUERY_NODE_INTERVAL_WINDOW == nodeType(pSelect->pWindow) && + if (NULL != pSelect->pWindow && QUERY_NODE_INTERVAL_WINDOW == nodeType(pSelect->pWindow) && NULL != ((SIntervalWindowNode*)pSelect->pWindow)->pFill) { pFill = (SFillNode*)((SIntervalWindowNode*)pSelect->pWindow)->pFill; } else if (pSelect->hasInterpFunc && NULL != pSelect->pFill) { pFill = (SFillNode*)pSelect->pFill; } - return NULL == pFill ? TSDB_CODE_SUCCESS : - checkFillValues(pCxt, pFill, pSelect); + return NULL == pFill ? TSDB_CODE_SUCCESS : checkFillValues(pCxt, pFill, pSelect); } static int32_t rewriteProjectAlias(SNodeList* pProjectionList) { @@ -7884,9 +7893,7 @@ static int32_t translateProcessMaskColFunc(STranslateContext* pCxt, SSelectStmt* SCatalog* pCatalog = pParseCxt->pCatalog; SNode* pNode = NULL; - FOREACH(pNode, pSelect->pProjectionList) { - (void)rewriteMaskColFunc(pCxt, pSelect, &pNode); - } + FOREACH(pNode, pSelect->pProjectionList) { (void)rewriteMaskColFunc(pCxt, pSelect, &pNode); } #endif return TSDB_CODE_SUCCESS; } @@ -8262,25 +8269,21 @@ static int32_t getQueryTimeRange(STranslateContext* pCxt, SNode** pWhere, STimeW return code; } -static int32_t translateSurroundingTime(STranslateContext* pCxt, - SNode* pSurroundingTime) { +static int32_t translateSurroundingTime(STranslateContext* pCxt, SNode* pSurroundingTime) { if (pSurroundingTime != NULL) { const SValueNode* pSurroundingTimeVal = (SValueNode*)pSurroundingTime; if (pSurroundingTimeVal->flag & VALUE_FLAG_IS_DURATION) { if (pSurroundingTimeVal->datum.i <= 0) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, - TSDB_CODE_PAR_INVALID_SURROUND_TIME_VALUES, - "Surrounding time value must be greater than 0"); + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_SURROUND_TIME_VALUES, + "Surrounding time value must be greater than 0"); } int8_t unit = pSurroundingTimeVal->unit; if (unit == TIME_UNIT_YEAR || unit == TIME_UNIT_MONTH) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, - TSDB_CODE_PAR_INVALID_SURROUND_TIME_VALUES, - "Unsupported time unit in surrounding time: %c", unit); + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_SURROUND_TIME_VALUES, + "Unsupported time unit in surrounding time: %c", unit); } } else { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, - TSDB_CODE_PAR_INVALID_SURROUND_TIME_VALUES, + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_SURROUND_TIME_VALUES, "Surrounding time value must be a " "duration expression"); } @@ -8339,18 +8342,16 @@ static int32_t checkFill(STranslateContext* pCxt, SFillNode* pFill, SValueNode* return TSDB_CODE_SUCCESS; } -static int32_t translateFill(STranslateContext* pCxt, SSelectStmt* pSelect, - SIntervalWindowNode* pInterval) { +static int32_t translateFill(STranslateContext* pCxt, SSelectStmt* pSelect, SIntervalWindowNode* pInterval) { if (NULL == pInterval->pFill) { return TSDB_CODE_SUCCESS; } - + SFillNode* pFill = (SFillNode*)pInterval->pFill; pFill->timeRange = pSelect->timeRange; PAR_ERR_RET(nodesCloneNode(pSelect->pTimeRange, &pFill->pTimeRange)); PAR_ERR_RET(translateSurroundingTime(pCxt, pFill->pSurroundingTime)); - return checkFill(pCxt, pFill, (SValueNode*)pInterval->pInterval, false, - pSelect->precision); + return checkFill(pCxt, pFill, (SValueNode*)pInterval->pInterval, false, pSelect->precision); } static int32_t getMonthsFromTimeVal(int64_t val, int32_t fromPrecision, char unit, double* pMonth) { @@ -8459,7 +8460,7 @@ static int32_t checkIntervalWindow(STranslateContext* pCxt, SIntervalWindowNode* return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INTER_OFFSET_TOO_BIG); } if (!fixed) { - double offsetMonth = 0, intervalMonth = 0; + double offsetMonth = 0, intervalMonth = 0; code = getMonthsFromTimeVal(pOffset->datum.i, precision, pOffset->unit, &offsetMonth); TAOS_CHECK_GOTO(code, &lino, _exit); @@ -8490,7 +8491,7 @@ static int32_t checkIntervalWindow(STranslateContext* pCxt, SIntervalWindowNode* } if (valInter) { if (IS_CALENDAR_TIME_DURATION(pSliding->unit)) { - double slidingMonth = 0, intervalMonth = 0; + double slidingMonth = 0, intervalMonth = 0; code = getMonthsFromTimeVal(pSliding->datum.i, precision, pSliding->unit, &slidingMonth); TAOS_CHECK_GOTO(code, &lino, _exit); @@ -8500,8 +8501,7 @@ static int32_t checkIntervalWindow(STranslateContext* pCxt, SIntervalWindowNode* if (slidingMonth > intervalMonth) { return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INTER_SLIDING_TOO_BIG); } - } - else { + } else { int64_t interverNano = 0, slidingNano = 0; code = convertCalendarTimeFromUnitToPrecision(pInter->datum.i, pInter->unit, precision, &interverNano); TAOS_CHECK_GOTO(code, &lino, _exit); @@ -8522,23 +8522,18 @@ static int32_t checkIntervalWindow(STranslateContext* pCxt, SIntervalWindowNode* if (NULL != pInterval->pFill) { SFillNode* pFill = (SFillNode*)pInterval->pFill; if (pFill->mode == FILL_MODE_NEAR) { - return generateSyntaxErrMsg(&pCxt->msgBuf, - TSDB_CODE_PAR_NOT_ALLOWED_FILL_MODE); + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FILL_MODE); } - if (pFill->pValues != NULL && - !(pFill->mode == FILL_MODE_VALUE || pFill->mode == FILL_MODE_VALUE_F) && - !((pFill->mode == FILL_MODE_PREV || pFill->mode == FILL_MODE_NEXT) && - pFill->pSurroundingTime != NULL)) { - return generateSyntaxErrMsg(&pCxt->msgBuf, - TSDB_CODE_PAR_NOT_ALLOWED_FILL_VALUES); + if (pFill->pValues != NULL && !(pFill->mode == FILL_MODE_VALUE || pFill->mode == FILL_MODE_VALUE_F) && + !((pFill->mode == FILL_MODE_PREV || pFill->mode == FILL_MODE_NEXT) && pFill->pSurroundingTime != NULL)) { + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FILL_VALUES); } if (pFill->pSurroundingTime != NULL) { const SValueNode* pSurroundingTime = (SValueNode*)pFill->pSurroundingTime; if (pSurroundingTime->datum.i < pInter->datum.i) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, - TSDB_CODE_PAR_INVALID_SURROUND_TIME_VALUES, - "Surrounding time cannot be less than interval size: %ld%s", - pInter->datum.i, getPrecisionStr(precision)); + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_SURROUND_TIME_VALUES, + "Surrounding time cannot be less than interval size: %ld%s", pInter->datum.i, + getPrecisionStr(precision)); } } } @@ -9053,17 +9048,17 @@ static int32_t translateCountWindow(STranslateContext* pCxt, SSelectStmt* pSelec } static int32_t checkAnomalyExpr(STranslateContext* pCxt, SNodeList* pNodeList) { - for(int32_t i = 0; i < pNodeList->length; ++i) { - SNode* pNode = nodesListGetNode(pNodeList, i); + for (int32_t i = 0; i < pNodeList->length; ++i) { + SNode* pNode = nodesListGetNode(pNodeList, i); int32_t type = ((SExprNode*)pNode)->resType.type; if (!IS_MATHABLE_TYPE(type)) { return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_ANOMALY_WIN_TYPE, - "ANOMALY_WINDOW only support mathable column"); + "ANOMALY_WINDOW only support mathable column"); } if (QUERY_NODE_COLUMN == nodeType(pNode) && COLUMN_TYPE_TAG == ((SColumnNode*)pNode)->colType) { return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_ANOMALY_WIN_COL, - "ANOMALY_WINDOW not support on tag column"); + "ANOMALY_WINDOW not support on tag column"); } } @@ -9266,26 +9261,20 @@ static int32_t translateInterpFill(STranslateContext* pCxt, SSelectStmt* pSelect code = translateExpr(pCxt, (SNode**)&pFill); } if (TSDB_CODE_SUCCESS == code) { - code = getQueryTimeRange(pCxt, &pSelect->pRange, &pFill->timeRange, - &pFill->pTimeRange, pSelect->pFromTable); + code = getQueryTimeRange(pCxt, &pSelect->pRange, &pFill->timeRange, &pFill->pTimeRange, pSelect->pFromTable); } if (TSDB_CODE_SUCCESS == code) { code = translateSurroundingTime(pCxt, pFill->pSurroundingTime); } if (TSDB_CODE_SUCCESS == code) { - code = checkFill(pCxt, pFill, (SValueNode*)pSelect->pEvery, true, - pSelect->precision); + code = checkFill(pCxt, pFill, (SValueNode*)pSelect->pEvery, true, pSelect->precision); } QUERY_CHECK_CODE(code, lino, _end); bool hasRowTsOriginFunc = false; - nodesWalkExprs(pSelect->pProjectionList, hasRowTsOriginFuncWalkNode, - &hasRowTsOriginFunc); - bool isPrevNextNear = pFill->mode == FILL_MODE_PREV || - pFill->mode == FILL_MODE_NEXT || - pFill->mode == FILL_MODE_NEAR; + nodesWalkExprs(pSelect->pProjectionList, hasRowTsOriginFuncWalkNode, &hasRowTsOriginFunc); + bool isPrevNextNear = pFill->mode == FILL_MODE_PREV || pFill->mode == FILL_MODE_NEXT || pFill->mode == FILL_MODE_NEAR; if (hasRowTsOriginFunc && !isPrevNextNear) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, - TSDB_CODE_PAR_FILL_NOT_ALLOWED_FUNC, + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_FILL_NOT_ALLOWED_FUNC, "_irowts_origin can only be used with " "FILL PREV/NEXT/NEAR"); } @@ -9293,24 +9282,20 @@ static int32_t translateInterpFill(STranslateContext* pCxt, SSelectStmt* pSelect const SNode* pSurroundingTime = pFill->pSurroundingTime; const SNode* pRangeAround = pSelect->pRangeAround; if (NULL != pSurroundingTime && NULL != pRangeAround) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, - TSDB_CODE_PAR_INVALID_SURROUND_TIME_VALUES, + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_SURROUND_TIME_VALUES, "Surrounding time and range interval " "cannot be provided together"); } bool isSurround = NULL != pSurroundingTime || NULL != pRangeAround; if (isSurround && !isPrevNextNear) { /* Only PREV/NEXT/NEAR mode is supported with surrounding time */ - return generateSyntaxErrMsgExt(&pCxt->msgBuf, - TSDB_CODE_PAR_INVALID_SURROUND_TIME_VALUES, + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_SURROUND_TIME_VALUES, "Only PREV/NEXT/NEAR mode is supported with " "surrounding time"); } - if (pFill->pValues != NULL && - !(pFill->mode == FILL_MODE_VALUE || pFill->mode == FILL_MODE_VALUE_F) && + if (pFill->pValues != NULL && !(pFill->mode == FILL_MODE_VALUE || pFill->mode == FILL_MODE_VALUE_F) && !(isPrevNextNear && isSurround)) { - return generateSyntaxErrMsg(&pCxt->msgBuf, - TSDB_CODE_PAR_NOT_ALLOWED_FILL_VALUES); + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FILL_VALUES); } _end: @@ -10067,7 +10052,8 @@ static int32_t createPkColByTable(STranslateContext* pCxt, SRealTableNode* pTabl bool found = false; PAR_ERR_JRET(findAndSetColumn(pCxt, &pCol, (STableNode*)pTable, &found, true)); if (!found) { - PAR_ERR_JRET(generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_COLUMN, "failed to find PK column in table %s", pTable->table.tableName)); + PAR_ERR_JRET(generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_COLUMN, + "failed to find PK column in table %s", pTable->table.tableName)); } *pPk = (SNode*)pCol; return code; @@ -10199,11 +10185,12 @@ static void resetResultTimeline(STranslateContext* pCxt, SSelectStmt* pSelect) { if (NULL == pSelect->pOrderByList) { if (inStreamCalcClause(pCxt)) { SNode* pNode = nodesListGetNode(pSelect->pProjectionList, 0); - if (pNode && QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsPlaceHolderFunc(((SFunctionNode*)pNode)->funcId) && isPrimaryKeyImpl(pNode)) { + if (pNode && QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsPlaceHolderFunc(((SFunctionNode*)pNode)->funcId) && + isPrimaryKeyImpl(pNode)) { pSelect->timeLineResMode = TIME_LINE_GLOBAL; } } - + return; } SNode* pOrder = ((SOrderByExprNode*)nodesListGetNode(pSelect->pOrderByList, 0))->pExpr; @@ -11006,7 +10993,7 @@ static int32_t translateInsertProject(STranslateContext* pCxt, SInsertStmt* pIns int16_t numOfBoundPKs = 0; FORBOTH(pBoundCol, pInsert->pCols, pProj, pProjects) { if (QUERY_NODE_FUNCTION == nodeType(pBoundCol)) { - if(!IS_STR_DATA_TYPE(((SExprNode*)pProj)->resType.type)){ + if (!IS_STR_DATA_TYPE(((SExprNode*)pProj)->resType.type)) { return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_TBNAME, "tbname must be a string type"); } continue; @@ -12275,7 +12262,6 @@ static int32_t translateTrimDbWal(STranslateContext* pCxt, STrimDbWalStmt* pStmt return buildCmdMsg(pCxt, TDMT_MND_TRIM_DB_WAL, (FSerializeFunc)tSerializeSTrimDbReq, &req); } - static int32_t translateCreateToken(STranslateContext* pCxt, SCreateTokenStmt* pStmt) { SCreateTokenReq req = {0}; @@ -12292,7 +12278,6 @@ static int32_t translateCreateToken(STranslateContext* pCxt, SCreateTokenStmt* p return code; } - static int32_t translateAlterToken(STranslateContext* pCxt, SAlterTokenStmt* pStmt) { SAlterTokenReq req = {0}; STokenOptions* opts = pStmt->pTokenOptions; @@ -12317,7 +12302,6 @@ static int32_t translateAlterToken(STranslateContext* pCxt, SAlterTokenStmt* pSt return code; } - static int32_t translateDropToken(STranslateContext* pCxt, SDropTokenStmt* pStmt) { SDropTokenReq req = {0}; tstrncpy(req.name, pStmt->name, sizeof(req.name)); @@ -12857,7 +12841,8 @@ static int32_t checkTableSchemaImpl(STranslateContext* pCxt, SNodeList* pTags, S } static int32_t checkTableSchema(STranslateContext* pCxt, SCreateTableStmt* pStmt) { - return checkTableSchemaImpl(pCxt, pStmt->pTags, pStmt->pCols, pStmt->pOptions->pRollupFuncs, true, pStmt->pOptions->virtualStb); + return checkTableSchemaImpl(pCxt, pStmt->pTags, pStmt->pCols, pStmt->pOptions->pRollupFuncs, true, + pStmt->pOptions->virtualStb); } static int32_t checkVTableSchema(STranslateContext* pCxt, SCreateVTableStmt* pStmt) { @@ -13992,7 +13977,7 @@ static int32_t translateCreateUser(STranslateContext* pCxt, SCreateUserStmt* pSt SCreateUserReq createReq = {0}; #ifdef TD_ENTERPRISE - if((code = translateCheckUserOptsPriv(pCxt, pStmt, &pStmt->userOps, false))) { + if ((code = translateCheckUserOptsPriv(pCxt, pStmt, &pStmt->userOps, false))) { return code; } #endif @@ -14077,14 +14062,13 @@ static int32_t translateCreateEncryptAlgr(STranslateContext* pCxt, SCreateEncryp return code; } - static int32_t translateAlterUser(STranslateContext* pCxt, SAlterUserStmt* pStmt) { int32_t code = 0; SAlterUserReq alterReq = {0}; SUserOptions* opts = pStmt->pUserOptions; #ifdef TD_ENTERPRISE - if((code = translateCheckUserOptsPriv(pCxt, pStmt, opts, true))) { + if ((code = translateCheckUserOptsPriv(pCxt, pStmt, opts, true))) { return code; } #endif @@ -14144,13 +14128,13 @@ static int32_t translateAlterUser(STranslateContext* pCxt, SAlterUserStmt* pStmt alterReq.numTimeRanges = LIST_LENGTH(opts->pTimeRanges); alterReq.numDropIpRanges = LIST_LENGTH(opts->pDropIpRanges); alterReq.numDropTimeRanges = LIST_LENGTH(opts->pDropTimeRanges); -if (alterReq.numIpRanges > 0) { + if (alterReq.numIpRanges > 0) { alterReq.pIpRanges = taosMemoryMalloc(alterReq.numIpRanges * sizeof(SIpRange)); if (!alterReq.pIpRanges) { tFreeSAlterUserReq(&alterReq); return terrno; } - int i = 0; + int i = 0; SNode* pNode = NULL; FOREACH(pNode, opts->pIpRanges) { SIpRangeNode* node = (SIpRangeNode*)(pNode); @@ -14164,7 +14148,7 @@ if (alterReq.numIpRanges > 0) { tFreeSAlterUserReq(&alterReq); return terrno; } - int i = 0; + int i = 0; SNode* pNode = NULL; FOREACH(pNode, opts->pTimeRanges) { SDateTimeRangeNode* node = (SDateTimeRangeNode*)(pNode); @@ -14178,7 +14162,7 @@ if (alterReq.numIpRanges > 0) { tFreeSAlterUserReq(&alterReq); return terrno; } - int i = 0; + int i = 0; SNode* pNode = NULL; FOREACH(pNode, opts->pDropIpRanges) { SIpRangeNode* node = (SIpRangeNode*)(pNode); @@ -14192,7 +14176,7 @@ if (alterReq.numIpRanges > 0) { tFreeSAlterUserReq(&alterReq); return terrno; } - int i = 0; + int i = 0; SNode* pNode = NULL; FOREACH(pNode, opts->pDropTimeRanges) { SDateTimeRangeNode* node = (SDateTimeRangeNode*)(pNode); @@ -14205,8 +14189,6 @@ if (alterReq.numIpRanges > 0) { return code; } - - static int32_t translateDropUser(STranslateContext* pCxt, SDropUserStmt* pStmt) { SDropUserReq dropReq = {0}; tstrncpy(dropReq.user, pStmt->userName, TSDB_USER_LEN); @@ -14484,8 +14466,7 @@ static int32_t translateCreateXnodeTask(STranslateContext* pCxt, SCreateXnodeTas } } - code = - buildCmdMsg(pCxt, TDMT_MND_CREATE_XNODE_TASK, (FSerializeFunc)tSerializeSMCreateXnodeTaskReq, &createReq); + code = buildCmdMsg(pCxt, TDMT_MND_CREATE_XNODE_TASK, (FSerializeFunc)tSerializeSMCreateXnodeTaskReq, &createReq); tFreeSMCreateXnodeTaskReq(&createReq); return code; } @@ -14568,14 +14549,15 @@ static int32_t translateUpdateXnodeTask(STranslateContext* pCxt, SUpdateXnodeTas } } - int32_t code = buildCmdMsg(pCxt, TDMT_MND_UPDATE_XNODE_TASK, (FSerializeFunc)tSerializeSMUpdateXnodeTaskReq, &updateReq); + int32_t code = + buildCmdMsg(pCxt, TDMT_MND_UPDATE_XNODE_TASK, (FSerializeFunc)tSerializeSMUpdateXnodeTaskReq, &updateReq); tFreeSMUpdateXnodeTaskReq(&updateReq); return code; } static int32_t translateCreateXnodeJob(STranslateContext* pCxt, SCreateXnodeJobStmt* pStmt) { SMCreateXnodeJobReq createReq = {0}; - const char* config = getXnodeTaskOptionByName(pStmt->options, "config"); + const char* config = getXnodeTaskOptionByName(pStmt->options, "config"); if (config == NULL) { return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_MND_XNODE_JOB_SYNTAX_ERROR, "Missing option: config"); } @@ -14594,7 +14576,8 @@ static int32_t translateCreateXnodeJob(STranslateContext* pCxt, SCreateXnodeJobS const char* status = getXnodeTaskOptionByName(pStmt->options, "status"); if (status != NULL) { if (strlen(status) > TSDB_XNODE_STATUS_LEN) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_MND_XNODE_JOB_SYNTAX_ERROR, "Invalid option: status too long"); + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_MND_XNODE_JOB_SYNTAX_ERROR, + "Invalid option: status too long"); } createReq.status = xCreateCowStr(strlen(status), status, false); } @@ -14708,10 +14691,10 @@ bool isXnodeSupportNodeType(SNode* pWhere) { } static int32_t translateRebalanceXnodeJobWhere(STranslateContext* pCxt, SRebalanceXnodeJobWhereStmt* pStmt) { - int32_t code = 0; + int32_t code = 0; SMRebalanceXnodeJobsWhereReq rebalanceReq = {0}; char* pAst = NULL; - int32_t astLen = 0; + int32_t astLen = 0; if (pStmt->pWhere != NULL) { TAOS_CHECK_GOTO(nodesNodeToString(pStmt->pWhere, true, &pAst, &astLen), NULL, _exit); @@ -15164,7 +15147,7 @@ static int32_t buildCreateTopicReq(STranslateContext* pCxt, SCreateTopicStmt* pS snprintf(pReq->name, sizeof(pReq->name), "%d.%s", pCxt->pParseCxt->acctId, pStmt->topicName); pReq->igExists = pStmt->ignoreExists; pReq->withMeta = pStmt->withMeta; - pReq->reload = pStmt->reload; + pReq->reload = pStmt->reload; pReq->sql = taosStrdup(pCxt->pParseCxt->pSql); if (NULL == pReq->sql) { @@ -15196,7 +15179,7 @@ static int32_t buildCreateTopicReq(STranslateContext* pCxt, SCreateTopicStmt* pS pCxt->pParseCxt->topicQuery = true; code = translateQuery(pCxt, pStmt->pQuery); } - if (TSDB_CODE_SUCCESS == code && realTable->pMeta != NULL && realTable->pMeta->tableType == TSDB_SUPER_TABLE){ + if (TSDB_CODE_SUCCESS == code && realTable->pMeta != NULL && realTable->pMeta->tableType == TSDB_SUPER_TABLE) { code = tNameExtractFullName(&name, pReq->subStbName); } if (TSDB_CODE_SUCCESS == code) { @@ -16579,6 +16562,7 @@ static int32_t createStreamReqBuildOutTable(STranslateContext* pCxt, SCreateStre PAR_ERR_JRET(createStreamReqBuildOutSubtable( pCxt, pStmt->streamDbName, pStmt->streamName, pStmt->targetDbName, pStmt->targetTabName, pStmt->pSubtable, pTriggerSlotHash, ((SStreamTriggerNode*)pStmt->pTrigger)->pPartitionList, (char**)&pReq->subTblNameExpr)); + pReq->nodelayCreateSubtable = pStmt->nodelayCreateSubtable; _return: @@ -16635,7 +16619,7 @@ static int64_t createStreamReqWindowGetBigInt(SNode* pVal) { return pVal ? ((SVa static int8_t createStreamReqWindowGetUnit(SNode* pVal) { return pVal ? ((SValueNode*)pVal)->unit : 0; } -static void createStreamReqGetTrueForOptions(SNode *pVal, int32_t *pType, int32_t *pCount, int64_t *pDuration) { +static void createStreamReqGetTrueForOptions(SNode* pVal, int32_t* pType, int32_t* pCount, int64_t* pDuration) { if (pVal == NULL) { *pType = 0; *pCount = 0; @@ -16648,7 +16632,7 @@ static void createStreamReqGetTrueForOptions(SNode *pVal, int32_t *pType, int32_ STrueForNode* pTrueFor = (STrueForNode*)pVal; *pType = pTrueFor->trueForType; *pCount = pTrueFor->count; - *pDuration = pTrueFor->pDuration ? ((SValueNode *)pTrueFor->pDuration)->datum.i : 0; + *pDuration = pTrueFor->pDuration ? ((SValueNode*)pTrueFor->pDuration)->datum.i : 0; } } @@ -17106,7 +17090,6 @@ static int32_t createStreamReqBuildForceOutput(STranslateContext* pCxt, SCreateS parserError("createStreamReqBuildForceOutput failed, code:%d", code); nodesDestroyNode((SNode*)pVal); return code; - } static int32_t extractCondFromCountWindow(STranslateContext* pCxt, SCountWindowNode* pCountWindow, SNode** pCond) { @@ -17165,7 +17148,8 @@ static int32_t createSimpleSelectStmtImpl(const char* pDb, const char* pTable, S static int32_t createSimpleSelectStmtFromCols(const char* pDb, const char* pTable, int32_t numOfProjs, const char* const pProjCol[], SSelectStmt** pStmt); // build trigger select list in create stream request -static int32_t createStreamReqBuildTriggerSelect(STranslateContext* pCxt, SRealTableNode* pTriggerTable, SSelectStmt** pTriggerSelect, SCreateStreamStmt* pStmt) { +static int32_t createStreamReqBuildTriggerSelect(STranslateContext* pCxt, SRealTableNode* pTriggerTable, + SSelectStmt** pTriggerSelect, SCreateStreamStmt* pStmt) { int32_t code = TSDB_CODE_SUCCESS; SFunctionNode* pFunc = NULL; SStreamTriggerNode* pTrigger = (SStreamTriggerNode*)pStmt->pTrigger; @@ -17174,9 +17158,11 @@ static int32_t createStreamReqBuildTriggerSelect(STranslateContext* pCxt, SRealT if (pOptions) { pPreFilter = pOptions->pPreFilter; } - PAR_ERR_JRET(createSimpleSelectStmtImpl(pTriggerTable->table.dbName, pTriggerTable->table.tableName, NULL, pTriggerSelect)); + PAR_ERR_JRET( + createSimpleSelectStmtImpl(pTriggerTable->table.dbName, pTriggerTable->table.tableName, NULL, pTriggerSelect)); // only collect columns appeared in trigger and tags in pre-filter - PAR_ERR_JRET(nodesCollectColumnsFromNode(pStmt->pTrigger, NULL, COLLECT_COL_TYPE_COL, &((SSelectStmt*)*pTriggerSelect)->pProjectionList)); + PAR_ERR_JRET(nodesCollectColumnsFromNode(pStmt->pTrigger, NULL, COLLECT_COL_TYPE_COL, + &((SSelectStmt*)*pTriggerSelect)->pProjectionList)); if (pPreFilter) { PAR_ERR_JRET(nodesCollectColumnsFromNode(pPreFilter, NULL, COLLECT_COL_TYPE_TAG, &((SSelectStmt*)*pTriggerSelect)->pProjectionList)); @@ -17190,7 +17176,6 @@ static int32_t createStreamReqBuildTriggerSelect(STranslateContext* pCxt, SRealT nodesDestroyNode((SNode*)pFunc); parserError("%s failed, code:%d", __func__, code); return code; - } // Do the translation of trigger select statement in create stream request @@ -17309,7 +17294,8 @@ static int32_t createStreamReqBuildTriggerTranslateWindow(STranslateContext* pCx } // Translate trigger partition in create stream request -static int32_t createStreamReqBuildTriggerTranslatePartition(STranslateContext* pCxt, SNodeList* pTriggerPartition, STableMeta* pTriggerTableMeta, SNode* pTriggerWindow) { +static int32_t createStreamReqBuildTriggerTranslatePartition(STranslateContext* pCxt, SNodeList* pTriggerPartition, + STableMeta* pTriggerTableMeta, SNode* pTriggerWindow) { int32_t code = TSDB_CODE_SUCCESS; pCxt->currClause = SQL_CLAUSE_PARTITION_BY; @@ -17560,7 +17546,8 @@ static int32_t translateStreamCalcQuery(STranslateContext* pCxt, SNodeList* pTri pCxt->streamInfo.calcClause = true; pCxt->pCurrStmt = (SNode*)pStreamCalcQuery; - // if stream has notification condition, add this condition to query's select list, so that we can use this column's value to judge whether to send notify later + // if stream has notification condition, add this condition to query's select list, so that we can use this column's + // value to judge whether to send notify later if (pNotifyCond) { SCheckNotifyCondContext checkNotifyCondCxt = {.pTransCxt = pCxt, .valid = true}; nodesRewriteExpr(&pNotifyCond, doCheckNotifyCond, &checkNotifyCondCxt); @@ -17646,8 +17633,8 @@ static int32_t createStreamReqBuildCalcDb(STranslateContext* pCxt, SHashObj* pDb } // Build calculation plan in create stream request -static int32_t createStreamReqBuildCalcPlan(STranslateContext* pCxt, SQueryPlan* calcPlan, - SArray* pScanPlanArray, SCMCreateStreamReq* pReq) { +static int32_t createStreamReqBuildCalcPlan(STranslateContext* pCxt, SQueryPlan* calcPlan, SArray* pScanPlanArray, + SCMCreateStreamReq* pReq) { int32_t code = TSDB_CODE_SUCCESS; SHashObj* pPlanMap = NULL; SStreamCalcScan* pCalcScan = NULL; @@ -17663,8 +17650,8 @@ static int32_t createStreamReqBuildCalcPlan(STranslateContext* pCxt, SQueryPlan* pReq->calcTsSlotId = -1; pReq->calcPkSlotId = -1; - // traverse all scan plans in calculation plan, split them from their parents, and make a fake value node to replace them. - // value node's value is the scan plan's (groupId << 32 | subplanId). + // traverse all scan plans in calculation plan, split them from their parents, and make a fake value node to replace + // them. value node's value is the scan plan's (groupId << 32 | subplanId). for (int32_t i = 0; i < taosArrayGetSize(pScanPlanArray); i++) { pCalcScan = taosArrayGet(pScanPlanArray, i); if (pCalcScan == NULL) { @@ -17747,14 +17734,14 @@ static int32_t createStreamReqBuildCalcPlan(STranslateContext* pCxt, SQueryPlan* } // Build calculate part in create stream request -static int32_t createStreamReqBuildCalc(STranslateContext* pCxt, SCreateStreamStmt* pStmt, - SNodeList *pTriggerPartition, SSelectStmt* pTriggerSelect, SNode* pTriggerWindow, SNode* pNotifyCond, +static int32_t createStreamReqBuildCalc(STranslateContext* pCxt, SCreateStreamStmt* pStmt, SNodeList* pTriggerPartition, + SSelectStmt* pTriggerSelect, SNode* pTriggerWindow, SNode* pNotifyCond, SCMCreateStreamReq* pReq) { - int32_t code = TSDB_CODE_SUCCESS; - SQueryPlan* calcPlan = NULL; - SArray* pScanPlanArray = NULL; - SHashObj* pDbs = NULL; - SNodeList* pProjectionList = NULL; + int32_t code = TSDB_CODE_SUCCESS; + SQueryPlan* calcPlan = NULL; + SArray* pScanPlanArray = NULL; + SHashObj* pDbs = NULL; + SNodeList* pProjectionList = NULL; parserDebug("translate create stream req start build calculate part, streamId:%" PRId64, pReq->streamId); @@ -17845,7 +17832,8 @@ static int32_t createStreamReqBuildCalc(STranslateContext* pCxt, SCreateStreamSt } // build default fields of create stream request -static int32_t createStreamReqBuildDefaultReq(STranslateContext* pCxt, SCreateStreamStmt* pStmt, SCMCreateStreamReq* pReq) { +static int32_t createStreamReqBuildDefaultReq(STranslateContext* pCxt, SCreateStreamStmt* pStmt, + SCMCreateStreamReq* pReq) { int32_t code = TSDB_CODE_SUCCESS; pReq->expiredTime = 0; @@ -17867,12 +17855,14 @@ static int32_t createStreamReqBuildDefaultReq(STranslateContext* pCxt, SCreateSt pReq->calcTsSlotId = -1; pReq->triPkSlotId = -1; pReq->calcPkSlotId = -1; + pReq->nodelayCreateSubtable = 0; return TSDB_CODE_SUCCESS; } // build stream name and id -static int32_t createStreamReqBuildNameAndId(STranslateContext* pCxt, SCreateStreamStmt* pStmt, SCMCreateStreamReq* pReq) { +static int32_t createStreamReqBuildNameAndId(STranslateContext* pCxt, SCreateStreamStmt* pStmt, + SCMCreateStreamReq* pReq) { int32_t code = TSDB_CODE_SUCCESS; SName streamName; @@ -17918,7 +17908,8 @@ static int32_t buildCreateStreamReq(STranslateContext* pCxt, SCreateStreamStmt* PAR_ERR_JRET(createStreamReqBuildDefaultReq(pCxt, pStmt, pReq)); PAR_ERR_JRET(createStreamReqBuildNameAndId(pCxt, pStmt, pReq)); PAR_ERR_JRET(createStreamReqBuildNotifyOptions(pCxt, pNotifyOptions, &pNotifyCond, pReq)); - // Split build AST and build plan into two steps, because trigger's select list may depend on stream's calculation part. + // Split build AST and build plan into two steps, because trigger's select list may depend on stream's calculation + // part. PAR_ERR_JRET(createStreamReqBuildTriggerAst(pCxt, pStmt, &pTriggerSelect, &pTriggerSlotHash, &pTriggerFilter, pReq)); PAR_ERR_JRET(createStreamReqBuildTriggerOptions(pCxt, pStmt, pTriggerOptions, pReq)); PAR_ERR_JRET(createStreamReqBuildCalc(pCxt, pStmt, pTrigger->pPartitionList, pTriggerSelect, pTriggerWindow, @@ -17970,8 +17961,8 @@ static int32_t translateDropStream(STranslateContext* pCxt, SDropStreamStmt* pSt int32_t i = 0; FOREACH(pStream, pStmt->pStreamList) { - SName name; - SStreamNode* pStreamNode = (SStreamNode*)pStream; + SName name; + SStreamNode* pStreamNode = (SStreamNode*)pStream; toName(pCxt->pParseCxt->acctId, pStreamNode->dbName, pStreamNode->streamName, &name); req.name[i] = taosMemoryCalloc(1, TSDB_STREAM_FNAME_LEN); @@ -18504,9 +18495,12 @@ static int32_t translateGrantFillColPrivileges(STranslateContext* pCxt, SGrantSt "Only ALTER, DROP, SHOW or SHOW CREATE table privilege can be granted on child table")); } - TAOS_CHECK_EXIT(fillPrivSetRowCols(pCxt, &pReqArgs->selectCols, pTableMeta, (SNodeList*)pPrivSetArgs->selectCols, false)); - TAOS_CHECK_EXIT(fillPrivSetRowCols(pCxt, &pReqArgs->insertCols, pTableMeta, (SNodeList*)pPrivSetArgs->insertCols, true)); - TAOS_CHECK_EXIT(fillPrivSetRowCols(pCxt, &pReqArgs->updateCols, pTableMeta, (SNodeList*)pPrivSetArgs->updateCols, true)); + TAOS_CHECK_EXIT( + fillPrivSetRowCols(pCxt, &pReqArgs->selectCols, pTableMeta, (SNodeList*)pPrivSetArgs->selectCols, false)); + TAOS_CHECK_EXIT( + fillPrivSetRowCols(pCxt, &pReqArgs->insertCols, pTableMeta, (SNodeList*)pPrivSetArgs->insertCols, true)); + TAOS_CHECK_EXIT( + fillPrivSetRowCols(pCxt, &pReqArgs->updateCols, pTableMeta, (SNodeList*)pPrivSetArgs->updateCols, true)); } _exit: @@ -18516,7 +18510,7 @@ static int32_t translateGrantFillColPrivileges(STranslateContext* pCxt, SGrantSt } static int32_t translateGrantCheckFillObject(STranslateContext* pCxt, SGrantStmt* pStmt, EPrivCategory category, - SAlterRoleReq* pReq, bool grant) { + SAlterRoleReq* pReq, bool grant) { SName name = {0}; STableMeta* pTableMeta = NULL; int32_t code = 0, lino = 0; @@ -18601,19 +18595,19 @@ static int32_t translateGrantCheckFillObject(STranslateContext* pCxt, SGrantStmt if (0 != pStmt->tabName[0]) { // not validate the object when revoke if (grant && (strncmp(pStmt->tabName, "*", 2) != 0)) { - SName name = {0}; - STableMeta* pTableMeta = NULL; - toName(pCxt->pParseCxt->acctId, pStmt->objName, pStmt->tabName, &name); - code = getTargetMeta(pCxt, &name, &pTableMeta, true); - if (TSDB_CODE_SUCCESS != code) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_GET_META_ERROR, "%s", tstrerror(code)); - } - if (((PRIV_OBJ_TBL == objType) && (TSDB_VIEW_TABLE == pTableMeta->tableType)) || - ((PRIV_OBJ_VIEW == objType) && (TSDB_VIEW_TABLE != pTableMeta->tableType))) { - taosMemoryFree(pTableMeta); - TAOS_RETURN(TSDB_CODE_PAR_PRIV_TYPE_TARGET_CONFLICT); - } + SName name = {0}; + STableMeta* pTableMeta = NULL; + toName(pCxt->pParseCxt->acctId, pStmt->objName, pStmt->tabName, &name); + code = getTargetMeta(pCxt, &name, &pTableMeta, true); + if (TSDB_CODE_SUCCESS != code) { + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_GET_META_ERROR, "%s", tstrerror(code)); + } + if (((PRIV_OBJ_TBL == objType) && (TSDB_VIEW_TABLE == pTableMeta->tableType)) || + ((PRIV_OBJ_VIEW == objType) && (TSDB_VIEW_TABLE != pTableMeta->tableType))) { taosMemoryFree(pTableMeta); + TAOS_RETURN(TSDB_CODE_PAR_PRIV_TYPE_TARGET_CONFLICT); + } + taosMemoryFree(pTableMeta); } } else { return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_SYNTAX_ERROR, @@ -18669,10 +18663,10 @@ static int32_t translateGrantCheckFillObject(STranslateContext* pCxt, SGrantStmt } _exit: if (code == TSDB_CODE_SUCCESS) { - if(pStmt->objName[0] != 0) { + if (pStmt->objName[0] != 0) { (void)snprintf(pReq->objFName, sizeof(pReq->objFName), "%d.%s", pCxt->pParseCxt->acctId, pStmt->objName); } - if(pStmt->tabName[0] != 0) { + if (pStmt->tabName[0] != 0) { (void)snprintf(pReq->tblName, sizeof(pReq->tblName), "%s", pStmt->tabName); } } @@ -18698,7 +18692,7 @@ static int32_t translateGrantRevoke(STranslateContext* pCxt, SGrantStmt* pStmt, EPrivCategory category = PRIV_CATEGORY_UNKNOWN; EPrivObjType objType = pStmt->privileges.objType; uint8_t objLevel = privObjGetLevel(objType); - SPrivSet tmpPrivSet = pStmt->privileges.privSet; // for conflict check + SPrivSet tmpPrivSet = pStmt->privileges.privSet; // for conflict check EPrivType conflict0 = PRIV_TYPE_UNKNOWN, conflict1 = PRIV_TYPE_UNKNOWN; if (objType <= PRIV_OBJ_UNKNOWN || objType >= PRIV_OBJ_MAX) { @@ -18805,12 +18799,12 @@ static int32_t translateGrantRevoke(STranslateContext* pCxt, SGrantStmt* pStmt, } } else if (conflict != 0) { return generateSyntaxErrMsg(&pCxt->msgBuf, conflict); - } else if(pStmt->pCond != NULL && objType != PRIV_OBJ_TBL) { + } else if (pStmt->pCond != NULL && objType != PRIV_OBJ_TBL) { return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_SYNTAX_ERROR, "The With clause can only be used for table privileges"); } req.privileges.privSet = pStmt->privileges.privSet; // assign the privileges - if(objType == PRIV_OBJ_VIEW) { // rewrite query for view to improve usability + if (objType == PRIV_OBJ_VIEW) { // rewrite query for view to improve usability if (PRIV_HAS(&req.privileges.privSet, PRIV_TBL_SELECT)) { privAddType(&req.privileges.privSet, PRIV_VIEW_SELECT); privRemoveType(&req.privileges.privSet, PRIV_TBL_SELECT); @@ -19010,7 +19004,7 @@ static int32_t translateShowCreateView(STranslateContext* pCxt, SShowCreateViewS return TSDB_CODE_OPS_NOT_SUPPORT; #else int32_t code = 0, lino = 0; - SName name = {0}; + SName name = {0}; toName(pCxt->pParseCxt->acctId, pStmt->dbName, pStmt->viewName, &name); TAOS_CHECK_EXIT(getViewMetaFromMetaCache(pCxt, &name, (SViewMeta**)&pStmt->pViewMeta)); if (!pStmt->hasPrivilege) { @@ -20679,14 +20673,14 @@ void updateContextFromSubQ(STranslateContext* pCxt, SNode* pNode, STranslateCont return; } - static int32_t mergeTranslateContextMetas(STranslateContext* pCxt, STranslateContext* pSrc) { int32_t code = TSDB_CODE_SUCCESS; if (NULL != pSrc->pDbs) { SFullDatabaseName* pDb = taosHashIterate(pSrc->pDbs, NULL); while (NULL != pDb) { - code = taosHashPut(pCxt->pDbs, pDb->fullDbName, strlen(pDb->fullDbName), pDb->fullDbName, sizeof(pDb->fullDbName)); + code = + taosHashPut(pCxt->pDbs, pDb->fullDbName, strlen(pDb->fullDbName), pDb->fullDbName, sizeof(pDb->fullDbName)); if (code && code != TSDB_CODE_DUP_KEY) { taosHashCancelIterate(pSrc->pDbs, pDb); return code; @@ -20735,7 +20729,7 @@ static int32_t mergeTranslateContextMetas(STranslateContext* pCxt, STranslateCon } static int32_t translateTableSubquery(STranslateContext* pCxt, SNode* pNode) { - int32_t code = TSDB_CODE_SUCCESS; + int32_t code = TSDB_CODE_SUCCESS; ESqlClause currClause = pCxt->currClause; SNode* pCurrStmt = pCxt->pCurrStmt; @@ -20752,7 +20746,7 @@ static int32_t translateTableSubquery(STranslateContext* pCxt, SNode* pNode) { } static int32_t translateExprSubqueryImpl(STranslateContext* pCxt, SNode* pNode) { - int32_t code = TSDB_CODE_SUCCESS; + int32_t code = TSDB_CODE_SUCCESS; STranslateContext cxt = {0}; cxt.isExprSubQ = true; @@ -20782,12 +20776,12 @@ static int32_t translateExprSubqueryImpl(STranslateContext* pCxt, SNode* pNode) parserError("Correlated subQuery not supported now"); code = TSDB_CODE_PAR_INVALID_EXPR_SUBQ; } -/* - if (pCxt->hasLocalSubQ) { - parserError("Only query with FROM supported now"); - code = TSDB_CODE_PAR_INVALID_EXPR_SUBQ; - } -*/ + /* + if (pCxt->hasLocalSubQ) { + parserError("Only query with FROM supported now"); + code = TSDB_CODE_PAR_INVALID_EXPR_SUBQ; + } + */ return code; } @@ -22069,9 +22063,9 @@ static int32_t buildVirtualTableBatchReq(STranslateContext* pCxt, const SCreateV SSchema* pSchema = req.ntb.schemaRow.pSchema + index; toSchema(pColDef, index + 1, pSchema); if (pColDef->pOptions && ((SColumnOptions*)pColDef->pOptions)->hasRef) { - PAR_ERR_JRET(setColRef(&req.colRef.pColRef[index], index + 1, NULL, ((SColumnOptions*)pColDef->pOptions)->refColumn, - ((SColumnOptions*)pColDef->pOptions)->refTable, - ((SColumnOptions*)pColDef->pOptions)->refDb)); + PAR_ERR_JRET( + setColRef(&req.colRef.pColRef[index], index + 1, NULL, ((SColumnOptions*)pColDef->pOptions)->refColumn, + ((SColumnOptions*)pColDef->pOptions)->refTable, ((SColumnOptions*)pColDef->pOptions)->refDb)); } ++index; } @@ -22124,16 +22118,16 @@ static int32_t buildVirtualSubTableBatchReq(const SCreateVSubTableStmt* pStmt, S PAR_ERR_JRET(TSDB_CODE_PAR_INVALID_COLUMN); } const SSchema* pSchema = getTableColumnSchema(pStbMeta) + schemaIdx; - PAR_ERR_JRET(setColRef(&req.colRef.pColRef[schemaIdx], pSchema->colId, pSchema->name, pColRef->refColName, pColRef->refTableName, - pColRef->refDbName)); + PAR_ERR_JRET(setColRef(&req.colRef.pColRef[schemaIdx], pSchema->colId, pSchema->name, pColRef->refColName, + pColRef->refTableName, pColRef->refDbName)); } } else if (pStmt->pColRefs) { col_id_t index = 1; // start from second column, don't set column ref for ts column FOREACH(pCol, pStmt->pColRefs) { SColumnRefNode* pColRef = (SColumnRefNode*)pCol; - const SSchema* pSchema = getTableColumnSchema(pStbMeta) + index; - PAR_ERR_JRET(setColRef(&req.colRef.pColRef[index], index + 1, pSchema->name, pColRef->refColName, pColRef->refTableName, - pColRef->refDbName)); + const SSchema* pSchema = getTableColumnSchema(pStbMeta) + index; + PAR_ERR_JRET(setColRef(&req.colRef.pColRef[index], index + 1, pSchema->name, pColRef->refColName, + pColRef->refTableName, pColRef->refDbName)); index++; } } else { @@ -22154,8 +22148,8 @@ static int32_t buildVirtualSubTableBatchReq(const SCreateVSubTableStmt* pStmt, S return code; } -static int32_t buildNormalTableBatchReq(STranslateContext* pCxt, const SCreateTableStmt* pStmt, const SVgroupInfo* pVgroupInfo, - SVgroupCreateTableBatch* pBatch) { +static int32_t buildNormalTableBatchReq(STranslateContext* pCxt, const SCreateTableStmt* pStmt, + const SVgroupInfo* pVgroupInfo, SVgroupCreateTableBatch* pBatch) { SVCreateTbReq req = {0}; req.type = TD_NORMAL_TABLE; req.name = taosStrdup(pStmt->tableName); @@ -23836,41 +23830,42 @@ static int32_t buildUpdateMultiTagValReq(STranslateContext* pCxt, SAlterTableStm return code; } -static int32_t checkColRef(STranslateContext* pCxt, char* colName, char* pRefDbName, char* pRefTableName, char* pRefColName, - SDataType type, int8_t precision) { +static int32_t checkColRef(STranslateContext* pCxt, char* colName, char* pRefDbName, char* pRefTableName, + char* pRefColName, SDataType type, int8_t precision) { STableMeta* pRefTableMeta = NULL; int32_t code = TSDB_CODE_SUCCESS; PAR_ERR_JRET(getTableMeta(pCxt, pRefDbName, pRefTableName, &pRefTableMeta)); if (pRefTableMeta->tableInfo.precision != precision) { - PAR_ERR_JRET(generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_REF_COLUMN_TYPE, "timestamp precision of virtual table and its reference table do not match")); + PAR_ERR_JRET(generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_REF_COLUMN_TYPE, + "timestamp precision of virtual table and its reference table do not match")); } // org table cannot has composite primary key if (pRefTableMeta->tableInfo.numOfColumns > 1 && pRefTableMeta->schema[1].flags & COL_IS_KEY) { - PAR_ERR_JRET(generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_REF_COLUMN, - "virtual table's column:\"%s\"'s reference can not from table with composite key", - colName)); + PAR_ERR_JRET(generateSyntaxErrMsgExt( + &pCxt->msgBuf, TSDB_CODE_PAR_INVALID_REF_COLUMN, + "virtual table's column:\"%s\"'s reference can not from table with composite key", colName)); } // org table must be child table or normal table if (pRefTableMeta->tableType != TSDB_NORMAL_TABLE && pRefTableMeta->tableType != TSDB_CHILD_TABLE) { - PAR_ERR_JRET(generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_REF_COLUMN, - "virtual table's column:\"%s\"'s reference can only be normal table or child table", - colName)); + PAR_ERR_JRET(generateSyntaxErrMsgExt( + &pCxt->msgBuf, TSDB_CODE_PAR_INVALID_REF_COLUMN, + "virtual table's column:\"%s\"'s reference can only be normal table or child table", colName)); } const SSchema* pRefCol = getNormalColSchema(pRefTableMeta, pRefColName); if (NULL == pRefCol) { PAR_ERR_JRET(generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_REF_COLUMN, - "virtual table's column:\"%s\"'s reference column:\"%s\" not exist", - colName, pRefColName)); + "virtual table's column:\"%s\"'s reference column:\"%s\" not exist", colName, + pRefColName)); } if (pRefCol->type != type.type || pRefCol->bytes != type.bytes) { - PAR_ERR_JRET(generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_REF_COLUMN_TYPE, - "virtual table's column:\"%s\"'s type and reference column:\"%s\"'s type not match", - colName, pRefColName)); + PAR_ERR_JRET(generateSyntaxErrMsgExt( + &pCxt->msgBuf, TSDB_CODE_PAR_INVALID_REF_COLUMN_TYPE, + "virtual table's column:\"%s\"'s type and reference column:\"%s\"'s type not match", colName, pRefColName)); } _return: @@ -24014,7 +24009,10 @@ static int32_t buildUpdateColReq(STranslateContext* pCxt, SAlterTableStmt* pStmt return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_VAR_COLUMN_LEN); } - int32_t maxBytesPerRow = (TSDB_VIRTUAL_NORMAL_TABLE == pTableMeta->tableType || TSDB_VIRTUAL_CHILD_TABLE == pTableMeta->tableType) ? TSDB_MAX_BYTES_PER_ROW_VIRTUAL : TSDB_MAX_BYTES_PER_ROW; + int32_t maxBytesPerRow = + (TSDB_VIRTUAL_NORMAL_TABLE == pTableMeta->tableType || TSDB_VIRTUAL_CHILD_TABLE == pTableMeta->tableType) + ? TSDB_MAX_BYTES_PER_ROW_VIRTUAL + : TSDB_MAX_BYTES_PER_ROW; if (pTableMeta->tableInfo.rowSize + pReq->colModBytes - pSchema->bytes > maxBytesPerRow) { return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_ROW_LENGTH, maxBytesPerRow); } @@ -24300,9 +24298,8 @@ static int32_t rewriteAlterTableImpl(STranslateContext* pCxt, SAlterTableStmt* p } if (pTableMeta->isAudit) { - return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_TSC_INVALID_OPERATION, - "Cannot alter audit table `%s`.`%s`", pStmt->dbName, - pStmt->tableName); + return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_TSC_INVALID_OPERATION, "Cannot alter audit table `%s`.`%s`", + pStmt->dbName, pStmt->tableName); } if (TSDB_SUPER_TABLE == pTableMeta->tableType) { @@ -24437,7 +24434,6 @@ static int32_t rewriteCreateVirtualTable(STranslateContext* pCxt, SQuery* pQuery toName(pCxt->pParseCxt->acctId, pStmt->dbName, pStmt->tableName, &name); - FOREACH(pNode, pStmt->pCols) { SColumnDefNode* pColNode = (SColumnDefNode*)pNode; SColumnOptions* pColOptions = (SColumnOptions*)pColNode->pOptions; @@ -24448,10 +24444,9 @@ static int32_t rewriteCreateVirtualTable(STranslateContext* pCxt, SQuery* pQuery if (IS_DECIMAL_TYPE(pColNode->dataType.type)) { PAR_ERR_JRET(generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_VTABLE_NOT_SUPPORT_DATA_TYPE)); } - PAR_ERR_JRET( - checkColRef(pCxt, pColNode->colName, pColOptions->refDb, pColOptions->refTable, pColOptions->refColumn, - (SDataType){.type = pColNode->dataType.type, .bytes = calcTypeBytes(pColNode->dataType)}, - dbCfg.precision)); + PAR_ERR_JRET(checkColRef( + pCxt, pColNode->colName, pColOptions->refDb, pColOptions->refTable, pColOptions->refColumn, + (SDataType){.type = pColNode->dataType.type, .bytes = calcTypeBytes(pColNode->dataType)}, dbCfg.precision)); } index++; } diff --git a/test/cases/18-StreamProcessing/99-Others/auto_create_output_table.py b/test/cases/18-StreamProcessing/99-Others/auto_create_output_table.py new file mode 100644 index 000000000000..a095c4a2eb00 --- /dev/null +++ b/test/cases/18-StreamProcessing/99-Others/auto_create_output_table.py @@ -0,0 +1,252 @@ +from new_test_framework.utils import tdSql, tdLog, tdStream, StreamItem +from new_test_framework.utils.eutil import findTaosdLog + +class TestStreamAutoCreateOutputTable: + + def setup_class(self): + tdLog.debug(f"start to execute {__file__}") + + def test_output_table_schema_validation(self): + """Stream result match schema + + 1. Verify error is raised when calculation result and output table column type do not match + 2. Verify error is raised when calculation result and output table column name do not match + 3. Verify error is raised when calculation result and output table Tag column type do not match + 4. Verify error is raised when calculation result and output table Tag column name do not match + + Since: v3.4.7.0 + + Catalog: + - Streams: 02-Stream + + Labels: common,ci + + Jira: ID-6490870739 + + History: + - 2025-03-04 Created by Peng Rongkun + + """ + + tdStream.createSnode() + + self.prepareData() + self.check_auto_create_out_ctb() + self.check_auto_create_out_ntb() + self.insertDataAndCheck() + + def prepareData(self): + tdLog.info(f"prepare data") + + sqls = [ + "drop database if exists db;", + "create database db vgroups 1;", + "use db;", + "create table stb (`ts` timestamp, `c1` int) tags(`t1` int);", + "create table tb1 using stb tags (1);", + "create table tb2 using stb tags (2);", + "create table out_exists (`ts` timestamp, `c1` int, `t1` int) tags(`tag_tbname` varchar(128));", + ] + + tdSql.executes(sqls) + tdLog.info(f"create successfully.") + + def check_auto_create_out_ctb(self): + tdSql.execute(f"use db") + + sql1 ="create stream s1 count_window(1) from stb partition by tbname into out_ctb1 NODELAY_CREATE_SUBTABLE as select * from %%tbname where c1 > 10000;" + sql2 ="create stream s2 count_window(1) from stb partition by tbname into out_ctb2 as select * from %%tbname where c1 > 10000;" + sql3 ="create stream s3 count_window(1) from stb partition by tbname into out_ctb3 NODELAY_CREATE_SUBTABLE OUTPUT_SUBTABLE(CONCAT('out3_', tbname))tags (`nameoftbl` varchar(128) as tbname) as select * from %%tbname where c1 > 10000;" + sql4 ="create stream s4 count_window(1) from stb partition by tbname,t1 into out_ctb4 NODELAY_CREATE_SUBTABLE OUTPUT_SUBTABLE(CONCAT('out4_', tbname))tags (`nameoftbl` varchar(128) as tbname, tagt1 int as t1) as select * from %%tbname where c1 > 10000;" + sql5 ="create stream s5 count_window(1) from stb partition by tbname into out_exists NODELAY_CREATE_SUBTABLE OUTPUT_SUBTABLE(CONCAT('out_exists_', tbname)) as select * from %%tbname where c1 > 10000;" + streams = [ + self.StreamItem(sql1, self.checks1), + self.StreamItem(sql2, self.checks2), + self.StreamItem(sql3, self.checks3), + self.StreamItem(sql4, self.checks4), + self.StreamItem(sql5, self.checks5) + ] + for stream in streams: + tdSql.execute(stream.sql) + tdStream.checkStreamStatus() + + def check_auto_create_out_ntb(self): + tdSql.execute(f"use db") + + sql1 ="create stream s10 count_window(1) from tb1 into out_normal as select * from tb1 where c1 > 10000;" + + streams = [ + self.StreamItem(sql1, self.checks10) + ] + for stream in streams: + tdSql.execute(stream.sql) + tdStream.checkStreamStatus() + + def checks1(self): + tdLog.info(f"start to check nodelay create output ctb") + result_sql = f"select * from information_schema.ins_stables where stable_name like 'out_ctb1';" + tdSql.checkResultsByFunc( + sql=result_sql, + func=lambda: tdSql.getRows() == 1 + and tdSql.compareData(0, 0, "out_ctb1") + ) + + result_sql = f"select tags tag_tbname from out_ctb1 order by tag_tbname;" + tdSql.checkResultsByFunc( + sql=result_sql, + func=lambda: tdSql.getRows() == 2 + and tdSql.compareData(0, 0, "tb1") + and tdSql.compareData(1, 0, "tb2") + ) + + def checks2(self): + tdLog.info(f"start to check delay create output ctb") + result_sql = f"select * from information_schema.ins_stables where stable_name like 'out_ctb2';" + tdSql.checkResultsByFunc( + sql=result_sql, + func=lambda: tdSql.getRows() == 1 + and tdSql.compareData(0, 0, "out_ctb2") + ) + + result_sql = f"select tags tag_tbname from out_ctb2 order by tag_tbname;" + tdSql.checkResultsByFunc( + sql=result_sql, + func=lambda: tdSql.getRows() == 0 + ) + + def checks3(self): + tdLog.info(f"start to check nodelay create output ctb with custom tbname and tag") + result_sql = f"select * from information_schema.ins_stables where stable_name like 'out_ctb3';" + tdSql.checkResultsByFunc( + sql=result_sql, + func=lambda: tdSql.getRows() == 1 + and tdSql.compareData(0, 0, "out_ctb3") + ) + + result_sql = f"select tbname from out_ctb3 order by tbname;" + tdSql.checkResultsByFunc( + sql=result_sql, + func=lambda: tdSql.getRows() == 2 + and tdSql.compareData(0, 0, "out3_tb1") + and tdSql.compareData(1, 0, "out3_tb2") + ) + + result_sql = f"select tags nameoftbl from out_ctb3 order by nameoftbl;" + tdSql.checkResultsByFunc( + sql=result_sql, + func=lambda: tdSql.getRows() == 1 + and tdSql.compareData(0, 0, "tb1") + and tdSql.compareData(1, 0, "tb2") + ) + + def checks4(self): + tdLog.info(f"start to check nodelay create output ctb with multiple tags") + result_sql = f"select * from information_schema.ins_stables where stable_name like 'out_ctb4';" + tdSql.checkResultsByFunc( + sql=result_sql, + func=lambda: tdSql.getRows() == 1 + and tdSql.compareData(0, 0, "out_ctb4") + ) + + result_sql = f"select tags tbname,nameoftbl,tagt1 from out_ctb4 order by tbname;" + tdSql.checkResultsByFunc( + sql=result_sql, + func=lambda: tdSql.getRows() == 2 + and tdSql.compareData(0, 0, "out4_tb1") + and tdSql.compareData(0, 1, "tb1") + and tdSql.compareData(0, 2, "1") + and tdSql.compareData(1, 0, "out4_tb2") + and tdSql.compareData(1, 1, "tb2") + and tdSql.compareData(1, 2, "2") + ) + + def checks5(self): + tdLog.info(f"start to check nodelay create output ctb with exists table") + result_sql = f"select tbname from out_exists order by tbname;" + tdSql.checkResultsByFunc( + sql=result_sql, + func=lambda: tdSql.getRows() == 2 + and tdSql.compareData(0, 0, "out_exists_tb1") + and tdSql.compareData(1, 0, "out_exists_tb2") + ) + + def checks10(self): + result_sql = f"select * from information_schema.ins_tables where table_name like 'out_normal';" + tdSql.checkResultsByFunc( + sql=result_sql, + func=lambda: tdSql.getRows() == 1 + and tdSql.compareData(0, 0, "out_normal") + ) + + result_sql = f"select * from out_normal;" + tdSql.checkResultsByFunc( + sql=result_sql, + func=lambda: tdSql.getRows() == 0 + ) + + def insertDataAndCheck(self): + tdLog.info(f"insert data and check") + sqls = [ + "insert into tb1 values ('2025-01-01 00:00:00', 10001);", + "insert into tb2 values ('2025-01-01 00:00:01', 10002);", + ] + tdSql.executes(sqls) + tdLog.info(f"insert data successfully") + tdLog.info(f"start to check data") + result_sql = f"select c1,tag_tbname from out_ctb1 order by ts;" + tdSql.checkResultsByFunc( + sql=result_sql, + func=lambda: tdSql.getRows() == 2 + and tdSql.compareData(0, 0, "10001") + and tdSql.compareData(0, 1, "tb1") + and tdSql.compareData(1, 0, "10002") + and tdSql.compareData(1, 1, "tb2") + ) + result_sql = f"select c1,tag_tbname from out_ctb2 order by ts;" + tdSql.checkResultsByFunc( + sql=result_sql, + func=lambda: tdSql.getRows() == 2 + and tdSql.compareData(0, 0, "10001") + and tdSql.compareData(0, 1, "tb1") + and tdSql.compareData(1, 0, "10002") + and tdSql.compareData(1, 1, "tb2") + ) + result_sql = f"select c1,tbname,nameoftbl from out_ctb3 order by ts;" + tdSql.checkResultsByFunc( + sql=result_sql, + func=lambda: tdSql.getRows() == 2 + and tdSql.compareData(0, 0, "10001") + and tdSql.compareData(0, 1, "out3_tb1") + and tdSql.compareData(0, 2, "tb1") + and tdSql.compareData(1, 0, "10002") + and tdSql.compareData(1, 1, "out3_tb2") + and tdSql.compareData(1, 2, "tb2") + ) + result_sql = f"select c1,tbname,nameoftbl,tagt1 from out_ctb4 order by ts;" + tdSql.checkResultsByFunc( + sql=result_sql, + func=lambda: tdSql.getRows() == 2 + and tdSql.compareData(0, 0, "10001") + and tdSql.compareData(0, 1, "out4_tb1") + and tdSql.compareData(0, 2, "tb1") + and tdSql.compareData(0, 3, "1") + and tdSql.compareData(1, 0, "10002") + and tdSql.compareData(1, 1, "out4_tb2") + and tdSql.compareData(1, 2, "tb2") + and tdSql.compareData(1, 3, "2") + ) + result_sql = f"select * from out_normal order by ts;" + tdSql.checkResultsByFunc( + sql=result_sql, + func=lambda: tdSql.getRows() == 1 + and tdSql.compareData(0, 0, "2025-01-01 00:00:00") + and tdSql.compareData(0, 1, "10001") + ) + + class StreamItem: + def __init__(self, sql, checkfunc): + self.sql = sql + self.checkfunc = checkfunc + + def check(self): + self.checkfunc() \ No newline at end of file