From 64487cfe291be82657958535385fd80017c8b86d Mon Sep 17 00:00:00 2001 From: chenhaoran Date: Wed, 20 Nov 2024 15:19:31 +0800 Subject: [PATCH 01/62] fix:handling the issue of 'git remote prune origin' failing due to ref lock --- packaging/delete_ref_lock.py | 70 ++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/packaging/delete_ref_lock.py b/packaging/delete_ref_lock.py index cf0e4cdd05..42803e43fd 100644 --- a/packaging/delete_ref_lock.py +++ b/packaging/delete_ref_lock.py @@ -6,54 +6,78 @@ def git_fetch(): result = subprocess.run(['git', 'fetch'], capture_output=True, text=True) return result -# 解析分支名称 +def git_prune(): + # git remote prune origin + print("git remote prune origin") + result = subprocess.run(['git', 'remote', 'prune', 'origin'], capture_output=True, text=True) + return result + def parse_branch_name_type1(error_output): + # error: cannot lock ref 'refs/remotes/origin/fix/3.0/TD-32817': is at 7af5 but expected eaba # 使用正则表达式匹配 'is at' 前的分支名称 match = re.search(r"error: cannot lock ref '(refs/remotes/origin/[^']+)': is at", error_output) if match: return match.group(1) return None -# 解析第二种错误中的分支名称 def parse_branch_name_type2(error_output): - # 使用正则表达式匹配 'exists' 前的第一个引号内的分支名称 + # 使用正则表达式匹配 'exists; cannot create' 前的第一个引号内的分支名称 match = re.search(r"'(refs/remotes/origin/[^']+)' exists;", error_output) if match: return match.group(1) return None +# parse branch name from error output of git remote prune origin +def parse_branch_name_type3(error_output): + # 使用正则表达式匹配 'Unable to' 前的第一个引号内的分支名称 + # git error: could not delete references: cannot lock ref 'refs/remotes/origin/test/3.0/TS-4893': Unable to create 'D:/workspace/main/TDinternal/community/.git/refs/remotes/origin/test/3.0/TS-4893.lock': File exists + match = re.search(r"references: cannot lock ref '(refs/remotes/origin/[^']+)': Unable to", error_output) + if match: + return match.group(1) + return None + + # 执行 git update-ref -d 命令 def git_update_ref(branch_name): if branch_name: subprocess.run(['git', 'update-ref', '-d', f'{branch_name}'], check=True) # 解析错误类型并执行相应的修复操作 +# parse error type and execute corresponding repair operation def handle_error(error_output): - # 错误类型1:本地引用的提交ID与远程不一致 - if "is at" in error_output and "but expected" in error_output: - branch_name = parse_branch_name_type1(error_output) - if branch_name: - print(f"Detected error type 1, attempting to delete ref for branch: {branch_name}") - git_update_ref(branch_name) - else: - print("Error parsing branch name for type 1.") - # 错误类型2:尝试创建新的远程引用时,本地已经存在同名的引用 - elif "exists; cannot create" in error_output: - branch_name = parse_branch_name_type2(error_output) - if branch_name: - print(f"Detected error type 2, attempting to delete ref for branch: {branch_name}") - git_update_ref(branch_name) - else: - print("Error parsing branch name for type 2.") + error_types = [ + ("is at", "but expected", parse_branch_name_type1, "type 1"), + ("exists; cannot create", None, parse_branch_name_type2, "type 2"), + ("Unable to create", "File exists", parse_branch_name_type3, "type 3") + ] + + for error_type in error_types: + if error_type[0] in error_output and (error_type[1] is None or error_type[1] in error_output): + branch_name = error_type[2](error_output) + if branch_name: + print(f"Detected error {error_type[3]}, attempting to delete ref for branch: {branch_name}") + git_update_ref(branch_name) + else: + print(f"Error parsing branch name for {error_type[3]}.") + break # 主函数 def main(): - fetch_result = git_fetch() - if fetch_result.returncode != 0: # 如果 git fetch 命令失败 - error_output = fetch_result.stderr + # fetch_result = git_fetch() + # if fetch_result.returncode != 0: # 如果 git fetch 命令失败 + # error_output = fetch_result.stderr + # handle_error(error_output) + # else: + # print("Git fetch successful.") + + prune_result = git_prune() + print(prune_result.returncode) + if prune_result.returncode != 0: # 如果 git fetch 命令失败 + error_output = prune_result.stderr + print(error_output) handle_error(error_output) else: - print("Git fetch successful.") + print("Git prune successful.") if __name__ == "__main__": main() \ No newline at end of file From 0cfe979082862f21fc936303dfe290f859fc16e3 Mon Sep 17 00:00:00 2001 From: chenhaoran Date: Wed, 20 Nov 2024 15:23:41 +0800 Subject: [PATCH 02/62] fix:handling the issue of 'git remote prune origin' failing due to ref lock --- packaging/delete_ref_lock.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/packaging/delete_ref_lock.py b/packaging/delete_ref_lock.py index 42803e43fd..7200246a8a 100644 --- a/packaging/delete_ref_lock.py +++ b/packaging/delete_ref_lock.py @@ -1,7 +1,6 @@ import subprocess import re -# 执行 git fetch 命令并捕获输出 def git_fetch(): result = subprocess.run(['git', 'fetch'], capture_output=True, text=True) return result @@ -14,14 +13,14 @@ def git_prune(): def parse_branch_name_type1(error_output): # error: cannot lock ref 'refs/remotes/origin/fix/3.0/TD-32817': is at 7af5 but expected eaba - # 使用正则表达式匹配 'is at' 前的分支名称 + # match the branch name before ‘is at’ with a regular expression match = re.search(r"error: cannot lock ref '(refs/remotes/origin/[^']+)': is at", error_output) if match: return match.group(1) return None def parse_branch_name_type2(error_output): - # 使用正则表达式匹配 'exists; cannot create' 前的第一个引号内的分支名称 + # match the branch name before ‘exists; cannot create’ with a regular expression match = re.search(r"'(refs/remotes/origin/[^']+)' exists;", error_output) if match: return match.group(1) @@ -29,7 +28,7 @@ def parse_branch_name_type2(error_output): # parse branch name from error output of git remote prune origin def parse_branch_name_type3(error_output): - # 使用正则表达式匹配 'Unable to' 前的第一个引号内的分支名称 + # match the branch name before the first single quote before 'Unable to' with a regular expression # git error: could not delete references: cannot lock ref 'refs/remotes/origin/test/3.0/TS-4893': Unable to create 'D:/workspace/main/TDinternal/community/.git/refs/remotes/origin/test/3.0/TS-4893.lock': File exists match = re.search(r"references: cannot lock ref '(refs/remotes/origin/[^']+)': Unable to", error_output) if match: @@ -37,12 +36,11 @@ def parse_branch_name_type3(error_output): return None -# 执行 git update-ref -d 命令 +# execute git update-ref -d to delete the ref def git_update_ref(branch_name): if branch_name: subprocess.run(['git', 'update-ref', '-d', f'{branch_name}'], check=True) -# 解析错误类型并执行相应的修复操作 # parse error type and execute corresponding repair operation def handle_error(error_output): error_types = [ @@ -61,18 +59,17 @@ def handle_error(error_output): print(f"Error parsing branch name for {error_type[3]}.") break -# 主函数 def main(): - # fetch_result = git_fetch() - # if fetch_result.returncode != 0: # 如果 git fetch 命令失败 - # error_output = fetch_result.stderr - # handle_error(error_output) - # else: - # print("Git fetch successful.") + fetch_result = git_fetch() + if fetch_result.returncode != 0: + error_output = fetch_result.stderr + handle_error(error_output) + else: + print("Git fetch successful.") prune_result = git_prune() print(prune_result.returncode) - if prune_result.returncode != 0: # 如果 git fetch 命令失败 + if prune_result.returncode != 0: error_output = prune_result.stderr print(error_output) handle_error(error_output) From 718b0ad16e2bc2769ae6414313bda018ac3b306b Mon Sep 17 00:00:00 2001 From: wangjiaming0909 <604227650@qq.com> Date: Tue, 19 Nov 2024 08:53:08 +0800 Subject: [PATCH 03/62] replace unsafe functions --- include/common/tcommon.h | 1 - source/libs/parser/src/parAstCreater.c | 135 +++++---- source/libs/parser/src/parAstParser.c | 16 +- source/libs/parser/src/parAuthenticator.c | 4 +- source/libs/parser/src/parCalcConst.c | 8 +- source/libs/parser/src/parInsertStmt.c | 2 +- source/libs/parser/src/parTranslater.c | 320 +++++++++++----------- source/libs/parser/src/parUtil.c | 24 +- source/libs/planner/src/planOptimizer.c | 4 +- source/libs/planner/src/planSpliter.c | 22 +- 10 files changed, 266 insertions(+), 270 deletions(-) diff --git a/include/common/tcommon.h b/include/common/tcommon.h index 111c9dde3c..df78d6a249 100644 --- a/include/common/tcommon.h +++ b/include/common/tcommon.h @@ -398,7 +398,6 @@ int32_t taosGenCrashJsonMsg(int signum, char** pMsg, int64_t clusterId, int64_t int32_t dumpConfToDataBlock(SSDataBlock* pBlock, int32_t startCol); #define TSMA_RES_STB_POSTFIX "_tsma_res_stb_" -#define MD5_OUTPUT_LEN 32 #define TSMA_RES_STB_EXTRA_COLUMN_NUM 4 // 3 columns: _wstart, _wend, _wduration, 1 tag: tbname static inline bool isTsmaResSTb(const char* stbName) { diff --git a/source/libs/parser/src/parAstCreater.c b/source/libs/parser/src/parAstCreater.c index 43f7b5a4ea..f6602fc731 100644 --- a/source/libs/parser/src/parAstCreater.c +++ b/source/libs/parser/src/parAstCreater.c @@ -50,12 +50,12 @@ } \ } while (0) -#define COPY_STRING_FORM_ID_TOKEN(buf, pToken) strncpy(buf, (pToken)->z, TMIN((pToken)->n, sizeof(buf) - 1)) -#define COPY_STRING_FORM_STR_TOKEN(buf, pToken) \ - do { \ - if ((pToken)->n > 2) { \ - strncpy(buf, (pToken)->z + 1, TMIN((pToken)->n - 2, sizeof(buf) - 1)); \ - } \ +#define COPY_STRING_FORM_ID_TOKEN(buf, pToken) tstrncpy(buf, (pToken)->z, TMIN((pToken)->n + 1, sizeof(buf))) +#define COPY_STRING_FORM_STR_TOKEN(buf, pToken) \ + do { \ + if ((pToken)->n > 2) { \ + tstrncpy(buf, (pToken)->z + 1, TMIN((pToken)->n - 1, sizeof(buf))); \ + } \ } while (0) SToken nil_token = {.type = TK_NK_NIL, .n = 0, .z = NULL}; @@ -113,7 +113,7 @@ static bool checkPassword(SAstCreateContext* pCxt, const SToken* pPasswordToken, } else if (pPasswordToken->n >= (TSDB_USET_PASSWORD_LEN + 2)) { pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NAME_OR_PASSWD_TOO_LONG); } else { - strncpy(pPassword, pPasswordToken->z, pPasswordToken->n); + tstrncpy(pPassword, pPasswordToken->z, TMIN(TSDB_USET_PASSWORD_LEN, pPasswordToken->n + 1)); (void)strdequote(pPassword); if (strtrim(pPassword) <= 0) { pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_PASSWD_EMPTY); @@ -142,16 +142,16 @@ static int32_t parseEndpoint(SAstCreateContext* pCxt, const SToken* pEp, char* p (void)strdequote(ep); (void)strtrim(ep); if (NULL == pPort) { - strcpy(pFqdn, ep); + tstrncpy(pFqdn, ep, TSDB_FQDN_LEN); return TSDB_CODE_SUCCESS; } char* pColon = strchr(ep, ':'); if (NULL == pColon) { *pPort = tsServerPort; - strcpy(pFqdn, ep); + tstrncpy(pFqdn, ep, TSDB_FQDN_LEN); return TSDB_CODE_SUCCESS; } - strncpy(pFqdn, ep, pColon - ep); + tstrncpy(pFqdn, ep, pColon - ep + 1); return parsePort(pCxt, pColon + 1, pPort); } @@ -320,22 +320,21 @@ SNode* releaseRawExprNode(SAstCreateContext* pCxt, SNode* pNode) { if (nodesIsExprNode(pRealizedExpr)) { SExprNode* pExpr = (SExprNode*)pRealizedExpr; if (QUERY_NODE_COLUMN == nodeType(pExpr)) { - strcpy(pExpr->aliasName, ((SColumnNode*)pExpr)->colName); - strcpy(pExpr->userAlias, ((SColumnNode*)pExpr)->colName); + tstrncpy(pExpr->aliasName, ((SColumnNode*)pExpr)->colName, TSDB_COL_NAME_LEN); + tstrncpy(pExpr->userAlias, ((SColumnNode*)pExpr)->colName, TSDB_COL_NAME_LEN); } else if (pRawExpr->isPseudoColumn) { // all pseudo column are translate to function with same name - strcpy(pExpr->userAlias, ((SFunctionNode*)pExpr)->functionName); - strcpy(pExpr->aliasName, ((SFunctionNode*)pExpr)->functionName); + tstrncpy(pExpr->userAlias, ((SFunctionNode*)pExpr)->functionName, TSDB_COL_NAME_LEN); + tstrncpy(pExpr->aliasName, ((SFunctionNode*)pExpr)->functionName, TSDB_COL_NAME_LEN); } else { - int32_t len = TMIN(sizeof(pExpr->aliasName) - 1, pRawExpr->n); + int32_t len = TMIN(sizeof(pExpr->aliasName), pRawExpr->n + 1); // See TS-3398. // Len of pRawExpr->p could be larger than len of aliasName[TSDB_COL_NAME_LEN]. // If aliasName is truncated, hash value of aliasName could be the same. uint64_t hashVal = MurmurHash3_64(pRawExpr->p, pRawExpr->n); sprintf(pExpr->aliasName, "%" PRIu64, hashVal); - strncpy(pExpr->userAlias, pRawExpr->p, len); - pExpr->userAlias[len] = '\0'; + tstrncpy(pExpr->userAlias, pRawExpr->p, len); } } pRawExpr->pNode = NULL; @@ -1021,9 +1020,9 @@ static SNode* createPrimaryKeyCol(SAstCreateContext* pCxt, const SToken* pFuncNa CHECK_MAKE_NODE(pCol); pCol->colId = PRIMARYKEY_TIMESTAMP_COL_ID; if (NULL == pFuncName) { - strcpy(pCol->colName, ROWTS_PSEUDO_COLUMN_NAME); + tstrncpy(pCol->colName, ROWTS_PSEUDO_COLUMN_NAME, TSDB_COL_NAME_LEN); } else { - strncpy(pCol->colName, pFuncName->z, pFuncName->n); + tstrncpy(pCol->colName, pFuncName->z, pFuncName->n + 1); } pCol->isPrimTs = true; return (SNode*)pCol; @@ -1052,7 +1051,7 @@ SNode* createCastFunctionNode(SAstCreateContext* pCxt, SNode* pExpr, SDataType d CHECK_PARSER_STATUS(pCxt); pCxt->errCode = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&func); CHECK_MAKE_NODE(func); - strcpy(func->functionName, "cast"); + tstrncpy(func->functionName, "cast", TSDB_FUNC_NAME_LEN); func->node.resType = dt; if (TSDB_DATA_TYPE_VARCHAR == dt.type || TSDB_DATA_TYPE_GEOMETRY == dt.type || TSDB_DATA_TYPE_VARBINARY == dt.type) { func->node.resType.bytes = func->node.resType.bytes + VARSTR_HEADER_SIZE; @@ -1073,7 +1072,7 @@ SNode* createPositionFunctionNode(SAstCreateContext* pCxt, SNode* pExpr, SNode* CHECK_PARSER_STATUS(pCxt); pCxt->errCode = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&func); CHECK_MAKE_NODE(func); - strcpy(func->functionName, "position"); + tstrncpy(func->functionName, "position", TSDB_FUNC_NAME_LEN); pCxt->errCode = nodesListMakeAppend(&func->pParameterList, pExpr); CHECK_PARSER_STATUS(pCxt); pCxt->errCode = nodesListMakeAppend(&func->pParameterList, pExpr2); @@ -1091,7 +1090,7 @@ SNode* createTrimFunctionNode(SAstCreateContext* pCxt, SNode* pExpr, ETrimType t CHECK_PARSER_STATUS(pCxt); pCxt->errCode = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&func); CHECK_MAKE_NODE(func); - strcpy(func->functionName, "trim"); + tstrncpy(func->functionName, "trim", TSDB_FUNC_NAME_LEN); func->trimType = type; pCxt->errCode = nodesListMakeAppend(&func->pParameterList, pExpr); CHECK_PARSER_STATUS(pCxt); @@ -1107,7 +1106,7 @@ SNode* createTrimFunctionNodeExt(SAstCreateContext* pCxt, SNode* pExpr, SNode* p CHECK_PARSER_STATUS(pCxt); pCxt->errCode = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&func); CHECK_MAKE_NODE(func); - strcpy(func->functionName, "trim"); + tstrncpy(func->functionName, "trim", TSDB_FUNC_NAME_LEN); func->trimType = type; pCxt->errCode = nodesListMakeAppend(&func->pParameterList, pExpr); CHECK_PARSER_STATUS(pCxt); @@ -1126,7 +1125,7 @@ SNode* createSubstrFunctionNode(SAstCreateContext* pCxt, SNode* pExpr, SNode* pE CHECK_PARSER_STATUS(pCxt); pCxt->errCode = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&func); CHECK_MAKE_NODE(func); - strcpy(func->functionName, "substr"); + tstrncpy(func->functionName, "substr", TSDB_FUNC_NAME_LEN); pCxt->errCode = nodesListMakeAppend(&func->pParameterList, pExpr); CHECK_PARSER_STATUS(pCxt); pCxt->errCode = nodesListMakeAppend(&func->pParameterList, pExpr2); @@ -1144,7 +1143,7 @@ SNode* createSubstrFunctionNodeExt(SAstCreateContext* pCxt, SNode* pExpr, SNode* CHECK_PARSER_STATUS(pCxt); pCxt->errCode = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&func); CHECK_MAKE_NODE(func); - strcpy(func->functionName, "substr"); + tstrncpy(func->functionName, "substr", TSDB_FUNC_NAME_LEN); pCxt->errCode = nodesListMakeAppend(&func->pParameterList, pExpr); CHECK_PARSER_STATUS(pCxt); pCxt->errCode = nodesListMakeAppend(&func->pParameterList, pExpr2); @@ -1228,10 +1227,10 @@ SNode* createTempTableNode(SAstCreateContext* pCxt, SNode* pSubquery, SToken* pT taosRandStr(tempTable->table.tableAlias, 8); } if (QUERY_NODE_SELECT_STMT == nodeType(pSubquery)) { - strcpy(((SSelectStmt*)pSubquery)->stmtName, tempTable->table.tableAlias); + tstrncpy(((SSelectStmt*)pSubquery)->stmtName, tempTable->table.tableAlias, TSDB_TABLE_NAME_LEN); ((SSelectStmt*)pSubquery)->isSubquery = true; } else if (QUERY_NODE_SET_OPERATOR == nodeType(pSubquery)) { - strcpy(((SSetOperator*)pSubquery)->stmtName, tempTable->table.tableAlias); + tstrncpy(((SSetOperator*)pSubquery)->stmtName, tempTable->table.tableAlias, TSDB_TABLE_NAME_LEN); } return (SNode*)tempTable; _err: @@ -1434,7 +1433,7 @@ SNode* createFillNode(SAstCreateContext* pCxt, EFillMode mode, SNode* pValues) { fill->pWStartTs = NULL; pCxt->errCode = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&(fill->pWStartTs)); CHECK_MAKE_NODE(fill->pWStartTs); - strcpy(((SFunctionNode*)fill->pWStartTs)->functionName, "_wstart"); + tstrncpy(((SFunctionNode*)fill->pWStartTs)->functionName, "_wstart", TSDB_FUNC_NAME_LEN); return (SNode*)fill; _err: nodesDestroyNode((SNode*)fill); @@ -1525,11 +1524,9 @@ SNode* setProjectionAlias(SAstCreateContext* pCxt, SNode* pNode, SToken* pAlias) CHECK_PARSER_STATUS(pCxt); trimEscape(pAlias); SExprNode* pExpr = (SExprNode*)pNode; - int32_t len = TMIN(sizeof(pExpr->aliasName) - 1, pAlias->n); - strncpy(pExpr->aliasName, pAlias->z, len); - pExpr->aliasName[len] = '\0'; - strncpy(pExpr->userAlias, pAlias->z, len); - pExpr->userAlias[len] = '\0'; + int32_t len = TMIN(sizeof(pExpr->aliasName), pAlias->n + 1); + tstrncpy(pExpr->aliasName, pAlias->z, len); + tstrncpy(pExpr->userAlias, pAlias->z, len); pExpr->asAlias = true; return pNode; _err: @@ -2245,7 +2242,7 @@ SNode* setColumnOptions(SAstCreateContext* pCxt, SNode* pOptions, const SToken* char optionType[TSDB_CL_OPTION_LEN]; memset(optionType, 0, TSDB_CL_OPTION_LEN); - strncpy(optionType, pVal1->z, TMIN(pVal1->n, TSDB_CL_OPTION_LEN)); + tstrncpy(optionType, pVal1->z, TMIN(pVal1->n, TSDB_CL_OPTION_LEN)); if (0 == strlen(optionType)) { pCxt->errCode = TSDB_CODE_PAR_SYNTAX_ERROR; return pOptions; @@ -2322,8 +2319,8 @@ SNode* createCreateTableStmt(SAstCreateContext* pCxt, bool ignoreExists, SNode* SCreateTableStmt* pStmt = NULL; pCxt->errCode = nodesMakeNode(QUERY_NODE_CREATE_TABLE_STMT, (SNode**)&pStmt); CHECK_MAKE_NODE(pStmt); - strcpy(pStmt->dbName, ((SRealTableNode*)pRealTable)->table.dbName); - strcpy(pStmt->tableName, ((SRealTableNode*)pRealTable)->table.tableName); + tstrncpy(pStmt->dbName, ((SRealTableNode*)pRealTable)->table.dbName, TSDB_DB_NAME_LEN); + tstrncpy(pStmt->tableName, ((SRealTableNode*)pRealTable)->table.tableName, TSDB_TABLE_NAME_LEN); pStmt->ignoreExists = ignoreExists; pStmt->pCols = pCols; pStmt->pTags = pTags; @@ -2344,10 +2341,10 @@ SNode* createCreateSubTableClause(SAstCreateContext* pCxt, bool ignoreExists, SN SCreateSubTableClause* pStmt = NULL; pCxt->errCode = nodesMakeNode(QUERY_NODE_CREATE_SUBTABLE_CLAUSE, (SNode**)&pStmt); CHECK_MAKE_NODE(pStmt); - strcpy(pStmt->dbName, ((SRealTableNode*)pRealTable)->table.dbName); - strcpy(pStmt->tableName, ((SRealTableNode*)pRealTable)->table.tableName); - strcpy(pStmt->useDbName, ((SRealTableNode*)pUseRealTable)->table.dbName); - strcpy(pStmt->useTableName, ((SRealTableNode*)pUseRealTable)->table.tableName); + tstrncpy(pStmt->dbName, ((SRealTableNode*)pRealTable)->table.dbName, TSDB_DB_NAME_LEN); + tstrncpy(pStmt->tableName, ((SRealTableNode*)pRealTable)->table.tableName, TSDB_TABLE_NAME_LEN); + tstrncpy(pStmt->useDbName, ((SRealTableNode*)pUseRealTable)->table.dbName, TSDB_DB_NAME_LEN); + tstrncpy(pStmt->useTableName, ((SRealTableNode*)pUseRealTable)->table.tableName, TSDB_TABLE_NAME_LEN); pStmt->ignoreExists = ignoreExists; pStmt->pSpecificTags = pSpecificTags; pStmt->pValsOfTags = pValsOfTags; @@ -2370,14 +2367,14 @@ SNode* createCreateSubTableFromFileClause(SAstCreateContext* pCxt, bool ignoreEx SCreateSubTableFromFileClause* pStmt = NULL; pCxt->errCode = nodesMakeNode(QUERY_NODE_CREATE_SUBTABLE_FROM_FILE_CLAUSE, (SNode**)&pStmt); CHECK_MAKE_NODE(pStmt); - strcpy(pStmt->useDbName, ((SRealTableNode*)pUseRealTable)->table.dbName); - strcpy(pStmt->useTableName, ((SRealTableNode*)pUseRealTable)->table.tableName); + tstrncpy(pStmt->useDbName, ((SRealTableNode*)pUseRealTable)->table.dbName, TSDB_DB_NAME_LEN); + tstrncpy(pStmt->useTableName, ((SRealTableNode*)pUseRealTable)->table.tableName, TSDB_TABLE_NAME_LEN); pStmt->ignoreExists = ignoreExists; pStmt->pSpecificTags = pSpecificTags; if (TK_NK_STRING == pFilePath->type) { (void)trimString(pFilePath->z, pFilePath->n, pStmt->filePath, PATH_MAX); } else { - strncpy(pStmt->filePath, pFilePath->z, pFilePath->n); + tstrncpy(pStmt->filePath, pFilePath->z, TMIN(PATH_MAX, pFilePath->n + 1)); } nodesDestroyNode(pUseRealTable); @@ -2405,8 +2402,8 @@ SNode* createDropTableClause(SAstCreateContext* pCxt, bool ignoreNotExists, SNod SDropTableClause* pStmt = NULL; pCxt->errCode = nodesMakeNode(QUERY_NODE_DROP_TABLE_CLAUSE, (SNode**)&pStmt); CHECK_MAKE_NODE(pStmt); - strcpy(pStmt->dbName, ((SRealTableNode*)pRealTable)->table.dbName); - strcpy(pStmt->tableName, ((SRealTableNode*)pRealTable)->table.tableName); + tstrncpy(pStmt->dbName, ((SRealTableNode*)pRealTable)->table.dbName, TSDB_DB_NAME_LEN); + tstrncpy(pStmt->tableName, ((SRealTableNode*)pRealTable)->table.tableName, TSDB_TABLE_NAME_LEN); pStmt->ignoreNotExists = ignoreNotExists; nodesDestroyNode(pRealTable); return (SNode*)pStmt; @@ -2433,8 +2430,8 @@ SNode* createDropSuperTableStmt(SAstCreateContext* pCxt, bool withOpt, bool igno SDropSuperTableStmt* pStmt = NULL; pCxt->errCode = nodesMakeNode(QUERY_NODE_DROP_SUPER_TABLE_STMT, (SNode**)&pStmt); CHECK_MAKE_NODE(pStmt); - strcpy(pStmt->dbName, ((SRealTableNode*)pRealTable)->table.dbName); - strcpy(pStmt->tableName, ((SRealTableNode*)pRealTable)->table.tableName); + tstrncpy(pStmt->dbName, ((SRealTableNode*)pRealTable)->table.dbName, TSDB_DB_NAME_LEN); + tstrncpy(pStmt->tableName, ((SRealTableNode*)pRealTable)->table.tableName, TSDB_TABLE_NAME_LEN); pStmt->ignoreNotExists = ignoreNotExists; pStmt->withOpt = withOpt; nodesDestroyNode(pRealTable); @@ -2445,8 +2442,8 @@ _err: } static SNode* createAlterTableStmtFinalize(SNode* pRealTable, SAlterTableStmt* pStmt) { - strcpy(pStmt->dbName, ((SRealTableNode*)pRealTable)->table.dbName); - strcpy(pStmt->tableName, ((SRealTableNode*)pRealTable)->table.tableName); + tstrncpy(pStmt->dbName, ((SRealTableNode*)pRealTable)->table.dbName, TSDB_DB_NAME_LEN); + tstrncpy(pStmt->tableName, ((SRealTableNode*)pRealTable)->table.tableName, TSDB_TABLE_NAME_LEN); nodesDestroyNode(pRealTable); return (SNode*)pStmt; } @@ -2765,8 +2762,8 @@ SNode* createShowCreateTableStmt(SAstCreateContext* pCxt, ENodeType type, SNode* SShowCreateTableStmt* pStmt = NULL; pCxt->errCode = nodesMakeNode(type, (SNode**)&pStmt); CHECK_MAKE_NODE(pStmt); - strcpy(pStmt->dbName, ((SRealTableNode*)pRealTable)->table.dbName); - strcpy(pStmt->tableName, ((SRealTableNode*)pRealTable)->table.tableName); + tstrncpy(pStmt->dbName, ((SRealTableNode*)pRealTable)->table.dbName, TSDB_DB_NAME_LEN); + tstrncpy(pStmt->tableName, ((SRealTableNode*)pRealTable)->table.tableName, TSDB_TABLE_NAME_LEN); nodesDestroyNode(pRealTable); return (SNode*)pStmt; _err: @@ -2779,8 +2776,8 @@ SNode* createShowCreateViewStmt(SAstCreateContext* pCxt, ENodeType type, SNode* SShowCreateViewStmt* pStmt = NULL; pCxt->errCode = nodesMakeNode(type, (SNode**)&pStmt); CHECK_MAKE_NODE(pStmt); - strcpy(pStmt->dbName, ((SRealTableNode*)pRealTable)->table.dbName); - strcpy(pStmt->viewName, ((SRealTableNode*)pRealTable)->table.tableName); + tstrncpy(pStmt->dbName, ((SRealTableNode*)pRealTable)->table.dbName, TSDB_DB_NAME_LEN); + tstrncpy(pStmt->viewName, ((SRealTableNode*)pRealTable)->table.tableName, TSDB_TABLE_NAME_LEN); nodesDestroyNode(pRealTable); return (SNode*)pStmt; _err: @@ -2793,8 +2790,8 @@ SNode* createShowTableDistributedStmt(SAstCreateContext* pCxt, SNode* pRealTable SShowTableDistributedStmt* pStmt = NULL; pCxt->errCode = nodesMakeNode(QUERY_NODE_SHOW_TABLE_DISTRIBUTED_STMT, (SNode**)&pStmt); CHECK_MAKE_NODE(pStmt); - strcpy(pStmt->dbName, ((SRealTableNode*)pRealTable)->table.dbName); - strcpy(pStmt->tableName, ((SRealTableNode*)pRealTable)->table.tableName); + tstrncpy(pStmt->dbName, ((SRealTableNode*)pRealTable)->table.dbName, TSDB_DB_NAME_LEN); + tstrncpy(pStmt->tableName, ((SRealTableNode*)pRealTable)->table.tableName, TSDB_TABLE_NAME_LEN); nodesDestroyNode(pRealTable); return (SNode*)pStmt; _err: @@ -2950,7 +2947,7 @@ SNode* createCreateUserStmt(SAstCreateContext* pCxt, SToken* pUserName, const ST pCxt->errCode = nodesMakeNode(QUERY_NODE_CREATE_USER_STMT, (SNode**)&pStmt); CHECK_MAKE_NODE(pStmt); COPY_STRING_FORM_ID_TOKEN(pStmt->userName, pUserName); - strcpy(pStmt->password, password); + tstrncpy(pStmt->password, password, TSDB_USET_PASSWORD_LEN); pStmt->sysinfo = sysinfo; pStmt->createDb = createDb; pStmt->isImport = is_import; @@ -2972,7 +2969,7 @@ SNode* createAlterUserStmt(SAstCreateContext* pCxt, SToken* pUserName, int8_t al char password[TSDB_USET_PASSWORD_LEN] = {0}; SToken* pVal = pAlterInfo; CHECK_NAME(checkPassword(pCxt, pVal, password)); - strcpy(pStmt->password, password); + tstrncpy(pStmt->password, password, TSDB_USET_PASSWORD_LEN); break; } case TSDB_ALTER_USER_ENABLE: { @@ -3282,8 +3279,8 @@ SNode* createCreateTopicStmtUseTable(SAstCreateContext* pCxt, bool ignoreExists, pStmt->withMeta = withMeta; pStmt->pWhere = pWhere; - strcpy(pStmt->subDbName, ((SRealTableNode*)pRealTable)->table.dbName); - strcpy(pStmt->subSTbName, ((SRealTableNode*)pRealTable)->table.tableName); + tstrncpy(pStmt->subDbName, ((SRealTableNode*)pRealTable)->table.dbName, TSDB_DB_NAME_LEN); + tstrncpy(pStmt->subSTbName, ((SRealTableNode*)pRealTable)->table.tableName, TSDB_TABLE_NAME_LEN); nodesDestroyNode(pRealTable); return (SNode*)pStmt; _err: @@ -3396,8 +3393,8 @@ SNode* createDescribeStmt(SAstCreateContext* pCxt, SNode* pRealTable) { SDescribeStmt* pStmt = NULL; pCxt->errCode = nodesMakeNode(QUERY_NODE_DESCRIBE_STMT, (SNode**)&pStmt); CHECK_MAKE_NODE(pStmt); - strcpy(pStmt->dbName, ((SRealTableNode*)pRealTable)->table.dbName); - strcpy(pStmt->tableName, ((SRealTableNode*)pRealTable)->table.tableName); + tstrncpy(pStmt->dbName, ((SRealTableNode*)pRealTable)->table.dbName, TSDB_DB_NAME_LEN); + tstrncpy(pStmt->tableName, ((SRealTableNode*)pRealTable)->table.tableName, TSDB_TABLE_NAME_LEN); nodesDestroyNode(pRealTable); return (SNode*)pStmt; _err: @@ -3477,8 +3474,8 @@ SNode* createCreateViewStmt(SAstCreateContext* pCxt, bool orReplace, SNode* pVie } pStmt->pQuerySql = tstrdup(pAs->z + i); CHECK_OUT_OF_MEM(pStmt->pQuerySql); - strcpy(pStmt->dbName, ((SViewNode*)pView)->table.dbName); - strcpy(pStmt->viewName, ((SViewNode*)pView)->table.tableName); + tstrncpy(pStmt->dbName, ((SViewNode*)pView)->table.dbName, TSDB_DB_NAME_LEN); + tstrncpy(pStmt->viewName, ((SViewNode*)pView)->table.tableName, TSDB_VIEW_NAME_LEN); nodesDestroyNode(pView); pStmt->orReplace = orReplace; pStmt->pQuery = pQuery; @@ -3496,8 +3493,8 @@ SNode* createDropViewStmt(SAstCreateContext* pCxt, bool ignoreNotExists, SNode* pCxt->errCode = nodesMakeNode(QUERY_NODE_DROP_VIEW_STMT, (SNode**)&pStmt); CHECK_MAKE_NODE(pStmt); pStmt->ignoreNotExists = ignoreNotExists; - strcpy(pStmt->dbName, ((SViewNode*)pView)->table.dbName); - strcpy(pStmt->viewName, ((SViewNode*)pView)->table.tableName); + tstrncpy(pStmt->dbName, ((SViewNode*)pView)->table.dbName, TSDB_DB_NAME_LEN); + tstrncpy(pStmt->viewName, ((SViewNode*)pView)->table.tableName, TSDB_VIEW_NAME_LEN); nodesDestroyNode(pView); return (SNode*)pStmt; _err: @@ -3582,8 +3579,8 @@ SNode* createCreateStreamStmt(SAstCreateContext* pCxt, bool ignoreExists, SToken pCxt->errCode = nodesMakeNode(QUERY_NODE_CREATE_STREAM_STMT, (SNode**)&pStmt); CHECK_MAKE_NODE(pStmt); COPY_STRING_FORM_ID_TOKEN(pStmt->streamName, pStreamName); - strcpy(pStmt->targetDbName, ((SRealTableNode*)pRealTable)->table.dbName); - strcpy(pStmt->targetTabName, ((SRealTableNode*)pRealTable)->table.tableName); + tstrncpy(pStmt->targetDbName, ((SRealTableNode*)pRealTable)->table.dbName, TSDB_DB_NAME_LEN); + tstrncpy(pStmt->targetTabName, ((SRealTableNode*)pRealTable)->table.tableName, TSDB_TABLE_NAME_LEN); nodesDestroyNode(pRealTable); pStmt->ignoreExists = ignoreExists; pStmt->pOptions = (SStreamOptions*)pOptions; @@ -3837,9 +3834,9 @@ SNode* createInsertStmt(SAstCreateContext* pCxt, SNode* pTable, SNodeList* pCols pStmt->pCols = pCols; pStmt->pQuery = pQuery; if (QUERY_NODE_SELECT_STMT == nodeType(pQuery)) { - strcpy(((SSelectStmt*)pQuery)->stmtName, ((STableNode*)pTable)->tableAlias); + tstrncpy(((SSelectStmt*)pQuery)->stmtName, ((STableNode*)pTable)->tableAlias, TSDB_TABLE_NAME_LEN); } else if (QUERY_NODE_SET_OPERATOR == nodeType(pQuery)) { - strcpy(((SSetOperator*)pQuery)->stmtName, ((STableNode*)pTable)->tableAlias); + tstrncpy(((SSetOperator*)pQuery)->stmtName, ((STableNode*)pTable)->tableAlias, TSDB_TABLE_NAME_LEN); } return (SNode*)pStmt; _err: diff --git a/source/libs/parser/src/parAstParser.c b/source/libs/parser/src/parAstParser.c index 657deb43d0..fbdb5e18d0 100644 --- a/source/libs/parser/src/parAstParser.c +++ b/source/libs/parser/src/parAstParser.c @@ -480,8 +480,8 @@ static int32_t collectMetaKeyFromExplain(SCollectMetaKeyCxt* pCxt, SExplainStmt* static int32_t collectMetaKeyFromDescribe(SCollectMetaKeyCxt* pCxt, SDescribeStmt* pStmt) { SName name = {.type = TSDB_TABLE_NAME_T, .acctId = pCxt->pParseCxt->acctId}; - strcpy(name.dbname, pStmt->dbName); - strcpy(name.tname, pStmt->tableName); + tstrncpy(name.dbname, pStmt->dbName, TSDB_DB_NAME_LEN); + tstrncpy(name.tname, pStmt->tableName, TSDB_TABLE_NAME_LEN); int32_t code = catalogRemoveTableMeta(pCxt->pParseCxt->pCatalog, &name); #ifdef TD_ENTERPRISE if (TSDB_CODE_SUCCESS == code) { @@ -781,8 +781,8 @@ static int32_t collectMetaKeyFromShowCreateDatabase(SCollectMetaKeyCxt* pCxt, SS static int32_t collectMetaKeyFromShowCreateTable(SCollectMetaKeyCxt* pCxt, SShowCreateTableStmt* pStmt) { SName name = {.type = TSDB_TABLE_NAME_T, .acctId = pCxt->pParseCxt->acctId}; - strcpy(name.dbname, pStmt->dbName); - strcpy(name.tname, pStmt->tableName); + tstrncpy(name.dbname, pStmt->dbName, TSDB_DB_NAME_LEN); + tstrncpy(name.tname, pStmt->tableName, TSDB_TABLE_NAME_LEN); int32_t code = catalogRemoveTableMeta(pCxt->pParseCxt->pCatalog, &name); if (TSDB_CODE_SUCCESS == code) { code = reserveTableCfgInCache(pCxt->pParseCxt->acctId, pStmt->dbName, pStmt->tableName, pCxt->pMetaCache); @@ -799,8 +799,8 @@ static int32_t collectMetaKeyFromShowCreateTable(SCollectMetaKeyCxt* pCxt, SShow static int32_t collectMetaKeyFromShowCreateView(SCollectMetaKeyCxt* pCxt, SShowCreateViewStmt* pStmt) { SName name = {.type = TSDB_TABLE_NAME_T, .acctId = pCxt->pParseCxt->acctId}; - strcpy(name.dbname, pStmt->dbName); - strcpy(name.tname, pStmt->viewName); + tstrncpy(name.dbname, pStmt->dbName, TSDB_DB_NAME_LEN); + tstrncpy(name.tname, pStmt->viewName, TSDB_TABLE_NAME_LEN); char dbFName[TSDB_DB_FNAME_LEN]; (void)tNameGetFullDbName(&name, dbFName); int32_t code = catalogRemoveViewMeta(pCxt->pParseCxt->pCatalog, dbFName, 0, pStmt->viewName, 0); @@ -841,8 +841,8 @@ static int32_t collectMetaKeyFromInsert(SCollectMetaKeyCxt* pCxt, SInsertStmt* p static int32_t collectMetaKeyFromShowBlockDist(SCollectMetaKeyCxt* pCxt, SShowTableDistributedStmt* pStmt) { SName name = {.type = TSDB_TABLE_NAME_T, .acctId = pCxt->pParseCxt->acctId}; - strcpy(name.dbname, pStmt->dbName); - strcpy(name.tname, pStmt->tableName); + tstrncpy(name.dbname, pStmt->dbName, TSDB_DB_NAME_LEN); + tstrncpy(name.tname, pStmt->tableName, TSDB_TABLE_NAME_LEN); int32_t code = catalogRemoveTableMeta(pCxt->pParseCxt->pCatalog, &name); if (TSDB_CODE_SUCCESS == code) { code = collectMetaKeyFromRealTableImpl(pCxt, pStmt->dbName, pStmt->tableName, AUTH_TYPE_READ); diff --git a/source/libs/parser/src/parAuthenticator.c b/source/libs/parser/src/parAuthenticator.c index 5ae17a7647..b08207c4da 100644 --- a/source/libs/parser/src/parAuthenticator.c +++ b/source/libs/parser/src/parAuthenticator.c @@ -131,8 +131,8 @@ EDealRes rewriteAuthTable(SNode* pNode, void* pContext) { if (QUERY_NODE_COLUMN == nodeType(pNode)) { SColumnNode* pCol = (SColumnNode*)pNode; SAuthRewriteCxt* pCxt = (SAuthRewriteCxt*)pContext; - strcpy(pCol->tableName, pCxt->pTarget->tableName); - strcpy(pCol->tableAlias, pCxt->pTarget->tableAlias); + tstrncpy(pCol->tableName, pCxt->pTarget->tableName, TSDB_TABLE_NAME_LEN); + tstrncpy(pCol->tableAlias, pCxt->pTarget->tableAlias, TSDB_TABLE_NAME_LEN); } return DEAL_RES_CONTINUE; diff --git a/source/libs/parser/src/parCalcConst.c b/source/libs/parser/src/parCalcConst.c index a2e98bece7..79ad7ad6ed 100644 --- a/source/libs/parser/src/parCalcConst.c +++ b/source/libs/parser/src/parCalcConst.c @@ -178,14 +178,14 @@ static EDealRes doFindAndReplaceNode(SNode** pNode, void* pContext) { SCalcConstContext* pCxt = pContext; if (pCxt->replaceCxt.pTarget == *pNode) { char aliasName[TSDB_COL_NAME_LEN] = {0}; - strcpy(aliasName, ((SExprNode*)*pNode)->aliasName); + tstrncpy(aliasName, ((SExprNode*)*pNode)->aliasName, TSDB_COL_NAME_LEN); nodesDestroyNode(*pNode); *pNode = NULL; pCxt->code = nodesCloneNode(pCxt->replaceCxt.pNew, pNode); if (NULL == *pNode) { return DEAL_RES_ERROR; } - strcpy(((SExprNode*)*pNode)->aliasName, aliasName); + tstrncpy(((SExprNode*)*pNode)->aliasName, aliasName, TSDB_COL_NAME_LEN); pCxt->replaceCxt.replaced = true; return DEAL_RES_END; @@ -228,14 +228,14 @@ static int32_t calcConstProject(SCalcConstContext* pCxt, SNode* pProject, bool d SAssociationNode* pAssNode = taosArrayGet(pAssociation, i); SNode** pCol = pAssNode->pPlace; if (*pCol == pAssNode->pAssociationNode) { - strcpy(aliasName, ((SExprNode*)*pCol)->aliasName); + tstrncpy(aliasName, ((SExprNode*)*pCol)->aliasName, TSDB_COL_NAME_LEN); SArray* pOrigAss = NULL; TSWAP(((SExprNode*)*pCol)->pAssociation, pOrigAss); nodesDestroyNode(*pCol); *pCol = NULL; code = nodesCloneNode(*pNew, pCol); if (TSDB_CODE_SUCCESS == code) { - strcpy(((SExprNode*)*pCol)->aliasName, aliasName); + tstrncpy(((SExprNode*)*pCol)->aliasName, aliasName, TSDB_COL_NAME_LEN); TSWAP(pOrigAss, ((SExprNode*)*pCol)->pAssociation); } taosArrayDestroy(pOrigAss); diff --git a/source/libs/parser/src/parInsertStmt.c b/source/libs/parser/src/parInsertStmt.c index 0979028e6d..736af2d57d 100644 --- a/source/libs/parser/src/parInsertStmt.c +++ b/source/libs/parser/src/parInsertStmt.c @@ -903,7 +903,7 @@ int32_t buildBoundFields(int32_t numOfBound, int16_t* boundColumns, SSchema* pSc for (int32_t i = 0; i < numOfBound; ++i) { schema = &pSchema[boundColumns[i]]; - strcpy((*fields)[i].name, schema->name); + tstrncpy((*fields)[i].name, schema->name, 65); (*fields)[i].type = schema->type; (*fields)[i].bytes = schema->bytes; } diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index 7e5d9375ac..dec4ac9328 100755 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -1299,15 +1299,15 @@ static bool hasPkInTable(const STableMeta* pTableMeta) { static void setColumnInfoBySchema(const SRealTableNode* pTable, const SSchema* pColSchema, int32_t tagFlag, SColumnNode* pCol) { - strcpy(pCol->dbName, pTable->table.dbName); - strcpy(pCol->tableAlias, pTable->table.tableAlias); - strcpy(pCol->tableName, pTable->table.tableName); - strcpy(pCol->colName, pColSchema->name); + tstrncpy(pCol->dbName, pTable->table.dbName, TSDB_DB_NAME_LEN); + tstrncpy(pCol->tableAlias, pTable->table.tableAlias, TSDB_TABLE_NAME_LEN); + tstrncpy(pCol->tableName, pTable->table.tableName, TSDB_TABLE_NAME_LEN); + tstrncpy(pCol->colName, pColSchema->name, TSDB_COL_NAME_LEN); if ('\0' == pCol->node.aliasName[0]) { - strcpy(pCol->node.aliasName, pColSchema->name); + tstrncpy(pCol->node.aliasName, pColSchema->name, TSDB_COL_NAME_LEN); } if ('\0' == pCol->node.userAlias[0]) { - strcpy(pCol->node.userAlias, pColSchema->name); + tstrncpy(pCol->node.userAlias, pColSchema->name, TSDB_COL_NAME_LEN); } pCol->tableId = pTable->pMeta->uid; pCol->tableType = pTable->pMeta->tableType; @@ -1338,7 +1338,7 @@ static int32_t setColumnInfoByExpr(STempTableNode* pTable, SExprNode* pExpr, SCo return terrno; } - strcpy(pCol->tableAlias, pTable->table.tableAlias); + tstrncpy(pCol->tableAlias, pTable->table.tableAlias, TSDB_TABLE_NAME_LEN); pCol->isPrimTs = isPrimaryKeyImpl((SNode*)pExpr); pCol->colId = pCol->isPrimTs ? PRIMARYKEY_TIMESTAMP_COL_ID : 0; if (QUERY_NODE_COLUMN == nodeType(pExpr)) { @@ -1346,12 +1346,12 @@ static int32_t setColumnInfoByExpr(STempTableNode* pTable, SExprNode* pExpr, SCo // strcpy(pCol->dbName, ((SColumnNode*)pExpr)->dbName); // strcpy(pCol->tableName, ((SColumnNode*)pExpr)->tableName); } - strcpy(pCol->colName, pExpr->aliasName); + tstrncpy(pCol->colName, pExpr->aliasName, TSDB_COL_NAME_LEN); if ('\0' == pCol->node.aliasName[0]) { - strcpy(pCol->node.aliasName, pCol->colName); + tstrncpy(pCol->node.aliasName, pExpr->aliasName, TSDB_COL_NAME_LEN); } if ('\0' == pCol->node.userAlias[0]) { - strcpy(pCol->node.userAlias, pExpr->userAlias); + tstrncpy(pCol->node.userAlias, pExpr->aliasName, TSDB_COL_NAME_LEN); } pCol->node.resType = pExpr->resType; return TSDB_CODE_SUCCESS; @@ -1667,7 +1667,7 @@ static int32_t biMakeTbnameProjectAstNode(char* funcName, char* tableAlias, SNod if (TSDB_CODE_SUCCESS == code) { snprintf(tbNameFunc->node.userAlias, sizeof(tbNameFunc->node.userAlias), (tableAlias) ? "%s.tbname" : "%stbname", (tableAlias) ? tableAlias : ""); - strncpy(tbNameFunc->node.aliasName, tbNameFunc->functionName, TSDB_COL_NAME_LEN); + tstrncpy(tbNameFunc->node.aliasName, tbNameFunc->functionName, TSDB_COL_NAME_LEN); if (funcName == NULL) { *pOutNode = (SNode*)tbNameFunc; return code; @@ -1685,7 +1685,7 @@ static int32_t biMakeTbnameProjectAstNode(char* funcName, char* tableAlias, SNod if (tsKeepColumnName) { snprintf(multiResFunc->node.userAlias, sizeof(tbNameFunc->node.userAlias), (tableAlias) ? "%s.tbname" : "%stbname", (tableAlias) ? tableAlias : ""); - strcpy(multiResFunc->node.aliasName, tbNameFunc->functionName); + tstrncpy(multiResFunc->node.aliasName, tbNameFunc->functionName, TSDB_COL_NAME_LEN); } else { snprintf(multiResFunc->node.userAlias, sizeof(multiResFunc->node.userAlias), tableAlias ? "%s(%s.tbname)" : "%s(%stbname)", funcName, tableAlias ? tableAlias : ""); @@ -1812,8 +1812,8 @@ int32_t biRewriteToTbnameFunc(STranslateContext* pCxt, SNode** ppNode, bool* pRe (SNode**)&tbnameFuncNode); if (TSDB_CODE_SUCCESS != code) return code; tbnameFuncNode->node.resType = pCol->node.resType; - strcpy(tbnameFuncNode->node.aliasName, pCol->node.aliasName); - strcpy(tbnameFuncNode->node.userAlias, pCol->node.userAlias); + tstrncpy(tbnameFuncNode->node.aliasName, pCol->node.aliasName, TSDB_COL_NAME_LEN); + tstrncpy(tbnameFuncNode->node.userAlias, pCol->node.userAlias, TSDB_COL_NAME_LEN); nodesDestroyNode(*ppNode); *ppNode = (SNode*)tbnameFuncNode; @@ -2131,7 +2131,7 @@ static EDealRes translateNormalValue(STranslateContext* pCxt, SValueNode* pVal, return generateDealNodeErrMsg(pCxt, terrno); } varDataSetLen(pVal->datum.p, len); - strncpy(varDataVal(pVal->datum.p), pVal->literal, len); + tstrncpy(varDataVal(pVal->datum.p), pVal->literal, len); break; } case TSDB_DATA_TYPE_TIMESTAMP: { @@ -2796,7 +2796,8 @@ static int32_t translateMultiResFunc(STranslateContext* pCxt, SFunctionNode* pFu } } if (tsKeepColumnName && 1 == LIST_LENGTH(pFunc->pParameterList) && !pFunc->node.asAlias && !pFunc->node.asParam) { - strcpy(pFunc->node.userAlias, ((SExprNode*)nodesListGetNode(pFunc->pParameterList, 0))->userAlias); + tstrncpy(pFunc->node.userAlias, ((SExprNode*)nodesListGetNode(pFunc->pParameterList, 0))->userAlias, + TSDB_COL_NAME_LEN); } return TSDB_CODE_SUCCESS; } @@ -2871,8 +2872,8 @@ static int32_t rewriteFuncToValue(STranslateContext* pCxt, char** pLiteral, SNod if (TSDB_CODE_SUCCESS != code) { return code; } - strcpy(pVal->node.aliasName, ((SExprNode*)*pNode)->aliasName); - strcpy(pVal->node.userAlias, ((SExprNode*)*pNode)->userAlias); + tstrncpy(pVal->node.aliasName, ((SExprNode*)*pNode)->aliasName, TSDB_COL_NAME_LEN); + tstrncpy(pVal->node.userAlias, ((SExprNode*)*pNode)->userAlias, TSDB_COL_NAME_LEN); pVal->node.resType = ((SExprNode*)*pNode)->resType; if (NULL == pLiteral || NULL == *pLiteral) { pVal->isNull = true; @@ -2987,10 +2988,10 @@ static int32_t replacePsedudoColumnFuncWithColumn(STranslateContext* pCxt, SNode if (0 != LIST_LENGTH(pFunc->pParameterList)) { SValueNode* pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 0); pCol->node.resType = pOldExpr->resType; - strcpy(pCol->tableAlias, pVal->literal); - strcpy(pCol->colName, pFunc->functionName); - strcpy(pCol->node.aliasName, pCol->colName); - strcpy(pCol->node.userAlias, pCol->colName); + tstrncpy(pCol->node.aliasName, pVal->literal, TSDB_COL_NAME_LEN); + tstrncpy(pCol->colName, pFunc->functionName, TSDB_COL_NAME_LEN); + tstrncpy(pCol->node.aliasName, pCol->colName, TSDB_COL_NAME_LEN); + tstrncpy(pCol->node.userAlias, pCol->colName, TSDB_COL_NAME_LEN); nodesDestroyNode(*ppNode); *ppNode = (SNode*)pCol; @@ -2998,9 +2999,9 @@ static int32_t replacePsedudoColumnFuncWithColumn(STranslateContext* pCxt, SNode } } pCol->node.resType = pOldExpr->resType; - strcpy(pCol->node.aliasName, pOldExpr->aliasName); - strcpy(pCol->node.userAlias, pOldExpr->userAlias); - strcpy(pCol->colName, pOldExpr->aliasName); + tstrncpy(pCol->node.aliasName, pOldExpr->aliasName, TSDB_COL_NAME_LEN); + tstrncpy(pCol->node.userAlias, pOldExpr->userAlias, TSDB_COL_NAME_LEN); + tstrncpy(pCol->colName, pOldExpr->aliasName, TSDB_COL_NAME_LEN); nodesDestroyNode(*ppNode); *ppNode = (SNode*)pCol; @@ -3255,7 +3256,7 @@ static int32_t createCastFunc(STranslateContext* pCxt, SNode* pExpr, SDataType d if (TSDB_CODE_SUCCESS != code) { return code; } - strcpy(pFunc->functionName, "cast"); + tstrncpy(pFunc->functionName, "cast", TSDB_FUNC_NAME_LEN); pFunc->node.resType = dt; if (TSDB_CODE_SUCCESS != nodesListMakeAppend(&pFunc->pParameterList, pExpr)) { nodesDestroyNode((SNode*)pFunc); @@ -3471,9 +3472,9 @@ static EDealRes rewriteColToSelectValFunc(STranslateContext* pCxt, SNode** pNode pCxt->errCode = code; return DEAL_RES_ERROR; } - strcpy(pFunc->functionName, "_select_value"); - strcpy(pFunc->node.aliasName, ((SExprNode*)*pNode)->aliasName); - strcpy(pFunc->node.userAlias, ((SExprNode*)*pNode)->userAlias); + tstrncpy(pFunc->functionName, "_select_value", TSDB_FUNC_NAME_LEN); + tstrncpy(pFunc->node.aliasName, ((SExprNode*)*pNode)->aliasName, TSDB_COL_NAME_LEN); + tstrncpy(pFunc->node.userAlias, ((SExprNode*)*pNode)->userAlias, TSDB_COL_NAME_LEN); pCxt->errCode = nodesListMakeAppend(&pFunc->pParameterList, *pNode); if (TSDB_CODE_SUCCESS == pCxt->errCode) { pCxt->errCode = getFuncInfo(pCxt, pFunc); @@ -3495,9 +3496,9 @@ static EDealRes rewriteExprToGroupKeyFunc(STranslateContext* pCxt, SNode** pNode return DEAL_RES_ERROR; } - strcpy(pFunc->functionName, "_group_key"); - strcpy(pFunc->node.aliasName, ((SExprNode*)*pNode)->aliasName); - strcpy(pFunc->node.userAlias, ((SExprNode*)*pNode)->userAlias); + tstrncpy(pFunc->functionName, "_group_key", TSDB_FUNC_NAME_LEN); + tstrncpy(pFunc->node.aliasName, ((SExprNode*)*pNode)->aliasName, TSDB_COL_NAME_LEN); + tstrncpy(pFunc->node.userAlias, ((SExprNode*)*pNode)->userAlias, TSDB_COL_NAME_LEN); pCxt->errCode = nodesListMakeAppend(&pFunc->pParameterList, *pNode); if (TSDB_CODE_SUCCESS == pCxt->errCode) { *pNode = (SNode*)pFunc; @@ -3514,9 +3515,9 @@ static EDealRes rewriteExprToSelectTagFunc(STranslateContext* pCxt, SNode** pNod return DEAL_RES_ERROR; } - strcpy(pFunc->functionName, "_group_const_value"); - strcpy(pFunc->node.aliasName, ((SExprNode*)*pNode)->aliasName); - strcpy(pFunc->node.userAlias, ((SExprNode*)*pNode)->userAlias); + tstrncpy(pFunc->functionName, "_group_const_value", TSDB_FUNC_NAME_LEN); + tstrncpy(pFunc->node.aliasName, ((SExprNode*)*pNode)->aliasName, TSDB_COL_NAME_LEN); + tstrncpy(pFunc->node.userAlias, ((SExprNode*)*pNode)->userAlias, TSDB_COL_NAME_LEN); pCxt->errCode = nodesListMakeAppend(&pFunc->pParameterList, *pNode); if (TSDB_CODE_SUCCESS == pCxt->errCode) { *pNode = (SNode*)pFunc; @@ -4288,7 +4289,7 @@ static int32_t setTableTsmas(STranslateContext* pCxt, SName* pName, SRealTableNo int32_t len = tsnprintf(buf, TSDB_TABLE_FNAME_LEN + TSDB_TABLE_NAME_LEN, "%s.%s_%s", pTsma->dbFName, pTsma->name, pRealTable->table.tableName); len = taosCreateMD5Hash(buf, len); - strncpy(tsmaTargetTbName.tname, buf, MD5_OUTPUT_LEN); + tstrncpy(tsmaTargetTbName.tname, buf, TSDB_TABLE_NAME_LEN); code = collectUseTable(&tsmaTargetTbName, pCxt->pTargetTables); if (TSDB_CODE_SUCCESS == code) code = catalogGetCachedTableHashVgroup(pCxt->pParseCxt->pCatalog, &tsmaTargetTbName, &vgInfo, &exists); @@ -4394,10 +4395,9 @@ static EDealRes doTranslateTbName(SNode** pNode, void* pContext) { return DEAL_RES_ERROR; } varDataSetLen(pVal->datum.p, tbLen); - strncpy(varDataVal(pVal->datum.p), pVal->literal, tbLen); - strcpy(pVal->node.userAlias, pFunc->node.userAlias); - strcpy(pVal->node.aliasName, pFunc->node.aliasName); - + tstrncpy(varDataVal(pVal->datum.p), pVal->literal, tbLen); + tstrncpy(pVal->node.userAlias, pFunc->node.userAlias, TSDB_COL_NAME_LEN); + tstrncpy(pVal->node.aliasName, pFunc->node.aliasName, TSDB_COL_NAME_LEN); nodesDestroyNode(*pNode); *pNode = (SNode*)pVal; } @@ -4462,9 +4462,9 @@ static int32_t addPrimJoinEqCond(SNode** pCond, SRealTableNode* leftTable, SReal pLeft->tableId = pLMeta->uid; pLeft->colId = pLMeta->schema[0].colId; pLeft->colType = COLUMN_TYPE_COLUMN; - strcpy(pLeft->tableName, leftTable->table.tableName); - strcpy(pLeft->tableAlias, leftTable->table.tableAlias); - strcpy(pLeft->colName, pLMeta->schema[0].name); + tstrncpy(pLeft->tableName, leftTable->table.tableName, TSDB_TABLE_NAME_LEN); + tstrncpy(pLeft->tableAlias, leftTable->table.tableAlias, TSDB_TABLE_NAME_LEN); + tstrncpy(pLeft->colName, pLMeta->schema[0].name, TSDB_COL_NAME_LEN); pOp->pLeft = (SNode*)pLeft; @@ -4479,9 +4479,9 @@ static int32_t addPrimJoinEqCond(SNode** pCond, SRealTableNode* leftTable, SReal pRight->tableId = pRMeta->uid; pRight->colId = pRMeta->schema[0].colId; pRight->colType = COLUMN_TYPE_COLUMN; - strcpy(pRight->tableName, rightTable->table.tableName); - strcpy(pRight->tableAlias, rightTable->table.tableAlias); - strcpy(pRight->colName, pRMeta->schema[0].name); + tstrncpy(pRight->tableName, rightTable->table.tableName, TSDB_TABLE_NAME_LEN); + tstrncpy(pRight->tableAlias, rightTable->table.tableAlias, TSDB_TABLE_NAME_LEN); + tstrncpy(pRight->colName, pRMeta->schema[0].name, TSDB_COL_NAME_LEN); pOp->pRight = (SNode*)pRight; @@ -5084,29 +5084,29 @@ static int32_t createMultiResFunc(SFunctionNode* pSrcFunc, SExprNode* pExpr, SNo pFunc->node.resType = pExpr->resType; pFunc->funcId = pSrcFunc->funcId; pFunc->funcType = pSrcFunc->funcType; - strcpy(pFunc->functionName, pSrcFunc->functionName); + tstrncpy(pFunc->functionName, pSrcFunc->functionName, TSDB_FUNC_NAME_LEN); char buf[TSDB_FUNC_NAME_LEN + TSDB_TABLE_NAME_LEN + TSDB_COL_NAME_LEN + TSDB_NAME_DELIMITER_LEN + 3] = {0}; int32_t len = 0; if (QUERY_NODE_COLUMN == nodeType(pExpr)) { SColumnNode* pCol = (SColumnNode*)pExpr; if (tsKeepColumnName) { - strcpy(pFunc->node.userAlias, pCol->colName); - strcpy(pFunc->node.aliasName, pCol->colName); + tstrncpy(pFunc->node.userAlias, pCol->colName, TSDB_COL_NAME_LEN); + tstrncpy(pFunc->node.aliasName, pCol->colName, TSDB_COL_NAME_LEN); } else { len = tsnprintf(buf, sizeof(buf) - 1, "%s(%s.%s)", pSrcFunc->functionName, pCol->tableAlias, pCol->colName); (void)taosHashBinary(buf, len); - strncpy(pFunc->node.aliasName, buf, TSDB_COL_NAME_LEN - 1); + tstrncpy(pFunc->node.aliasName, buf, TSDB_COL_NAME_LEN); len = tsnprintf(buf, sizeof(buf) - 1, "%s(%s)", pSrcFunc->functionName, pCol->colName); // note: userAlias could be truncated here - strncpy(pFunc->node.userAlias, buf, TSDB_COL_NAME_LEN - 1); + tstrncpy(pFunc->node.userAlias, buf, TSDB_COL_NAME_LEN); } } else { len = tsnprintf(buf, sizeof(buf) - 1, "%s(%s)", pSrcFunc->functionName, pExpr->aliasName); (void)taosHashBinary(buf, len); - strncpy(pFunc->node.aliasName, buf, TSDB_COL_NAME_LEN - 1); + tstrncpy(pFunc->node.aliasName, buf, TSDB_COL_NAME_LEN); len = tsnprintf(buf, sizeof(buf) - 1, "%s(%s)", pSrcFunc->functionName, pExpr->userAlias); // note: userAlias could be truncated here - strncpy(pFunc->node.userAlias, buf, TSDB_COL_NAME_LEN - 1); + tstrncpy(pFunc->node.userAlias, buf, TSDB_COL_NAME_LEN); } *ppNodeOut = (SNode*)pFunc; return code; @@ -5435,7 +5435,7 @@ static int32_t rewriteProjectAlias(SNodeList* pProjectionList) { FOREACH(pProject, pProjectionList) { SExprNode* pExpr = (SExprNode*)pProject; if ('\0' == pExpr->userAlias[0]) { - strcpy(pExpr->userAlias, pExpr->aliasName); + tstrncpy(pExpr->userAlias, pExpr->aliasName, TSDB_COL_NAME_LEN); } sprintf(pExpr->aliasName, "#expr_%d", no++); } @@ -6129,7 +6129,7 @@ static int32_t createDefaultFillNode(STranslateContext* pCxt, SNode** pOutput) { return code; } pCol->colId = PRIMARYKEY_TIMESTAMP_COL_ID; - strcpy(pCol->colName, ROWTS_PSEUDO_COLUMN_NAME); + tstrncpy(pCol->colName, ROWTS_PSEUDO_COLUMN_NAME, TSDB_COL_NAME_LEN); pFill->pWStartTs = (SNode*)pCol; *pOutput = (SNode*)pFill; @@ -6734,7 +6734,7 @@ static int32_t replaceToChildTableQuery(STranslateContext* pCxt, SEqCondTbNameTa int32_t len = tsnprintf(buf, TSDB_TABLE_FNAME_LEN + TSDB_TABLE_NAME_LEN, "%s.%s_%s", pTsma->dbFName, pTsma->name, pRealTable->table.tableName); len = taosCreateMD5Hash(buf, len); - strncpy(tsmaTargetTbName.tname, buf, MD5_OUTPUT_LEN); + tstrncpy(tsmaTargetTbName.tname, buf, TSDB_TABLE_NAME_LEN); STsmaTargetTbInfo ctbInfo = {0}; if (!pRealTable->tsmaTargetTbInfo) { pRealTable->tsmaTargetTbInfo = taosArrayInit(pRealTable->pTsmas->size, sizeof(STsmaTargetTbInfo)); @@ -6897,7 +6897,7 @@ static int32_t createPrimaryKeyColByTable(STranslateContext* pCxt, STableNode* p return code; } pCol->colId = PRIMARYKEY_TIMESTAMP_COL_ID; - strcpy(pCol->colName, ROWTS_PSEUDO_COLUMN_NAME); + tstrncpy(pCol->colName, ROWTS_PSEUDO_COLUMN_NAME, TSDB_COL_NAME_LEN); bool found = false; code = findAndSetColumn(pCxt, &pCol, pTable, &found, true); if (TSDB_CODE_SUCCESS != code || !found) { @@ -6996,7 +6996,7 @@ static int32_t createPkColByTable(STranslateContext* pCxt, SRealTableNode* pTabl return code; } pCol->colId = pTable->pMeta->schema[1].colId; - strcpy(pCol->colName, pTable->pMeta->schema[1].name); + tstrncpy(pCol->colName, pTable->pMeta->schema[1].name, TSDB_COL_NAME_LEN); bool found = false; code = findAndSetColumn(pCxt, &pCol, (STableNode*)pTable, &found, true); if (TSDB_CODE_SUCCESS != code || !found) { @@ -8462,7 +8462,7 @@ static int32_t columnDefNodeToField(SNodeList* pList, SArray** pArray, bool calB field.bytes = pCol->dataType.bytes; } - strcpy(field.name, pCol->colName); + tstrncpy(field.name, pCol->colName, TSDB_COL_NAME_LEN); if (pCol->pOptions) { setColEncode(&field.compress, columnEncodeVal(((SColumnOptions*)pCol->pOptions)->encode)); setColCompress(&field.compress, columnCompressVal(((SColumnOptions*)pCol->pOptions)->compress)); @@ -8500,7 +8500,7 @@ static int32_t tagDefNodeToField(SNodeList* pList, SArray** pArray, bool calByte } else { field.bytes = pCol->dataType.bytes; } - strcpy(field.name, pCol->colName); + tstrncpy(field.name, pCol->colName, TSDB_COL_NAME_LEN); if (pCol->sma) { field.flags |= COL_SMA_ON; } @@ -8905,7 +8905,7 @@ static void toSchema(const SColumnDefNode* pCol, col_id_t colId, SSchema* pSchem pSchema->type = pCol->dataType.type; pSchema->bytes = calcTypeBytes(pCol->dataType); pSchema->flags = flags; - strcpy(pSchema->name, pCol->colName); + tstrncpy(pSchema->name, pCol->colName, TSDB_COL_NAME_LEN); } typedef struct SSampleAstInfo { @@ -8942,8 +8942,8 @@ static int32_t addWstartToSampleProjects(SNodeList* pProjectionList) { if (NULL == pFunc) { return code; } - strcpy(pFunc->functionName, "_wstart"); - strcpy(pFunc->node.userAlias, "_wstart"); + tstrncpy(pFunc->functionName, "_wstart", TSDB_FUNC_NAME_LEN); + tstrncpy(pFunc->node.userAlias, "_wstart", TSDB_FUNC_NAME_LEN); return nodesListPushFront(pProjectionList, (SNode*)pFunc); } @@ -8953,8 +8953,8 @@ static int32_t addWendToSampleProjects(SNodeList* pProjectionList) { if (NULL == pFunc) { return code; } - strcpy(pFunc->functionName, "_wend"); - strcpy(pFunc->node.userAlias, "_wend"); + tstrncpy(pFunc->functionName, "_wend", TSDB_FUNC_NAME_LEN); + tstrncpy(pFunc->node.userAlias, "_wend", TSDB_FUNC_NAME_LEN); return nodesListAppend(pProjectionList, (SNode*)pFunc); } @@ -8964,8 +8964,8 @@ static int32_t addWdurationToSampleProjects(SNodeList* pProjectionList) { if (NULL == pFunc) { return code; } - strcpy(pFunc->functionName, "_wduration"); - strcpy(pFunc->node.userAlias, "_wduration"); + tstrncpy(pFunc->functionName, "_wduration", TSDB_FUNC_NAME_LEN); + tstrncpy(pFunc->node.userAlias, "_wduration", TSDB_FUNC_NAME_LEN); return nodesListAppend(pProjectionList, (SNode*)pFunc); } @@ -9011,7 +9011,7 @@ static int32_t buildIntervalForSampleAst(SSampleAstInfo* pInfo, SNode** pOutput) return code; } ((SColumnNode*)pInterval->pCol)->colId = PRIMARYKEY_TIMESTAMP_COL_ID; - strcpy(((SColumnNode*)pInterval->pCol)->colName, ROWTS_PSEUDO_COLUMN_NAME); + tstrncpy(((SColumnNode*)pInterval->pCol)->colName, ROWTS_PSEUDO_COLUMN_NAME, TSDB_COL_NAME_LEN); *pOutput = (SNode*)pInterval; return TSDB_CODE_SUCCESS; } @@ -9091,7 +9091,7 @@ static int32_t createColumnFromDef(SColumnDefNode* pDef, SNode** ppCol) { if (NULL == pCol) { return code; } - strcpy(pCol->colName, pDef->colName); + tstrncpy(pCol->colName, pDef->colName, TSDB_COL_NAME_LEN); *ppCol = (SNode*)pCol; return code; } @@ -9184,9 +9184,9 @@ static int32_t createTbnameFunction(SFunctionNode** ppFunc) { if (NULL == pFunc) { return code; } - strcpy(pFunc->functionName, "tbname"); - strcpy(pFunc->node.aliasName, "tbname"); - strcpy(pFunc->node.userAlias, "tbname"); + tstrncpy(pFunc->functionName, "tbname", TSDB_FUNC_NAME_LEN); + tstrncpy(pFunc->node.aliasName, "tbname", TSDB_COL_NAME_LEN); + tstrncpy(pFunc->node.userAlias, "tbname", TSDB_COL_NAME_LEN); *ppFunc = pFunc; return code; } @@ -9383,7 +9383,7 @@ static int32_t buildAlterSuperTableReq(STranslateContext* pCxt, SAlterTableStmt* case TSDB_ALTER_TABLE_UPDATE_COLUMN_BYTES: case TSDB_ALTER_TABLE_UPDATE_TAG_BYTES: { TAOS_FIELD field = {.type = pStmt->dataType.type, .bytes = calcTypeBytes(pStmt->dataType)}; - strcpy(field.name, pStmt->colName); + tstrncpy(field.name, pStmt->colName, 65); if (NULL == taosArrayPush(pAlterReq->pFields, &field)) { return terrno; } @@ -9392,12 +9392,12 @@ static int32_t buildAlterSuperTableReq(STranslateContext* pCxt, SAlterTableStmt* case TSDB_ALTER_TABLE_UPDATE_TAG_NAME: case TSDB_ALTER_TABLE_UPDATE_COLUMN_NAME: { TAOS_FIELD oldField = {0}; - strcpy(oldField.name, pStmt->colName); + tstrncpy(oldField.name, pStmt->colName, 65); if (NULL == taosArrayPush(pAlterReq->pFields, &oldField)) { return terrno; } TAOS_FIELD newField = {0}; - strcpy(newField.name, pStmt->newColName); + tstrncpy(newField.name, pStmt->newColName, 65); if (NULL == taosArrayPush(pAlterReq->pFields, &newField)) { return terrno; } @@ -9405,7 +9405,7 @@ static int32_t buildAlterSuperTableReq(STranslateContext* pCxt, SAlterTableStmt* } case TSDB_ALTER_TABLE_UPDATE_COLUMN_COMPRESS: { TAOS_FIELD field = {0}; - strcpy(field.name, pStmt->colName); + tstrncpy(field.name, pStmt->colName, 65); if (!checkColumnEncode(pStmt->pColOptions->encode)) return TSDB_CODE_TSC_ENCODE_PARAM_ERROR; if (!checkColumnCompress(pStmt->pColOptions->compress)) return TSDB_CODE_TSC_COMPRESS_PARAM_ERROR; if (!checkColumnLevel(pStmt->pColOptions->compressLevel)) return TSDB_CODE_TSC_COMPRESS_LEVEL_ERROR; @@ -9428,7 +9428,7 @@ static int32_t buildAlterSuperTableReq(STranslateContext* pCxt, SAlterTableStmt* if (!pAlterReq->pFields) return terrno; SFieldWithOptions field = {.type = pStmt->dataType.type, .bytes = calcTypeBytes(pStmt->dataType)}; // TAOS_FIELD field = {.type = pStmt->dataType.type, .bytes = calcTypeBytes(pStmt->dataType)}; - strcpy(field.name, pStmt->colName); + tstrncpy(field.name, pStmt->colName, TSDB_COL_NAME_LEN); if (pStmt->pColOptions != NULL) { if (!checkColumnEncodeOrSetDefault(pStmt->dataType.type, pStmt->pColOptions->encode)) return TSDB_CODE_TSC_ENCODE_PARAM_ERROR; @@ -9669,12 +9669,12 @@ static int32_t translateCreateUser(STranslateContext* pCxt, SCreateUserStmt* pSt if ((code = checkRangeOption(pCxt, TSDB_CODE_INVALID_OPTION, "sysinfo", pStmt->sysinfo, 0, 1, false))) { return code; } - strcpy(createReq.user, pStmt->userName); + tstrncpy(createReq.user, pStmt->userName, TSDB_USER_LEN); createReq.createType = 0; createReq.superUser = 0; createReq.sysInfo = pStmt->sysinfo; createReq.enable = 1; - strcpy(createReq.pass, pStmt->password); + tstrncpy(createReq.pass, pStmt->password, TSDB_USET_PASSWORD_LEN); createReq.isImport = pStmt->isImport; createReq.createDb = pStmt->createDb; @@ -9713,7 +9713,7 @@ static int32_t translateAlterUser(STranslateContext* pCxt, SAlterUserStmt* pStmt if ((code = checkAlterUser(pCxt, pStmt))) { return code; } - strcpy(alterReq.user, pStmt->userName); + tstrncpy(alterReq.user, pStmt->userName, TSDB_USER_LEN); alterReq.alterType = pStmt->alterType; alterReq.superUser = 0; alterReq.enable = pStmt->enable; @@ -9739,7 +9739,7 @@ static int32_t translateAlterUser(STranslateContext* pCxt, SAlterUserStmt* pStmt static int32_t translateDropUser(STranslateContext* pCxt, SDropUserStmt* pStmt) { SDropUserReq dropReq = {0}; - strcpy(dropReq.user, pStmt->userName); + tstrncpy(dropReq.user, pStmt->userName, TSDB_USER_LEN); int32_t code = buildCmdMsg(pCxt, TDMT_MND_DROP_USER, (FSerializeFunc)tSerializeSDropUserReq, &dropReq); tFreeSDropUserReq(&dropReq); @@ -9785,7 +9785,7 @@ static int32_t translateUpdateAnode(STranslateContext* pCxt, SUpdateAnodeStmt* p static int32_t translateCreateDnode(STranslateContext* pCxt, SCreateDnodeStmt* pStmt) { SCreateDnodeReq createReq = {0}; - strcpy(createReq.fqdn, pStmt->fqdn); + tstrncpy(createReq.fqdn, pStmt->fqdn, TSDB_FQDN_LEN); createReq.port = pStmt->port; int32_t code = buildCmdMsg(pCxt, TDMT_MND_CREATE_DNODE, (FSerializeFunc)tSerializeSCreateDnodeReq, &createReq); @@ -9796,7 +9796,7 @@ static int32_t translateCreateDnode(STranslateContext* pCxt, SCreateDnodeStmt* p static int32_t translateDropDnode(STranslateContext* pCxt, SDropDnodeStmt* pStmt) { SDropDnodeReq dropReq = {0}; dropReq.dnodeId = pStmt->dnodeId; - strcpy(dropReq.fqdn, pStmt->fqdn); + tstrncpy(dropReq.fqdn, pStmt->fqdn, TSDB_FQDN_LEN); dropReq.port = pStmt->port; dropReq.force = pStmt->force; dropReq.unsafe = pStmt->unsafe; @@ -9809,8 +9809,8 @@ static int32_t translateDropDnode(STranslateContext* pCxt, SDropDnodeStmt* pStmt static int32_t translateAlterDnode(STranslateContext* pCxt, SAlterDnodeStmt* pStmt) { SMCfgDnodeReq cfgReq = {0}; cfgReq.dnodeId = pStmt->dnodeId; - strcpy(cfgReq.config, pStmt->config); - strcpy(cfgReq.value, pStmt->value); + tstrncpy(cfgReq.config, pStmt->config, TSDB_DNODE_CONFIG_LEN); + tstrncpy(cfgReq.value, pStmt->value, TSDB_DNODE_VALUE_LEN); int32_t code = 0; if (0 == strncasecmp(cfgReq.config, "encrypt_key", 12)) { @@ -9857,8 +9857,8 @@ static int32_t translateRestoreDnode(STranslateContext* pCxt, SRestoreComponentN static int32_t translateAlterCluster(STranslateContext* pCxt, SAlterClusterStmt* pStmt) { SMCfgClusterReq cfgReq = {0}; - strcpy(cfgReq.config, pStmt->config); - strcpy(cfgReq.value, pStmt->value); + tstrncpy(cfgReq.config, pStmt->config, TSDB_DNODE_CONFIG_LEN); + tstrncpy(cfgReq.value, pStmt->value, TSDB_CLUSTER_VALUE_LEN); int32_t code = buildCmdMsg(pCxt, TDMT_MND_CONFIG_CLUSTER, (FSerializeFunc)tSerializeSMCfgClusterReq, &cfgReq); tFreeSMCfgClusterReq(&cfgReq); @@ -10329,9 +10329,9 @@ static int32_t checkCollectTopicTags(STranslateContext* pCxt, SCreateTopicStmt* if (NULL == col) { return code; } - strcpy(col->colName, column->name); - strcpy(col->node.aliasName, col->colName); - strcpy(col->node.userAlias, col->colName); + tstrncpy(col->colName, column->name, TSDB_COL_NAME_LEN); + tstrncpy(col->node.aliasName, col->colName, TSDB_COL_NAME_LEN); + tstrncpy(col->node.userAlias, col->colName, TSDB_COL_NAME_LEN); code = addTagList(&colCxt.pTags, (SNode*)col); if (TSDB_CODE_SUCCESS != code) { nodesDestroyNode((SNode*)col); @@ -10368,9 +10368,9 @@ static int32_t buildQueryForTableTopic(STranslateContext* pCxt, SCreateTopicStmt if (TSDB_CODE_SUCCESS == code) { code = nodesMakeNode(QUERY_NODE_REAL_TABLE, (SNode**)&realTable); if (realTable) { - strcpy(realTable->table.dbName, pStmt->subDbName); - strcpy(realTable->table.tableName, pStmt->subSTbName); - strcpy(realTable->table.tableAlias, pStmt->subSTbName); + tstrncpy(realTable->table.dbName, pStmt->subDbName, TSDB_DB_NAME_LEN); + tstrncpy(realTable->table.tableName, pStmt->subSTbName, TSDB_TABLE_NAME_LEN); + tstrncpy(realTable->table.tableAlias, pStmt->subSTbName, TSDB_TABLE_NAME_LEN); code = createSelectStmtImpl(true, pProjection, (SNode*)realTable, NULL, ppSelect); } if (TSDB_CODE_SUCCESS == code) { @@ -10443,7 +10443,7 @@ static int32_t translateDropCGroup(STranslateContext* pCxt, SDropCGroupStmt* pSt if (TSDB_CODE_SUCCESS != code) return code; (void)tNameGetFullDbName(&name, dropReq.topic); dropReq.igNotExists = pStmt->ignoreNotExists; - strcpy(dropReq.cgroup, pStmt->cgroup); + tstrncpy(dropReq.cgroup, pStmt->cgroup, TSDB_CGROUP_LEN); return buildCmdMsg(pCxt, TDMT_MND_TMQ_DROP_CGROUP, (FSerializeFunc)tSerializeSMDropCgroupReq, &dropReq); } @@ -10558,7 +10558,7 @@ static int32_t translateKillCompact(STranslateContext* pCxt, SKillStmt* pStmt) { static int32_t translateKillQuery(STranslateContext* pCxt, SKillQueryStmt* pStmt) { SKillQueryReq killReq = {0}; - strcpy(killReq.queryStrId, pStmt->queryId); + tstrncpy(killReq.queryStrId, pStmt->queryId, TSDB_QUERY_ID_LEN); return buildCmdMsg(pCxt, TDMT_MND_KILL_QUERY, (FSerializeFunc)tSerializeSKillQueryReq, &killReq); } @@ -10614,7 +10614,7 @@ static int32_t checkCreateStream(STranslateContext* pCxt, SCreateStreamStmt* pSt static void getSourceDatabase(SNode* pStmt, int32_t acctId, char* pDbFName) { SName name = {.type = TSDB_DB_NAME_T, .acctId = acctId}; - strcpy(name.dbname, ((SRealTableNode*)(((SSelectStmt*)pStmt)->pFromTable))->table.dbName); + tstrncpy(name.dbname, ((SRealTableNode*)(((SSelectStmt*)pStmt)->pFromTable))->table.dbName, TSDB_DB_NAME_LEN); (void)tNameGetFullDbName(&name, pDbFName); } @@ -10673,7 +10673,7 @@ static int32_t addIrowTsToCreateStreamQueryImpl(STranslateContext* pCxt, SSelect SColumnDefNode* pColDef = NULL; code = nodesMakeNode(QUERY_NODE_COLUMN_DEF, (SNode**)&pColDef); if (TSDB_CODE_SUCCESS == code) { - strcpy(pColDef->colName, pFunc->node.aliasName); + tstrncpy(pColDef->colName, pFunc->node.aliasName, TSDB_COL_NAME_LEN); pColDef->dataType = pFunc->node.resType; pColDef->sma = true; code = setColumnDefNodePrimaryKey(pColDef, false); @@ -10697,8 +10697,8 @@ static int32_t addWstartTsToCreateStreamQueryImpl(STranslateContext* pCxt, SSele if (NULL == pFunc) { return code; } - strcpy(pFunc->functionName, "_wstart"); - strcpy(pFunc->node.userAlias, "_irowts"); + tstrncpy(pFunc->functionName, "_wstart", TSDB_FUNC_NAME_LEN); + tstrncpy(pFunc->node.userAlias, "_irowts", TSDB_COL_NAME_LEN); char* defaultName[] = {"_wstart", "ts", NULL}; getStreamQueryFirstProjectAliasName(pUserAliasSet, pFunc->node.aliasName, sizeof(pFunc->node.aliasName), defaultName); code = getFuncInfo(pCxt, pFunc); @@ -10710,7 +10710,7 @@ static int32_t addWstartTsToCreateStreamQueryImpl(STranslateContext* pCxt, SSele SColumnDefNode* pColDef = NULL; code = nodesMakeNode(QUERY_NODE_COLUMN_DEF, (SNode**)&pColDef); if (TSDB_CODE_SUCCESS == code) { - strcpy(pColDef->colName, pFunc->node.aliasName); + tstrncpy(pColDef->colName, pFunc->node.aliasName, TSDB_COL_NAME_LEN); pColDef->dataType = pFunc->node.resType; pColDef->sma = true; code = setColumnDefNodePrimaryKey(pColDef, false); @@ -10870,7 +10870,7 @@ static int32_t addColDefNodeByProj(SNodeList** ppCols, const SNode* pProject, in SColumnDefNode* pColDef = NULL; int32_t code = nodesMakeNode(QUERY_NODE_COLUMN_DEF, (SNode**)&pColDef); if (TSDB_CODE_SUCCESS != code) return code; - strcpy(pColDef->colName, pExpr->userAlias); + tstrncpy(pColDef->colName, pExpr->userAlias, TSDB_COL_NAME_LEN); pColDef->dataType = pExpr->resType; pColDef->sma = flags & COL_SMA_ON; code = setColumnDefNodePrimaryKey(pColDef, flags & COL_IS_KEY); @@ -11171,7 +11171,7 @@ static int32_t adjustDataTypeOfProjections(STranslateContext* pCxt, const STable SColumnDefNode* pColDef = NULL; int32_t code = nodesMakeNode(QUERY_NODE_COLUMN_DEF, (SNode**)&pColDef); if (TSDB_CODE_SUCCESS != code) return code; - strcpy(pColDef->colName, pSchema->name); + tstrncpy(pColDef->colName, pSchema->name, TSDB_COL_NAME_LEN); pColDef->dataType = dt; pColDef->sma = pSchema->flags & COL_SMA_ON; code = setColumnDefNodePrimaryKey(pColDef, pSchema->flags & COL_IS_KEY); @@ -11214,7 +11214,7 @@ static int32_t addProjToProjColPos(STranslateContext* pCxt, const SSchema* pSche if (!dataTypeEqual(&dt, &((SExprNode*)pNewProj)->resType)) { SNode* pFunc = NULL; code = createCastFunc(pCxt, pNewProj, dt, &pFunc); - strcpy(((SExprNode*)pFunc)->userAlias, ((SExprNode*)pNewProj)->userAlias); + tstrncpy(((SExprNode*)pFunc)->userAlias, ((SExprNode*)pNewProj)->userAlias, TSDB_COL_NAME_LEN); pNewProj = pFunc; } if (TSDB_CODE_SUCCESS == code) { @@ -11783,8 +11783,8 @@ static int32_t buildCreateStreamReq(STranslateContext* pCxt, SCreateStreamStmt* (void)tNameGetFullDbName(&name, pReq->name); if ('\0' != pStmt->targetTabName[0]) { - strcpy(name.dbname, pStmt->targetDbName); - strcpy(name.tname, pStmt->targetTabName); + tstrncpy(name.dbname, pStmt->targetDbName, TSDB_DB_NAME_LEN); + tstrncpy(name.tname, pStmt->targetTabName, TSDB_TABLE_NAME_LEN); code = tNameExtractFullName(&name, pReq->targetStbFullName); } if (TSDB_CODE_SUCCESS == code) { @@ -12010,7 +12010,7 @@ static int32_t translateCreateView(STranslateContext* pCxt, SCreateViewStmt* pSt pStmt->createReq.precision = res.schemaRes.precision; pStmt->createReq.numOfCols = res.schemaRes.numOfCols; pStmt->createReq.pSchema = res.schemaRes.pSchema; - strncpy(pStmt->createReq.name, pStmt->viewName, sizeof(pStmt->createReq.name) - 1); + tstrncpy(pStmt->createReq.name, pStmt->viewName, TSDB_VIEW_NAME_LEN); tstrncpy(pStmt->createReq.dbFName, dbFName, sizeof(pStmt->createReq.dbFName)); snprintf(pStmt->createReq.fullname, sizeof(pStmt->createReq.fullname) - 1, "%s.%s", pStmt->createReq.dbFName, pStmt->viewName); @@ -12039,7 +12039,7 @@ static int32_t translateDropView(STranslateContext* pCxt, SDropViewStmt* pStmt) int32_t code = tNameSetDbName(&name, pCxt->pParseCxt->acctId, pStmt->dbName, strlen(pStmt->dbName)); if (TSDB_CODE_SUCCESS == code) { (void)tNameGetFullDbName(&name, dropReq.dbFName); - strncpy(dropReq.name, pStmt->viewName, sizeof(dropReq.name) - 1); + tstrncpy(dropReq.name, pStmt->viewName, TSDB_VIEW_NAME_LEN); snprintf(dropReq.fullname, sizeof(dropReq.fullname) - 1, "%s.%s", dropReq.dbFName, dropReq.name); dropReq.sql = (char*)pCxt->pParseCxt->pSql; if (NULL == dropReq.sql) { @@ -12106,7 +12106,7 @@ static int32_t translateCreateFunction(STranslateContext* pCxt, SCreateFunctionS } SCreateFuncReq req = {0}; - strcpy(req.name, pStmt->funcName); + tstrncpy(req.name, pStmt->funcName, TSDB_FUNC_NAME_LEN); req.orReplace = pStmt->orReplace; req.igExists = pStmt->ignoreExists; req.funcType = pStmt->isAgg ? TSDB_FUNC_TYPE_AGGREGATE : TSDB_FUNC_TYPE_SCALAR; @@ -12125,7 +12125,7 @@ static int32_t translateCreateFunction(STranslateContext* pCxt, SCreateFunctionS static int32_t translateDropFunction(STranslateContext* pCxt, SDropFunctionStmt* pStmt) { SDropFuncReq req = {0}; - strcpy(req.name, pStmt->funcName); + tstrncpy(req.name, pStmt->funcName, TSDB_FUNC_NAME_LEN); req.igNotExists = pStmt->ignoreNotExists; return buildCmdMsg(pCxt, TDMT_MND_DROP_FUNC, (FSerializeFunc)tSerializeSDropFuncReq, &req); } @@ -12136,9 +12136,9 @@ static int32_t createRealTableForGrantTable(SGrantStmt* pStmt, SRealTableNode** if (NULL == pRealTable) { return code; } - strcpy(pRealTable->table.dbName, pStmt->objName); - strcpy(pRealTable->table.tableName, pStmt->tabName); - strcpy(pRealTable->table.tableAlias, pStmt->tabName); + tstrncpy(pRealTable->table.dbName, pStmt->objName, TSDB_DB_NAME_LEN); + tstrncpy(pRealTable->table.tableName, pStmt->tabName, TSDB_TABLE_NAME_LEN); + tstrncpy(pRealTable->table.tableAlias, pStmt->tabName, TSDB_TABLE_NAME_LEN); *pTable = pRealTable; return TSDB_CODE_SUCCESS; } @@ -12213,7 +12213,7 @@ static int32_t translateGrant(STranslateContext* pCxt, SGrantStmt* pStmt) { } #endif - strcpy(req.user, pStmt->userName); + tstrncpy(req.user, pStmt->userName, TSDB_USER_LEN); sprintf(req.objname, "%d.%s", pCxt->pParseCxt->acctId, pStmt->objName); sprintf(req.tabName, "%s", pStmt->tabName); if (!req.isView) { @@ -12249,7 +12249,7 @@ static int32_t translateRevoke(STranslateContext* pCxt, SRevokeStmt* pStmt) { } #endif - strcpy(req.user, pStmt->userName); + tstrncpy(req.user, pStmt->userName, TSDB_USER_LEN); sprintf(req.objname, "%d.%s", pCxt->pParseCxt->acctId, pStmt->objName); sprintf(req.tabName, "%s", pStmt->tabName); code = buildCmdMsg(pCxt, TDMT_MND_ALTER_USER, (FSerializeFunc)tSerializeSAlterUserReq, &req); @@ -12267,7 +12267,7 @@ static int32_t translateBalanceVgroup(STranslateContext* pCxt, SBalanceVgroupStm static int32_t translateBalanceVgroupLeader(STranslateContext* pCxt, SBalanceVgroupLeaderStmt* pStmt) { SBalanceVgroupLeaderReq req = {0}; req.vgId = pStmt->vgId; - strcpy(req.db, pStmt->dbName); + tstrncpy(req.db, pStmt->dbName, TSDB_DB_FNAME_LEN); int32_t code = buildCmdMsg(pCxt, TDMT_MND_BALANCE_VGROUP_LEADER, (FSerializeFunc)tSerializeSBalanceVgroupLeaderReq, &req); tFreeSBalanceVgroupLeaderReq(&req); @@ -12553,7 +12553,7 @@ static int32_t createColumnBySchema(const SSchema* pSchema, SColumnNode** ppCol) (*ppCol)->colId = pSchema->colId; (*ppCol)->node.resType.type = pSchema->type; (*ppCol)->node.resType.bytes = pSchema->bytes; - strcpy((*ppCol)->colName, pSchema->name); + tstrncpy((*ppCol)->colName, pSchema->name, TSDB_COL_NAME_LEN); return TSDB_CODE_SUCCESS; } @@ -13102,9 +13102,9 @@ static int32_t extractQueryResultSchema(const SNodeList* pProjections, int32_t* } (*pSchema)[index].colId = index + 1; if ('\0' != pExpr->userAlias[0]) { - strcpy((*pSchema)[index].name, pExpr->userAlias); + tstrncpy((*pSchema)[index].name, pExpr->userAlias, TSDB_COL_NAME_LEN); } else { - strcpy((*pSchema)[index].name, pExpr->aliasName); + tstrncpy((*pSchema)[index].name, pExpr->aliasName, TSDB_COL_NAME_LEN); } index += 1; } @@ -13122,7 +13122,7 @@ static int32_t extractExplainResultSchema(int32_t* numOfCols, SSchema** pSchema) } (*pSchema)[0].type = TSDB_DATA_TYPE_BINARY; (*pSchema)[0].bytes = TSDB_EXPLAIN_RESULT_ROW_SIZE; - strcpy((*pSchema)[0].name, TSDB_EXPLAIN_RESULT_COLUMN_NAME); + tstrncpy((*pSchema)[0].name, TSDB_EXPLAIN_RESULT_COLUMN_NAME, TSDB_COL_NAME_LEN); return TSDB_CODE_SUCCESS; } @@ -13136,32 +13136,32 @@ static int32_t extractDescribeResultSchema(STableMeta* pMeta, int32_t* numOfCols (*pSchema)[0].type = TSDB_DATA_TYPE_BINARY; (*pSchema)[0].bytes = DESCRIBE_RESULT_FIELD_LEN; - strcpy((*pSchema)[0].name, "field"); + tstrncpy((*pSchema)[0].name, "field", TSDB_COL_NAME_LEN); (*pSchema)[1].type = TSDB_DATA_TYPE_BINARY; (*pSchema)[1].bytes = DESCRIBE_RESULT_TYPE_LEN; - strcpy((*pSchema)[1].name, "type"); + tstrncpy((*pSchema)[1].name, "type", TSDB_COL_NAME_LEN); (*pSchema)[2].type = TSDB_DATA_TYPE_INT; (*pSchema)[2].bytes = tDataTypes[TSDB_DATA_TYPE_INT].bytes; - strcpy((*pSchema)[2].name, "length"); + tstrncpy((*pSchema)[2].name, "length", TSDB_COL_NAME_LEN); (*pSchema)[3].type = TSDB_DATA_TYPE_BINARY; (*pSchema)[3].bytes = DESCRIBE_RESULT_NOTE_LEN; - strcpy((*pSchema)[3].name, "note"); + tstrncpy((*pSchema)[3].name, "note", TSDB_COL_NAME_LEN); if (pMeta && useCompress(pMeta->tableType)) { (*pSchema)[4].type = TSDB_DATA_TYPE_BINARY; (*pSchema)[4].bytes = DESCRIBE_RESULT_COPRESS_OPTION_LEN; - strcpy((*pSchema)[4].name, "encode"); + tstrncpy((*pSchema)[4].name, "encode", TSDB_COL_NAME_LEN); (*pSchema)[5].type = TSDB_DATA_TYPE_BINARY; (*pSchema)[5].bytes = DESCRIBE_RESULT_COPRESS_OPTION_LEN; - strcpy((*pSchema)[5].name, "compress"); + tstrncpy((*pSchema)[5].name, "compress", TSDB_COL_NAME_LEN); (*pSchema)[6].type = TSDB_DATA_TYPE_BINARY; (*pSchema)[6].bytes = DESCRIBE_RESULT_COPRESS_OPTION_LEN; - strcpy((*pSchema)[6].name, "level"); + tstrncpy((*pSchema)[6].name, "level", TSDB_COL_NAME_LEN); } return TSDB_CODE_SUCCESS; @@ -13176,11 +13176,11 @@ static int32_t extractShowCreateDatabaseResultSchema(int32_t* numOfCols, SSchema (*pSchema)[0].type = TSDB_DATA_TYPE_BINARY; (*pSchema)[0].bytes = TSDB_DB_NAME_LEN; - strcpy((*pSchema)[0].name, "Database"); + tstrncpy((*pSchema)[0].name, "Database", TSDB_COL_NAME_LEN); (*pSchema)[1].type = TSDB_DATA_TYPE_BINARY; (*pSchema)[1].bytes = TSDB_MAX_BINARY_LEN; - strcpy((*pSchema)[1].name, "Create Database"); + tstrncpy((*pSchema)[1].name, "Create Database", TSDB_COL_NAME_LEN); return TSDB_CODE_SUCCESS; } @@ -13194,11 +13194,11 @@ static int32_t extractShowCreateTableResultSchema(int32_t* numOfCols, SSchema** (*pSchema)[0].type = TSDB_DATA_TYPE_BINARY; (*pSchema)[0].bytes = SHOW_CREATE_TB_RESULT_FIELD1_LEN; - strcpy((*pSchema)[0].name, "Table"); + tstrncpy((*pSchema)[0].name, "Table", TSDB_COL_NAME_LEN); (*pSchema)[1].type = TSDB_DATA_TYPE_BINARY; (*pSchema)[1].bytes = SHOW_CREATE_TB_RESULT_FIELD2_LEN; - strcpy((*pSchema)[1].name, "Create Table"); + tstrncpy((*pSchema)[1].name, "Create Table", TSDB_COL_NAME_LEN); return TSDB_CODE_SUCCESS; } @@ -13212,11 +13212,11 @@ static int32_t extractShowCreateViewResultSchema(int32_t* numOfCols, SSchema** p (*pSchema)[0].type = TSDB_DATA_TYPE_BINARY; (*pSchema)[0].bytes = SHOW_CREATE_VIEW_RESULT_FIELD1_LEN; - strcpy((*pSchema)[0].name, "View"); + tstrncpy((*pSchema)[0].name, "View", TSDB_COL_NAME_LEN); (*pSchema)[1].type = TSDB_DATA_TYPE_BINARY; (*pSchema)[1].bytes = SHOW_CREATE_VIEW_RESULT_FIELD2_LEN; - strcpy((*pSchema)[1].name, "Create View"); + tstrncpy((*pSchema)[1].name, "Create View", TSDB_COL_NAME_LEN); return TSDB_CODE_SUCCESS; } @@ -13230,19 +13230,19 @@ static int32_t extractShowVariablesResultSchema(int32_t* numOfCols, SSchema** pS (*pSchema)[0].type = TSDB_DATA_TYPE_BINARY; (*pSchema)[0].bytes = TSDB_CONFIG_OPTION_LEN; - strcpy((*pSchema)[0].name, "name"); + tstrncpy((*pSchema)[0].name, "name", TSDB_COL_NAME_LEN); (*pSchema)[1].type = TSDB_DATA_TYPE_BINARY; (*pSchema)[1].bytes = TSDB_CONFIG_PATH_LEN; - strcpy((*pSchema)[1].name, "value"); + tstrncpy((*pSchema)[1].name, "value", TSDB_COL_NAME_LEN); (*pSchema)[2].type = TSDB_DATA_TYPE_BINARY; (*pSchema)[2].bytes = TSDB_CONFIG_SCOPE_LEN; - strcpy((*pSchema)[2].name, "scope"); + tstrncpy((*pSchema)[2].name, "scope", TSDB_COL_NAME_LEN); (*pSchema)[3].type = TSDB_DATA_TYPE_BINARY; (*pSchema)[3].bytes = TSDB_CONFIG_INFO_LEN; - strcpy((*pSchema)[3].name, "info"); + tstrncpy((*pSchema)[3].name, "info", TSDB_COL_NAME_LEN); return TSDB_CODE_SUCCESS; } @@ -13256,15 +13256,15 @@ static int32_t extractCompactDbResultSchema(int32_t* numOfCols, SSchema** pSchem (*pSchema)[0].type = TSDB_DATA_TYPE_BINARY; (*pSchema)[0].bytes = COMPACT_DB_RESULT_FIELD1_LEN; - strcpy((*pSchema)[0].name, "result"); + tstrncpy((*pSchema)[0].name, "result", TSDB_COL_NAME_LEN); (*pSchema)[1].type = TSDB_DATA_TYPE_INT; (*pSchema)[1].bytes = tDataTypes[TSDB_DATA_TYPE_INT].bytes; - strcpy((*pSchema)[1].name, "id"); + tstrncpy((*pSchema)[1].name, "id", TSDB_COL_NAME_LEN); (*pSchema)[2].type = TSDB_DATA_TYPE_BINARY; (*pSchema)[2].bytes = COMPACT_DB_RESULT_FIELD3_LEN; - strcpy((*pSchema)[2].name, "reason"); + tstrncpy((*pSchema)[2].name, "reason", TSDB_COL_NAME_LEN); return TSDB_CODE_SUCCESS; } @@ -13309,7 +13309,7 @@ static int32_t createStarCol(SNode** ppNode) { if (NULL == pCol) { return code; } - strcpy(pCol->colName, "*"); + tstrncpy(pCol->colName, "*", TSDB_COL_NAME_LEN); *ppNode = (SNode*)pCol; return code; } @@ -13453,8 +13453,8 @@ static int32_t createParOperatorNode(EOperatorType opType, const char* pLeftCol, nodesDestroyNode((SNode*)pOper); return code; } - strcpy(((SColumnNode*)pOper->pLeft)->colName, pLeftCol); - strcpy(((SColumnNode*)pOper->pRight)->colName, pRightCol); + tstrncpy(((SColumnNode*)pOper->pLeft)->colName, pLeftCol, TSDB_COL_NAME_LEN); + tstrncpy(((SColumnNode*)pOper->pRight)->colName, pRightCol, TSDB_COL_NAME_LEN); *ppResOp = (SNode*)pOper; return TSDB_CODE_SUCCESS; @@ -13721,7 +13721,7 @@ static int32_t createShowCondition(const SShowStmt* pShow, SSelectStmt* pSelect) } if (NULL != pShow->pDbName) { - strcpy(((SRealTableNode*)pSelect->pFromTable)->qualDbName, ((SValueNode*)pShow->pDbName)->literal); + tstrncpy(((SRealTableNode*)pSelect->pFromTable)->qualDbName, ((SValueNode*)pShow->pDbName)->literal, TSDB_DB_NAME_LEN); } return TSDB_CODE_SUCCESS; @@ -13794,7 +13794,7 @@ static int32_t createTagsFunction(SFunctionNode** ppNode) { if (NULL == pFunc) { return code; } - strcpy(pFunc->functionName, "_tags"); + tstrncpy(pFunc->functionName, "_tags", TSDB_FUNC_NAME_LEN); *ppNode = pFunc; return code; } @@ -13892,8 +13892,8 @@ static int32_t createBlockDistInfoFunc(SFunctionNode** ppNode) { return code; } - strcpy(pFunc->functionName, "_block_dist_info"); - strcpy(pFunc->node.aliasName, "_block_dist_info"); + tstrncpy(pFunc->functionName, "_block_dist_info", TSDB_FUNC_NAME_LEN); + tstrncpy(pFunc->node.aliasName, "_block_dist_info", TSDB_COL_NAME_LEN); *ppNode = pFunc; return code; } @@ -13905,8 +13905,8 @@ static int32_t createBlockDistFunc(SFunctionNode** ppNode) { return code; } - strcpy(pFunc->functionName, "_block_dist"); - strcpy(pFunc->node.aliasName, "_block_dist"); + tstrncpy(pFunc->functionName, "_block_dist", TSDB_FUNC_NAME_LEN); + tstrncpy(pFunc->node.aliasName, "_block_dist", TSDB_COL_NAME_LEN); SFunctionNode* pFuncNew = NULL; code = createBlockDistInfoFunc(&pFuncNew); if (TSDB_CODE_SUCCESS == code) { @@ -13948,7 +13948,7 @@ static int32_t buildNormalTableBatchReq(int32_t acctId, const SCreateTableStmt* SVgroupCreateTableBatch* pBatch) { char dbFName[TSDB_DB_FNAME_LEN] = {0}; SName name = {.type = TSDB_DB_NAME_T, .acctId = acctId}; - (void)strcpy(name.dbname, pStmt->dbName); + tstrncpy(name.dbname, pStmt->dbName, TSDB_DB_NAME_LEN); (void)tNameGetFullDbName(&name, dbFName); SVCreateTbReq req = {0}; @@ -14004,7 +14004,7 @@ static int32_t buildNormalTableBatchReq(int32_t acctId, const SCreateTableStmt* ++index; } pBatch->info = *pVgroupInfo; - (void)strcpy(pBatch->dbName, pStmt->dbName); + tstrncpy(pBatch->dbName, pStmt->dbName, TSDB_DB_NAME_LEN); pBatch->req.pArray = taosArrayInit(1, sizeof(struct SVCreateTbReq)); if (NULL == pBatch->req.pArray) { tdDestroySVCreateTbReq(&req); @@ -14180,7 +14180,7 @@ static int32_t addCreateTbReqIntoVgroup(SHashObj* pVgroupHashmap, const char* db if (pTableBatch == NULL) { SVgroupCreateTableBatch tBatch = {0}; tBatch.info = *pVgInfo; - strcpy(tBatch.dbName, dbName); + tstrncpy(tBatch.dbName, dbName, TSDB_DB_NAME_LEN); tBatch.req.pArray = taosArrayInit(4, sizeof(struct SVCreateTbReq)); if (!tBatch.req.pArray) { @@ -14683,7 +14683,7 @@ static int32_t constructParseFileContext(SCreateSubTableFromFileClause* pStmt, S pParFileCxt->pTag = NULL; pParFileCxt->ctbName.type = TSDB_TABLE_NAME_T; pParFileCxt->ctbName.acctId = acctId; - strcpy(pParFileCxt->ctbName.dbname, pStmt->useDbName); + tstrncpy(pParFileCxt->ctbName.dbname, pStmt->useDbName, TSDB_DB_NAME_LEN); if (NULL == pParFileCxt->aTagNames) { pParFileCxt->aTagNames = taosArrayInit(8, TSDB_COL_NAME_LEN); @@ -14757,8 +14757,8 @@ static int32_t prepareReadCsvFile(STranslateContext* pCxt, SCreateSubTableFromFi } pCreateInfo->ignoreExists = pCreateStmt->ignoreExists; - strncpy(pCreateInfo->useDbName, pCreateStmt->useDbName, TSDB_DB_NAME_LEN); - strncpy(pCreateInfo->useTableName, pCreateStmt->useTableName, TSDB_TABLE_NAME_LEN); + tstrncpy(pCreateInfo->useDbName, pCreateStmt->useDbName, TSDB_DB_NAME_LEN); + tstrncpy(pCreateInfo->useTableName, pCreateStmt->useTableName, TSDB_TABLE_NAME_LEN); } { @@ -15958,8 +15958,8 @@ static int32_t createParCaseWhenNode(SNode* pCase, SNodeList* pWhenThenList, SNo pCaseWhen->pWhenThenList = pWhenThenList; pCaseWhen->pElse = pElse; if (pAias) { - strcpy(pCaseWhen->node.aliasName, pAias); - strcpy(pCaseWhen->node.userAlias, pAias); + tstrncpy(pCaseWhen->node.aliasName, pAias, TSDB_COL_NAME_LEN); + tstrncpy(pCaseWhen->node.userAlias, pAias, TSDB_COL_NAME_LEN); } *ppResCaseWhen = (SNode*)pCaseWhen; return TSDB_CODE_SUCCESS; @@ -15972,9 +15972,9 @@ static int32_t createParFunctionNode(const char* pFunName, const char* pAias, SN if (TSDB_CODE_SUCCESS != code) { return code; } - strcpy(pFunc->functionName, pFunName); - strcpy(pFunc->node.aliasName, pAias); - strcpy(pFunc->node.userAlias, pAias); + tstrncpy(pFunc->functionName, pFunName, TSDB_FUNC_NAME_LEN); + tstrncpy(pFunc->node.aliasName, pAias, TSDB_COL_NAME_LEN); + tstrncpy(pFunc->node.userAlias, pAias, TSDB_COL_NAME_LEN); pFunc->pParameterList = pParameterList; *ppResFunc = (SNode*)pFunc; return TSDB_CODE_SUCCESS; @@ -15999,7 +15999,7 @@ static int32_t createParTempTableNode(SSelectStmt* pSubquery, SNode** ppResTempT } pTempTable->pSubquery = (SNode*)pSubquery; taosRandStr(pTempTable->table.tableAlias, 8); - strcpy(pSubquery->stmtName, pTempTable->table.tableAlias); + tstrncpy(pSubquery->stmtName, pTempTable->table.tableAlias, TSDB_TABLE_NAME_LEN); pSubquery->isSubquery = true; *ppResTempTable = (SNode*)pTempTable; return TSDB_CODE_SUCCESS; diff --git a/source/libs/parser/src/parUtil.c b/source/libs/parser/src/parUtil.c index 44e44982a3..49095e215f 100644 --- a/source/libs/parser/src/parUtil.c +++ b/source/libs/parser/src/parUtil.c @@ -250,7 +250,7 @@ int32_t generateSyntaxErrMsgExt(SMsgBuf* pBuf, int32_t errCode, const char* pFor int32_t buildInvalidOperationMsg(SMsgBuf* pBuf, const char* msg) { if (pBuf->buf) { - strncpy(pBuf->buf, msg, pBuf->len); + tstrncpy(pBuf->buf, msg, pBuf->len); } return TSDB_CODE_TSC_INVALID_OPERATION; @@ -277,7 +277,7 @@ int32_t buildSyntaxErrMsg(SMsgBuf* pBuf, const char* additionalInfo, const char* } char buf[64] = {0}; // only extract part of sql string - strncpy(buf, sourceStr, tListLen(buf) - 1); + tstrncpy(buf, sourceStr, tListLen(buf)); if (additionalInfo != NULL) { snprintf(pBuf->buf, pBuf->len, msgFormat2, buf, additionalInfo); @@ -454,7 +454,7 @@ int32_t parseJsontoTagData(const char* json, SArray* pTagVals, STag** ppTag, voi continue; } STagVal val = {0}; - // strcpy(val.colName, colName); + // TSDB_DB_FNAME_LENme, colName); val.pKey = jsonKey; retCode = taosHashPut(keyHash, jsonKey, keyLen, &keyLen, CHAR_BYTES); // add key to hash to remove dumplicate, value is useless @@ -603,10 +603,10 @@ static int32_t getIntegerFromAuthStr(const char* pStart, char** pNext) { char* p = strchr(pStart, '*'); char buf[10] = {0}; if (NULL == p) { - strcpy(buf, pStart); + tstrncpy(buf, pStart, 10); *pNext = NULL; } else { - strncpy(buf, pStart, p - pStart); + tstrncpy(buf, pStart, p - pStart + 1); *pNext = ++p; } return taosStr2Int32(buf, NULL, 10); @@ -615,10 +615,10 @@ static int32_t getIntegerFromAuthStr(const char* pStart, char** pNext) { static void getStringFromAuthStr(const char* pStart, char* pStr, char** pNext) { char* p = strchr(pStart, '*'); if (NULL == p) { - strcpy(pStr, pStart); + tstrncpy(pStr, pStart, strlen(pStart) + 1); *pNext = NULL; } else { - strncpy(pStr, pStart, p - pStart); + tstrncpy(pStr, pStart, p - pStart + 1); *pNext = ++p; } if (*pStart == '`' && *(pStart + 1) == '`') { @@ -652,7 +652,7 @@ static int32_t buildTableReq(SHashObj* pTablesHash, SArray** pTables) { size_t len = 0; char* pKey = taosHashGetKey(p, &len); char fullName[TSDB_TABLE_FNAME_LEN] = {0}; - strncpy(fullName, pKey, len); + tstrncpy(fullName, pKey, len); SName name = {0}; int32_t code = tNameFromString(&name, fullName, T_NAME_ACCT | T_NAME_DB | T_NAME_TABLE); if (TSDB_CODE_SUCCESS == code) { @@ -683,7 +683,7 @@ static int32_t buildDbReq(SHashObj* pDbsHash, SArray** pDbs) { size_t len = 0; char* pKey = taosHashGetKey(p, &len); char fullName[TSDB_DB_FNAME_LEN] = {0}; - strncpy(fullName, pKey, len); + tstrncpy(fullName, pKey, len); if (NULL == taosArrayPush(*pDbs, fullName)) { taosHashCancelIterate(pDbsHash, p); taosArrayDestroy(*pDbs); @@ -707,7 +707,7 @@ static int32_t buildTableReqFromDb(SHashObj* pDbsHash, SArray** pDbs) { SParseTablesMetaReq* p = taosHashIterate(pDbsHash, NULL); while (NULL != p) { STablesReq req = {0}; - strcpy(req.dbFName, p->dbFName); + tstrncpy(req.dbFName, p->dbFName, TSDB_DB_FNAME_LEN); int32_t code = buildTableReq(p->pTables, &req.pTables); if (TSDB_CODE_SUCCESS == code) { if (NULL == taosArrayPush(*pDbs, &req)) { @@ -737,7 +737,7 @@ static int32_t buildUserAuthReq(SHashObj* pUserAuthHash, SArray** pUserAuth) { size_t len = 0; char* pKey = taosHashGetKey(p, &len); char key[USER_AUTH_KEY_MAX_LEN] = {0}; - strncpy(key, pKey, len); + tstrncpy(key, pKey, len); SUserAuthInfo userAuth = {0}; stringToUserAuth(key, len, &userAuth); if (NULL == taosArrayPush(*pUserAuth, &userAuth)) { @@ -763,7 +763,7 @@ static int32_t buildUdfReq(SHashObj* pUdfHash, SArray** pUdf) { size_t len = 0; char* pFunc = taosHashGetKey(p, &len); char func[TSDB_FUNC_NAME_LEN] = {0}; - strncpy(func, pFunc, len); + tstrncpy(func, pFunc, len); if (NULL == taosArrayPush(*pUdf, func)) { taosHashCancelIterate(pUdfHash, p); taosArrayDestroy(*pUdf); diff --git a/source/libs/planner/src/planOptimizer.c b/source/libs/planner/src/planOptimizer.c index 0a1f0bcbf6..a7b0836c5c 100644 --- a/source/libs/planner/src/planOptimizer.c +++ b/source/libs/planner/src/planOptimizer.c @@ -5489,8 +5489,8 @@ static int32_t tbCntScanOptCreateSumFunc(SFunctionNode* pCntFunc, SNode* pParam, if (NULL == pFunc) { return code; } - strcpy(pFunc->functionName, "sum"); - strcpy(pFunc->node.aliasName, pCntFunc->node.aliasName); + tstrncpy(pFunc->functionName, "sum", TSDB_FUNC_NAME_LEN); + tstrncpy(pFunc->node.aliasName, pCntFunc->node.aliasName, TSDB_COL_NAME_LEN); code = createColumnByRewriteExpr(pParam, &pFunc->pParameterList); if (TSDB_CODE_SUCCESS == code) { code = fmGetFuncInfo(pFunc, NULL, 0); diff --git a/source/libs/planner/src/planSpliter.c b/source/libs/planner/src/planSpliter.c index e0e42087f3..fc8731e40e 100644 --- a/source/libs/planner/src/planSpliter.c +++ b/source/libs/planner/src/planSpliter.c @@ -428,7 +428,7 @@ static int32_t stbSplAppendWStart(SNodeList* pFuncs, int32_t* pIndex, uint8_t pr if (NULL == pWStart) { return code; } - strcpy(pWStart->functionName, "_wstart"); + tstrncpy(pWStart->functionName, "_wstart", TSDB_FUNC_NAME_LEN); int64_t pointer = (int64_t)pWStart; char name[TSDB_COL_NAME_LEN + TSDB_POINTER_PRINT_BYTES + TSDB_NAME_DELIMITER_LEN + 1] = {0}; int32_t len = tsnprintf(name, sizeof(name) - 1, "%s.%" PRId64 "", pWStart->functionName, pointer); @@ -460,7 +460,7 @@ static int32_t stbSplAppendWEnd(SWindowLogicNode* pWin, int32_t* pIndex) { if (NULL == pWEnd) { return code; } - strcpy(pWEnd->functionName, "_wend"); + tstrncpy(pWEnd->functionName, "_wend", TSDB_FUNC_NAME_LEN); int64_t pointer = (int64_t)pWEnd; char name[TSDB_COL_NAME_LEN + TSDB_POINTER_PRINT_BYTES + TSDB_NAME_DELIMITER_LEN + 1] = {0}; int32_t len = tsnprintf(name, sizeof(name) - 1, "%s.%" PRId64 "", pWEnd->functionName, pointer); @@ -1137,8 +1137,8 @@ static int32_t stbSplAggNodeCreateMerge(SSplitContext* pCtx, SStableSplitInfo* p if (!nodesEqualNode(pParam, (SNode*)pCol)) continue; // use the colName of group_key func to make sure finding the right slot id for merge keys. - strcpy(pCol->colName, pFunc->node.aliasName); - strcpy(pCol->node.aliasName, pFunc->node.aliasName); + tstrncpy(pCol->colName, pFunc->node.aliasName, TSDB_COL_NAME_LEN); + tstrncpy(pCol->node.aliasName, pFunc->node.aliasName, TSDB_COL_NAME_LEN); memset(pCol->tableAlias, 0, TSDB_TABLE_NAME_LEN); break; } @@ -1267,15 +1267,15 @@ static int32_t stbSplCreateColumnNode(SExprNode* pExpr, SNode** ppNode) { return code; } if (QUERY_NODE_COLUMN == nodeType(pExpr)) { - strcpy(pCol->dbName, ((SColumnNode*)pExpr)->dbName); - strcpy(pCol->tableName, ((SColumnNode*)pExpr)->tableName); - strcpy(pCol->tableAlias, ((SColumnNode*)pExpr)->tableAlias); - strcpy(pCol->colName, ((SColumnNode*)pExpr)->colName); + tstrncpy(pCol->dbName, ((SColumnNode*)pExpr)->dbName, TSDB_DB_NAME_LEN); + tstrncpy(pCol->tableName, ((SColumnNode*)pExpr)->tableName, TSDB_TABLE_NAME_LEN); + tstrncpy(pCol->tableAlias, ((SColumnNode*)pExpr)->tableAlias, TSDB_TABLE_NAME_LEN); + tstrncpy(pCol->colName, ((SColumnNode*)pExpr)->colName, TSDB_COL_NAME_LEN); } else { - strcpy(pCol->colName, pExpr->aliasName); + tstrncpy(pCol->colName, pExpr->aliasName, TSDB_COL_NAME_LEN); } - strcpy(pCol->node.aliasName, pExpr->aliasName); - strcpy(pCol->node.userAlias, pExpr->userAlias); + tstrncpy(pCol->node.aliasName, pExpr->aliasName, TSDB_COL_NAME_LEN); + tstrncpy(pCol->node.userAlias, pExpr->userAlias, TSDB_COL_NAME_LEN); pCol->node.resType = pExpr->resType; *ppNode = (SNode*)pCol; return code; From 9a01b42bc28485bba8602e5edee3f347f889c037 Mon Sep 17 00:00:00 2001 From: wangjiaming0909 Date: Mon, 2 Dec 2024 16:20:40 +0800 Subject: [PATCH 04/62] replace unsafe funcs --- include/common/tcommon.h | 1 + source/dnode/mnode/impl/src/mndSma.c | 16 ++-- source/libs/nodes/src/nodesCloneFuncs.c | 6 +- source/libs/nodes/src/nodesUtilFuncs.c | 10 +- source/libs/parser/src/parAstCreater.c | 10 +- source/libs/parser/src/parTranslater.c | 42 ++++----- source/libs/parser/src/parUtil.c | 6 +- source/libs/parser/src/parser.c | 14 +-- source/libs/planner/src/planLogicCreater.c | 64 ++++++------- source/libs/planner/src/planOptimizer.c | 103 +++++++++------------ source/libs/planner/src/planPhysiCreater.c | 70 ++++++-------- source/libs/planner/src/planSpliter.c | 13 +-- source/libs/planner/src/planUtil.c | 14 +-- 13 files changed, 156 insertions(+), 213 deletions(-) diff --git a/include/common/tcommon.h b/include/common/tcommon.h index df78d6a249..111c9dde3c 100644 --- a/include/common/tcommon.h +++ b/include/common/tcommon.h @@ -398,6 +398,7 @@ int32_t taosGenCrashJsonMsg(int signum, char** pMsg, int64_t clusterId, int64_t int32_t dumpConfToDataBlock(SSDataBlock* pBlock, int32_t startCol); #define TSMA_RES_STB_POSTFIX "_tsma_res_stb_" +#define MD5_OUTPUT_LEN 32 #define TSMA_RES_STB_EXTRA_COLUMN_NUM 4 // 3 columns: _wstart, _wend, _wduration, 1 tag: tbname static inline bool isTsmaResSTb(const char* stbName) { diff --git a/source/dnode/mnode/impl/src/mndSma.c b/source/dnode/mnode/impl/src/mndSma.c index a54c7f1b14..aadc67c41f 100644 --- a/source/dnode/mnode/impl/src/mndSma.c +++ b/source/dnode/mnode/impl/src/mndSma.c @@ -797,7 +797,7 @@ static int32_t mndGetStreamNameFromSmaName(char *streamName, char *smaName) { if (TSDB_CODE_SUCCESS != code) { return code; } - sprintf(streamName, "%d.%s", n.acctId, n.tname); + snprintf(streamName, TSDB_TABLE_FNAME_LEN,"%d.%s", n.acctId, n.tname); return TSDB_CODE_SUCCESS; } @@ -1222,7 +1222,7 @@ static int32_t mndGetSma(SMnode *pMnode, SUserIndexReq *indexReq, SUserIndexRsp memcpy(rsp->dbFName, pSma->db, sizeof(pSma->db)); memcpy(rsp->tblFName, pSma->stb, sizeof(pSma->stb)); - strcpy(rsp->indexType, TSDB_INDEX_TYPE_SMA); + tstrncpy(rsp->indexType, TSDB_INDEX_TYPE_SMA, TSDB_INDEX_TYPE_LEN); SNodeList *pList = NULL; int32_t extOffset = 0; @@ -1255,8 +1255,8 @@ int32_t mndGetTableSma(SMnode *pMnode, char *tbFName, STableIndexRsp *rsp, bool return TSDB_CODE_SUCCESS; } - strcpy(rsp->dbFName, pStb->db); - strcpy(rsp->tbName, pStb->name + strlen(pStb->db) + 1); + tstrncpy(rsp->dbFName, pStb->db, TSDB_DB_FNAME_LEN); + tstrncpy(rsp->tbName, pStb->name + strlen(pStb->db) + 1, TSDB_TABLE_NAME_LEN); rsp->suid = pStb->uid; rsp->version = pStb->smaVer; mndReleaseStb(pMnode, pStb); @@ -1632,7 +1632,7 @@ static int32_t mndCreateTSMABuildCreateStreamReq(SCreateTSMACxt *pCxt) { f.bytes = pExprNode->resType.bytes; f.type = pExprNode->resType.type; f.flags = COL_SMA_ON; - strcpy(f.name, pExprNode->userAlias); + tstrncpy(f.name, pExprNode->userAlias, TSDB_COL_NAME_LEN); if (NULL == taosArrayPush(pCxt->pCreateStreamReq->pCols, &f)) { code = terrno; break; @@ -1735,7 +1735,7 @@ static int32_t mndCreateTSMATxnPrepare(SCreateTSMACxt* pCxt) { } dropStbReq.igNotExists = true; - strncpy(dropStbReq.name, pCxt->targetStbFullName, TSDB_TABLE_FNAME_LEN); + tstrncpy(dropStbReq.name, pCxt->targetStbFullName, TSDB_TABLE_FNAME_LEN); dropStbUndoAction.epSet = createStreamRedoAction.epSet; dropStbUndoAction.acceptableCode = TSDB_CODE_MND_STB_NOT_EXIST; dropStbUndoAction.retryCode = TSDB_CODE_MND_STREAM_MUST_BE_DELETED; @@ -1836,7 +1836,7 @@ static int32_t mndTSMAGenerateOutputName(const char* tsmaName, char* streamName, if (TSDB_CODE_SUCCESS != code) { return code; } - sprintf(streamName, "%d.%s", smaName.acctId, smaName.tname); + snprintf(streamName, TSDB_TABLE_FNAME_LEN, "%d.%s", smaName.acctId, smaName.tname); snprintf(targetStbName, TSDB_TABLE_FNAME_LEN, "%s"TSMA_RES_STB_POSTFIX, tsmaName); return TSDB_CODE_SUCCESS; } @@ -2486,7 +2486,7 @@ static int32_t mndGetSomeTsmas(SMnode* pMnode, STableTSMAInfoRsp* pRsp, tsmaFilt mndReleaseStb(pMnode, pStb); TAOS_RETURN(code); } - sprintf(streamName, "%d.%s", smaName.acctId, smaName.tname); + snprintf(streamName, TSDB_TABLE_FNAME_LEN, "%d.%s", smaName.acctId, smaName.tname); pStream = NULL; code = mndAcquireStream(pMnode, streamName, &pStream); diff --git a/source/libs/nodes/src/nodesCloneFuncs.c b/source/libs/nodes/src/nodesCloneFuncs.c index c2deec9c68..f272236080 100644 --- a/source/libs/nodes/src/nodesCloneFuncs.c +++ b/source/libs/nodes/src/nodesCloneFuncs.c @@ -26,9 +26,9 @@ (pDst)->fldname = (pSrc)->fldname; \ } while (0) -#define COPY_CHAR_ARRAY_FIELD(fldname) \ - do { \ - strcpy((pDst)->fldname, (pSrc)->fldname); \ +#define COPY_CHAR_ARRAY_FIELD(fldname) \ + do { \ + tstrncpy((pDst)->fldname, (pSrc)->fldname, sizeof((pDst)->fldname)); \ } while (0) #define COPY_OBJECT_FIELD(fldname, size) \ diff --git a/source/libs/nodes/src/nodesUtilFuncs.c b/source/libs/nodes/src/nodesUtilFuncs.c index 04b0d56a63..d75f39f376 100644 --- a/source/libs/nodes/src/nodesUtilFuncs.c +++ b/source/libs/nodes/src/nodesUtilFuncs.c @@ -2339,7 +2339,7 @@ char* nodesGetStrValueFromNode(SValueNode* pNode) { return NULL; } - sprintf(buf, "%s", pNode->datum.b ? "true" : "false"); + snprintf(buf, MAX_NUM_STR_SIZE, "%s", pNode->datum.b ? "true" : "false"); return buf; } case TSDB_DATA_TYPE_TINYINT: @@ -2352,7 +2352,7 @@ char* nodesGetStrValueFromNode(SValueNode* pNode) { return NULL; } - sprintf(buf, "%" PRId64, pNode->datum.i); + snprintf(buf, MAX_NUM_STR_SIZE, "%" PRId64, pNode->datum.i); return buf; } case TSDB_DATA_TYPE_UTINYINT: @@ -2364,7 +2364,7 @@ char* nodesGetStrValueFromNode(SValueNode* pNode) { return NULL; } - sprintf(buf, "%" PRIu64, pNode->datum.u); + snprintf(buf, MAX_NUM_STR_SIZE, "%" PRIu64, pNode->datum.u); return buf; } case TSDB_DATA_TYPE_FLOAT: @@ -2374,7 +2374,7 @@ char* nodesGetStrValueFromNode(SValueNode* pNode) { return NULL; } - sprintf(buf, "%e", pNode->datum.d); + snprintf(buf, MAX_NUM_STR_SIZE, "%e", pNode->datum.d); return buf; } case TSDB_DATA_TYPE_NCHAR: @@ -2530,7 +2530,7 @@ static EDealRes doCollect(SCollectColumnsCxt* pCxt, SColumnNode* pCol, SNode* pN } if (pCol->projRefIdx > 0) { len = taosHashBinary(name, strlen(name)); - len += sprintf(name + len, "_%d", pCol->projRefIdx); + len += tsnprintf(name + len, TSDB_TABLE_NAME_LEN + TSDB_COL_NAME_LEN - len, "_%d", pCol->projRefIdx); } SNode** pNodeFound = taosHashGet(pCxt->pColHash, name, len); if (pNodeFound == NULL) { diff --git a/source/libs/parser/src/parAstCreater.c b/source/libs/parser/src/parAstCreater.c index f6602fc731..de8353046e 100644 --- a/source/libs/parser/src/parAstCreater.c +++ b/source/libs/parser/src/parAstCreater.c @@ -333,7 +333,7 @@ SNode* releaseRawExprNode(SAstCreateContext* pCxt, SNode* pNode) { // Len of pRawExpr->p could be larger than len of aliasName[TSDB_COL_NAME_LEN]. // If aliasName is truncated, hash value of aliasName could be the same. uint64_t hashVal = MurmurHash3_64(pRawExpr->p, pRawExpr->n); - sprintf(pExpr->aliasName, "%" PRIu64, hashVal); + snprintf(pExpr->aliasName, TSDB_COL_NAME_LEN, "%" PRIu64, hashVal); tstrncpy(pExpr->userAlias, pRawExpr->p, len); } } @@ -945,11 +945,11 @@ SNode* createOperatorNode(SAstCreateContext* pCxt, EOperatorType type, SNode* pL goto _err; } if ('+' == pVal->literal[0]) { - sprintf(pNewLiteral, "-%s", pVal->literal + 1); + snprintf(pNewLiteral, strlen(pVal->literal) + 2, "-%s", pVal->literal + 1); } else if ('-' == pVal->literal[0]) { - sprintf(pNewLiteral, "%s", pVal->literal + 1); + snprintf(pNewLiteral, strlen(pVal->literal) + 2, "%s", pVal->literal + 1); } else { - sprintf(pNewLiteral, "-%s", pVal->literal); + snprintf(pNewLiteral, strlen(pVal->literal) + 2, "-%s", pVal->literal); } taosMemoryFree(pVal->literal); pVal->literal = pNewLiteral; @@ -1761,7 +1761,7 @@ SNode* createSetOperator(SAstCreateContext* pCxt, ESetOperatorType type, SNode* setSubquery(setOp->pLeft); setOp->pRight = pRight; setSubquery(setOp->pRight); - sprintf(setOp->stmtName, "%p", setOp); + snprintf(setOp->stmtName, TSDB_TABLE_NAME_LEN, "%p", setOp); return (SNode*)setOp; _err: nodesDestroyNode(pLeft); diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index dec4ac9328..476d9e1b1c 100755 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -1628,7 +1628,7 @@ static void biMakeAliasNameInMD5(char* pExprStr, int32_t len, char* pAlias) { tMD5Final(&ctx); char* p = pAlias; for (uint8_t i = 0; i < tListLen(ctx.digest); ++i) { - sprintf(p, "%02x", ctx.digest[i]); + snprintf(p, len + 1 - 2 * i, "%02x", ctx.digest[i]); p += 2; } } @@ -4333,7 +4333,7 @@ static int32_t setTableTsmas(STranslateContext* pCxt, SName* pName, SRealTableNo } } if (code == TSDB_CODE_SUCCESS) { - sprintf(ctbInfo.tableName, "%s", tsmaTargetTbName.tname); + snprintf(ctbInfo.tableName, TSDB_TABLE_NAME_LEN, "%s", tsmaTargetTbName.tname); ctbInfo.uid = pTableMeta->uid; taosMemoryFree(pTableMeta); } else if (TSDB_CODE_PAR_TABLE_NOT_EXIST == code) { @@ -5437,7 +5437,7 @@ static int32_t rewriteProjectAlias(SNodeList* pProjectionList) { if ('\0' == pExpr->userAlias[0]) { tstrncpy(pExpr->userAlias, pExpr->aliasName, TSDB_COL_NAME_LEN); } - sprintf(pExpr->aliasName, "#expr_%d", no++); + snprintf(pExpr->aliasName, TSDB_COL_NAME_LEN,"#expr_%d", no++); } return TSDB_CODE_SUCCESS; } @@ -6743,7 +6743,7 @@ static int32_t replaceToChildTableQuery(STranslateContext* pCxt, SEqCondTbNameTa break; } } - sprintf(ctbInfo.tableName, "%s", tsmaTargetTbName.tname); + snprintf(ctbInfo.tableName, TSDB_TABLE_NAME_LEN, "%s", tsmaTargetTbName.tname); ctbInfo.uid = pMeta->uid; if (NULL == taosArrayPush(pRealTable->tsmaTargetTbInfo, &ctbInfo)) { @@ -6808,7 +6808,7 @@ static int32_t setEqualTbnameTableVgroups(STranslateContext* pCxt, SSelectStmt* code = terrno; break; } - sprintf(pNewTbName, "%s.%s_%s", pTsma->dbFName, pTsma->name, pTbName); + snprintf(pNewTbName, TSDB_TABLE_FNAME_LEN + TSDB_TABLE_NAME_LEN + 1, "%s.%s_%s", pTsma->dbFName, pTsma->name, pTbName); int32_t len = taosCreateMD5Hash(pNewTbName, strlen(pNewTbName)); } if (TSDB_CODE_SUCCESS == code) { @@ -8985,7 +8985,7 @@ static int32_t buildProjectsForSampleAst(SSampleAstInfo* pInfo, SNodeList** pLis SNode* pProject = NULL; if (pProjectionTotalLen) *pProjectionTotalLen = 0; FOREACH(pProject, pProjectionList) { - sprintf(((SExprNode*)pProject)->aliasName, "#%p", pProject); + snprintf(((SExprNode*)pProject)->aliasName, TSDB_COL_NAME_LEN, "#%p", pProject); if (pProjectionTotalLen) *pProjectionTotalLen += ((SExprNode*)pProject)->resType.bytes; } *pList = pProjectionList; @@ -9023,7 +9023,7 @@ static int32_t buildSampleAst(STranslateContext* pCxt, SSampleAstInfo* pInfo, ch if (NULL == pSelect) { return code; } - sprintf(pSelect->stmtName, "%p", pSelect); + snprintf(pSelect->stmtName, TSDB_TABLE_NAME_LEN, "%p", pSelect); code = buildTableForSampleAst(pInfo, &pSelect->pFromTable); if (TSDB_CODE_SUCCESS == code) { @@ -11308,9 +11308,6 @@ static int32_t adjustOrderOfProjections(STranslateContext* pCxt, SNodeList** ppC code = nodesMakeList(&pNewProjections); if (TSDB_CODE_SUCCESS != code) return code; code = nodesMakeList(&pNewCols); - if (TSDB_CODE_SUCCESS != code) { - code = code; - } for (int32_t i = 0; TSDB_CODE_SUCCESS == code && i < num; ++i) { SProjColPos* pPos = taosArrayGet(pProjColPos, i); code = nodesListStrictAppend(pNewProjections, pPos->pProj); @@ -11416,9 +11413,6 @@ static int32_t adjustOrderOfTags(STranslateContext* pCxt, SNodeList* pTags, cons int32_t numOfTags = getNumOfTags(pMeta); const SSchema* pTagsSchema = getTableTagSchema(pMeta); code = nodesMakeList(&pNewTagExprs); - if (NULL == pNewTagExprs) { - code = code; - } for (int32_t i = 0; TSDB_CODE_SUCCESS == code && i < numOfTags; ++i) { const SSchema* pTagSchema = pTagsSchema + i; if (indexOfBoundTags < numOfBoundTags) { @@ -12214,8 +12208,8 @@ static int32_t translateGrant(STranslateContext* pCxt, SGrantStmt* pStmt) { #endif tstrncpy(req.user, pStmt->userName, TSDB_USER_LEN); - sprintf(req.objname, "%d.%s", pCxt->pParseCxt->acctId, pStmt->objName); - sprintf(req.tabName, "%s", pStmt->tabName); + snprintf(req.objname, TSDB_DB_FNAME_LEN, "%d.%s", pCxt->pParseCxt->acctId, pStmt->objName); + snprintf(req.tabName, TSDB_TABLE_NAME_LEN, "%s", pStmt->tabName); if (!req.isView) { code = translateGrantTagCond(pCxt, pStmt, &req); } @@ -12250,8 +12244,8 @@ static int32_t translateRevoke(STranslateContext* pCxt, SRevokeStmt* pStmt) { #endif tstrncpy(req.user, pStmt->userName, TSDB_USER_LEN); - sprintf(req.objname, "%d.%s", pCxt->pParseCxt->acctId, pStmt->objName); - sprintf(req.tabName, "%s", pStmt->tabName); + snprintf(req.objname, TSDB_DB_FNAME_LEN, "%d.%s", pCxt->pParseCxt->acctId, pStmt->objName); + snprintf(req.tabName, TSDB_TABLE_NAME_LEN, "%s", pStmt->tabName); code = buildCmdMsg(pCxt, TDMT_MND_ALTER_USER, (FSerializeFunc)tSerializeSAlterUserReq, &req); tFreeSAlterUserReq(&req); return code; @@ -12434,14 +12428,14 @@ static int32_t buildTSMAAstStreamSubTable(SCreateTSMAStmt* pStmt, SMCreateSmaReq code = nodesMakeNode(QUERY_NODE_VALUE, (SNode**)&pVal); if (TSDB_CODE_SUCCESS != code) goto _end; - sprintf(pMd5Func->functionName, "%s", "md5"); - sprintf(pConcatFunc->functionName, "%s", "concat"); + snprintf(pMd5Func->functionName, TSDB_FUNC_NAME_LEN, "%s", "md5"); + snprintf(pConcatFunc->functionName, TSDB_FUNC_NAME_LEN, "%s", "concat"); pVal->literal = taosMemoryMalloc(TSDB_TABLE_FNAME_LEN + 1); if (!pVal->literal) { code = terrno; goto _end; } - sprintf(pVal->literal, "%s_", pReq->name); + snprintf(pVal->literal, TSDB_TABLE_FNAME_LEN + 1, "%s_", pReq->name); pVal->node.resType.type = TSDB_DATA_TYPE_VARCHAR; pVal->node.resType.bytes = strlen(pVal->literal); code = nodesListMakeAppend(&pConcatFunc->pParameterList, (SNode*)pVal); @@ -12485,10 +12479,8 @@ static int32_t buildTSMAAst(STranslateContext* pCxt, SCreateTSMAStmt* pStmt, SMC // append partition by tbname code = createTbnameFunction(&pTbnameFunc); if (pTbnameFunc) { - sprintf(pTbnameFunc->node.userAlias, "tbname"); + snprintf(pTbnameFunc->node.userAlias, TSDB_COL_NAME_LEN, "tbname"); code = nodesListMakeStrictAppend(&info.pPartitionByList, (SNode*)pTbnameFunc); - } else { - code = code; } } if (TSDB_CODE_SUCCESS == code) { @@ -13363,7 +13355,7 @@ static int32_t createSimpleSelectStmtImpl(const char* pDb, const char* pTable, S if (NULL == pSelect) { return code; } - sprintf(pSelect->stmtName, "%p", pSelect); + snprintf(pSelect->stmtName, TSDB_TABLE_NAME_LEN, "%p", pSelect); SRealTableNode* pRealTable = NULL; code = nodesMakeNode(QUERY_NODE_REAL_TABLE, (SNode**)&pRealTable); @@ -16415,7 +16407,7 @@ static int32_t rewriteShowAliveStmt(STranslateContext* pCxt, SQuery* pQuery) { pStmt->pProjectionList = pProjList; pStmt->pFromTable = pTempTblNode; - sprintf(pStmt->stmtName, "%p", pStmt); + snprintf(pStmt->stmtName, TSDB_TABLE_NAME_LEN, "%p", pStmt); nodesDestroyNode(pQuery->pRoot); pQuery->pRoot = (SNode*)pStmt; diff --git a/source/libs/parser/src/parUtil.c b/source/libs/parser/src/parUtil.c index 49095e215f..bb54864066 100644 --- a/source/libs/parser/src/parUtil.c +++ b/source/libs/parser/src/parUtil.c @@ -595,8 +595,8 @@ int32_t getVnodeSysTableTargetName(int32_t acctId, SNode* pWhere, SName* pName) static int32_t userAuthToString(int32_t acctId, const char* pUser, const char* pDb, const char* pTable, AUTH_TYPE type, char* pStr, bool isView) { - return sprintf(pStr, "%s*%d*%s*%s*%d*%d", pUser, acctId, pDb, (NULL == pTable || '\0' == pTable[0]) ? "``" : pTable, - type, isView); + return snprintf(pStr, USER_AUTH_KEY_MAX_LEN, "%s*%d*%s*%s*%d*%d", pUser, acctId, pDb, + (NULL == pTable || '\0' == pTable[0]) ? "``" : pTable, type, isView); } static int32_t getIntegerFromAuthStr(const char* pStart, char** pNext) { @@ -831,7 +831,7 @@ int32_t createSelectStmtImpl(bool isDistinct, SNodeList* pProjectionList, SNode* select->isDistinct = isDistinct; select->pProjectionList = pProjectionList; select->pFromTable = pTable; - sprintf(select->stmtName, "%p", select); + snprintf(select->stmtName, TSDB_TABLE_NAME_LEN, "%p", select); select->timeLineResMode = select->isDistinct ? TIME_LINE_NONE : TIME_LINE_GLOBAL; select->timeLineCurMode = TIME_LINE_GLOBAL; select->onlyHasKeepOrderFunc = true; diff --git a/source/libs/parser/src/parser.c b/source/libs/parser/src/parser.c index 8ac1acb1a2..c7ce5334d6 100644 --- a/source/libs/parser/src/parser.c +++ b/source/libs/parser/src/parser.c @@ -109,7 +109,7 @@ bool qParseDbName(const char* pStr, size_t length, char** pDbName) { if (*pDbName == NULL) { return false; } - strncpy(*pDbName, t.z, dbNameLen); + tstrncpy(*pDbName, t.z, dbNameLen); (*pDbName)[dbNameLen] = '\0'; return true; } @@ -185,7 +185,7 @@ static int32_t setValueByBindParam(SValueNode* pVal, TAOS_MULTI_BIND* pParam) { return terrno; } varDataSetLen(pVal->datum.p, pVal->node.resType.bytes); - strncpy(varDataVal(pVal->datum.p), (const char*)pParam->buffer, pVal->node.resType.bytes); + tstrncpy(varDataVal(pVal->datum.p), (const char*)pParam->buffer, pVal->node.resType.bytes); pVal->node.resType.bytes += VARSTR_HEADER_SIZE; break; case TSDB_DATA_TYPE_NCHAR: { @@ -218,7 +218,7 @@ static int32_t setValueByBindParam(SValueNode* pVal, TAOS_MULTI_BIND* pParam) { static EDealRes rewriteQueryExprAliasImpl(SNode* pNode, void* pContext) { if (nodesIsExprNode(pNode) && QUERY_NODE_COLUMN != nodeType(pNode)) { - sprintf(((SExprNode*)pNode)->aliasName, "#%d", *(int32_t*)pContext); + snprintf(((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN, "#%d", *(int32_t*)pContext); ++(*(int32_t*)pContext); } return DEAL_RES_CONTINUE; @@ -433,9 +433,6 @@ int32_t qStmtBindParams(SQuery* pQuery, TAOS_MULTI_BIND* pParams, int32_t colIdx nodesDestroyNode(pQuery->pRoot); pQuery->pRoot = NULL; code = nodesCloneNode(pQuery->pPrepareRoot, &pQuery->pRoot); - if (NULL == pQuery->pRoot) { - code = code; - } } if (TSDB_CODE_SUCCESS == code) { rewriteExprAlias(pQuery->pRoot); @@ -475,7 +472,7 @@ static int32_t setValueByBindParam2(SValueNode* pVal, TAOS_STMT2_BIND* pParam) { return terrno; } varDataSetLen(pVal->datum.p, pVal->node.resType.bytes); - strncpy(varDataVal(pVal->datum.p), (const char*)pParam->buffer, pVal->node.resType.bytes); + tstrncpy(varDataVal(pVal->datum.p), (const char*)pParam->buffer, pVal->node.resType.bytes); pVal->node.resType.bytes += VARSTR_HEADER_SIZE; break; case TSDB_DATA_TYPE_NCHAR: { @@ -525,9 +522,6 @@ int32_t qStmtBindParams2(SQuery* pQuery, TAOS_STMT2_BIND* pParams, int32_t colId nodesDestroyNode(pQuery->pRoot); pQuery->pRoot = NULL; code = nodesCloneNode(pQuery->pPrepareRoot, &pQuery->pRoot); - if (NULL == pQuery->pRoot) { - code = code; - } } if (TSDB_CODE_SUCCESS == code) { rewriteExprAlias(pQuery->pRoot); diff --git a/source/libs/planner/src/planLogicCreater.c b/source/libs/planner/src/planLogicCreater.c index 47a0144243..527412f8c0 100644 --- a/source/libs/planner/src/planLogicCreater.c +++ b/source/libs/planner/src/planLogicCreater.c @@ -119,9 +119,9 @@ static EDealRes doRewriteExpr(SNode** pNode, void* pContext) { } SExprNode* pToBeRewrittenExpr = (SExprNode*)(*pNode); pCol->node.resType = pToBeRewrittenExpr->resType; - strcpy(pCol->node.aliasName, pToBeRewrittenExpr->aliasName); - strcpy(pCol->node.userAlias, ((SExprNode*)pExpr)->userAlias); - strcpy(pCol->colName, ((SExprNode*)pExpr)->aliasName); + tstrncpy(pCol->node.aliasName, pToBeRewrittenExpr->aliasName, TSDB_COL_NAME_LEN); + tstrncpy(pCol->node.userAlias, ((SExprNode*)pExpr)->userAlias, TSDB_COL_NAME_LEN); + tstrncpy(pCol->colName, ((SExprNode*)pExpr)->aliasName, TSDB_COL_NAME_LEN); pCol->node.projIdx = ((SExprNode*)(*pNode))->projIdx; if (QUERY_NODE_FUNCTION == nodeType(pExpr)) { setColumnInfo((SFunctionNode*)pExpr, pCol, pCxt->isPartitionBy); @@ -150,7 +150,7 @@ static EDealRes doNameExpr(SNode* pNode, void* pContext) { case QUERY_NODE_LOGIC_CONDITION: case QUERY_NODE_FUNCTION: { if ('\0' == ((SExprNode*)pNode)->aliasName[0]) { - sprintf(((SExprNode*)pNode)->aliasName, "#expr_%p", pNode); + snprintf(((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN, "#expr_%p", pNode); } return DEAL_RES_IGNORE_CHILD; } @@ -305,12 +305,12 @@ static SNode* createFirstCol(SRealTableNode* pTable, const SSchema* pSchema) { pCol->tableId = pTable->pMeta->uid; pCol->colId = pSchema->colId; pCol->colType = COLUMN_TYPE_COLUMN; - strcpy(pCol->tableAlias, pTable->table.tableAlias); - strcpy(pCol->tableName, pTable->table.tableName); + tstrncpy(pCol->tableAlias, pTable->table.tableAlias, TSDB_TABLE_NAME_LEN); + tstrncpy(pCol->tableName, pTable->table.tableName, TSDB_TABLE_NAME_LEN); pCol->isPk = pSchema->flags & COL_IS_KEY; pCol->tableHasPk = hasPkInTable(pTable->pMeta); pCol->numOfPKs = pTable->pMeta->tableInfo.numOfPKs; - strcpy(pCol->colName, pSchema->name); + tstrncpy(pCol->colName, pSchema->name, TSDB_COL_NAME_LEN); return (SNode*)pCol; } @@ -386,8 +386,8 @@ static int32_t makeScanLogicNode(SLogicPlanContext* pCxt, SRealTableNode* pRealT pScan->scanRange = TSWINDOW_INITIALIZER; pScan->tableName.type = TSDB_TABLE_NAME_T; pScan->tableName.acctId = pCxt->pPlanCxt->acctId; - strcpy(pScan->tableName.dbname, pRealTable->table.dbName); - strcpy(pScan->tableName.tname, pRealTable->table.tableName); + tstrncpy(pScan->tableName.dbname, pRealTable->table.dbName, TSDB_DB_NAME_LEN); + tstrncpy(pScan->tableName.tname, pRealTable->table.tableName, TSDB_TABLE_NAME_LEN); pScan->showRewrite = pCxt->pPlanCxt->showRewrite; pScan->ratio = pRealTable->ratio; pScan->dataRequired = FUNC_DATA_REQUIRED_DATA_LOAD; @@ -776,12 +776,12 @@ static int32_t addWinJoinPrimKeyToAggFuncs(SSelectStmt* pSelect, SNodeList** pLi } SSchema* pColSchema = &pProbeTable->pMeta->schema[0]; - strcpy(pCol->dbName, pProbeTable->table.dbName); - strcpy(pCol->tableAlias, pProbeTable->table.tableAlias); - strcpy(pCol->tableName, pProbeTable->table.tableName); - strcpy(pCol->colName, pColSchema->name); - strcpy(pCol->node.aliasName, pColSchema->name); - strcpy(pCol->node.userAlias, pColSchema->name); + tstrncpy(pCol->dbName, pProbeTable->table.dbName, TSDB_DB_NAME_LEN); + tstrncpy(pCol->tableAlias, pProbeTable->table.tableAlias, TSDB_TABLE_NAME_LEN); + tstrncpy(pCol->tableName, pProbeTable->table.tableName, TSDB_TABLE_NAME_LEN); + tstrncpy(pCol->colName, pColSchema->name, TSDB_COL_NAME_LEN); + tstrncpy(pCol->node.aliasName, pColSchema->name, TSDB_COL_NAME_LEN); + tstrncpy(pCol->node.userAlias, pColSchema->name, TSDB_COL_NAME_LEN); pCol->tableId = pProbeTable->pMeta->uid; pCol->tableType = pProbeTable->pMeta->tableType; pCol->colId = pColSchema->colId; @@ -1547,21 +1547,20 @@ static int32_t createSortLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect if (TSDB_CODE_SUCCESS == code) { pSort->pSortKeys = NULL; code = nodesCloneList(pSelect->pOrderByList, &pSort->pSortKeys); - if (NULL == pSort->pSortKeys) { - code = code; - } - SNode* pNode = NULL; - SOrderByExprNode* firstSortKey = (SOrderByExprNode*)nodesListGetNode(pSort->pSortKeys, 0); - if (isPrimaryKeySort(pSelect->pOrderByList)) pSort->node.outputTsOrder = firstSortKey->order; - if (firstSortKey->pExpr->type == QUERY_NODE_COLUMN) { - SColumnNode* pCol = (SColumnNode*)firstSortKey->pExpr; - int16_t projIdx = 1; - FOREACH(pNode, pSelect->pProjectionList) { - SExprNode* pExpr = (SExprNode*)pNode; - if (0 == strcmp(pCol->node.aliasName, pExpr->aliasName)) { - pCol->projIdx = projIdx; break; + if (TSDB_CODE_SUCCESS == code) { + SNode* pNode = NULL; + SOrderByExprNode* firstSortKey = (SOrderByExprNode*)nodesListGetNode(pSort->pSortKeys, 0); + if (isPrimaryKeySort(pSelect->pOrderByList)) pSort->node.outputTsOrder = firstSortKey->order; + if (firstSortKey->pExpr->type == QUERY_NODE_COLUMN) { + SColumnNode* pCol = (SColumnNode*)firstSortKey->pExpr; + int16_t projIdx = 1; + FOREACH(pNode, pSelect->pProjectionList) { + SExprNode* pExpr = (SExprNode*)pNode; + if (0 == strcmp(pCol->node.aliasName, pExpr->aliasName)) { + pCol->projIdx = projIdx; break; + } + projIdx++; } - projIdx++; } } } @@ -1615,10 +1614,7 @@ static int32_t createProjectLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSel pProject->pProjections = NULL; code = nodesCloneList(pSelect->pProjectionList, &pProject->pProjections); - if (NULL == pProject->pProjections) { - code = code; - } - strcpy(pProject->stmtName, pSelect->stmtName); + tstrncpy(pProject->stmtName, pSelect->stmtName, TSDB_TABLE_NAME_LEN); if (TSDB_CODE_SUCCESS == code) { code = createColumnByProjections(pCxt, pSelect->stmtName, pSelect->pProjectionList, &pProject->node.pTargets); @@ -2108,7 +2104,7 @@ static int32_t createVnodeModifLogicNodeByDelete(SLogicPlanContext* pCxt, SDelet pModify->tableId = pRealTable->pMeta->uid; pModify->tableType = pRealTable->pMeta->tableType; snprintf(pModify->tableName, sizeof(pModify->tableName), "%s", pRealTable->table.tableName); - strcpy(pModify->tsColName, pRealTable->pMeta->schema->name); + tstrncpy(pModify->tsColName, pRealTable->pMeta->schema->name, TSDB_COL_NAME_LEN); pModify->deleteTimeRange = pDelete->timeRange; pModify->pAffectedRows = NULL; code = nodesCloneNode(pDelete->pCountFunc, &pModify->pAffectedRows); diff --git a/source/libs/planner/src/planOptimizer.c b/source/libs/planner/src/planOptimizer.c index a7b0836c5c..63ce847cdf 100644 --- a/source/libs/planner/src/planOptimizer.c +++ b/source/libs/planner/src/planOptimizer.c @@ -184,7 +184,7 @@ static EDealRes optRebuildTbanme(SNode** pNode, void* pContext) { *(int32_t*)pContext = code; return DEAL_RES_ERROR; } - strcpy(pFunc->functionName, "tbname"); + tstrncpy(pFunc->functionName, "tbname", TSDB_FUNC_NAME_LEN); pFunc->funcType = FUNCTION_TYPE_TBNAME; pFunc->node.resType = ((SColumnNode*)*pNode)->node.resType; nodesDestroyNode(*pNode); @@ -1291,9 +1291,7 @@ static int32_t pdcJoinAddPreFilterColsToTarget(SOptimizeContext* pCxt, SJoinLogi SNodeList* pCondCols = NULL; code = nodesMakeList(&pCondCols); SNodeList* pTargets = NULL; - if (NULL == pCondCols) { - code = code; - } else { + if (TSDB_CODE_SUCCESS == code) { code = nodesCollectColumnsFromNode(pJoin->pColOnCond, NULL, COLLECT_COL_TYPE_ALL, &pCondCols); } if (TSDB_CODE_SUCCESS == code) { @@ -2927,9 +2925,9 @@ static int32_t smaIndexOptCreateSmaCol(SNode* pFunc, uint64_t tableId, int32_t c pCol->tableType = TSDB_SUPER_TABLE; pCol->colId = colId; pCol->colType = COLUMN_TYPE_COLUMN; - strcpy(pCol->colName, ((SExprNode*)pFunc)->aliasName); + tstrncpy(pCol->colName, ((SExprNode*)pFunc)->aliasName, TSDB_COL_NAME_LEN); pCol->node.resType = ((SExprNode*)pFunc)->resType; - strcpy(pCol->node.aliasName, ((SExprNode*)pFunc)->aliasName); + tstrncpy(pCol->node.aliasName, ((SExprNode*)pFunc)->aliasName, TSDB_COL_NAME_LEN); *ppNode = pCol; return code; } @@ -2998,7 +2996,7 @@ static int32_t smaIndexOptCreateSmaCols(SNodeList* pFuncs, uint64_t tableId, SNo } SExprNode exprNode; exprNode.resType = ((SExprNode*)pWsNode)->resType; - sprintf(exprNode.aliasName, "#expr_%d", index + 1); + snprintf(exprNode.aliasName, TSDB_COL_NAME_LEN, "#expr_%d", index + 1); SColumnNode* pkNode = NULL; code = smaIndexOptCreateSmaCol((SNode*)&exprNode, tableId, PRIMARYKEY_TIMESTAMP_COL_ID, &pkNode); if (TSDB_CODE_SUCCESS != code) { @@ -3168,7 +3166,7 @@ static void partTagsSetAlias(char* pAlias, const char* pTableAlias, const char* int32_t len = tsnprintf(name, TSDB_COL_FNAME_LEN, "%s.%s", pTableAlias, pColName); (void)taosHashBinary(name, len); - strncpy(pAlias, name, TSDB_COL_NAME_LEN - 1); + tstrncpy(pAlias, name, TSDB_COL_NAME_LEN); } static int32_t partTagsCreateWrapperFunc(const char* pFuncName, SNode* pNode, SFunctionNode** ppNode) { @@ -3186,7 +3184,7 @@ static int32_t partTagsCreateWrapperFunc(const char* pFuncName, SNode* pNode, SF SColumnNode* pCol = (SColumnNode*)pNode; partTagsSetAlias(pFunc->node.aliasName, pCol->tableAlias, pCol->colName); } else { - strcpy(pFunc->node.aliasName, ((SExprNode*)pNode)->aliasName); + tstrncpy(pFunc->node.aliasName, ((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN); } code = nodesCloneNode(pNode, &pNew); if (TSDB_CODE_SUCCESS == code) { @@ -3472,7 +3470,7 @@ static EDealRes eliminateProjOptRewriteScanTableAlias(SNode* pNode, void* pConte if (QUERY_NODE_COLUMN == nodeType(pNode)) { SColumnNode* pCol = (SColumnNode*)pNode; RewriteTableAliasCxt* pCtx = (RewriteTableAliasCxt*)pContext; - strncpy(pCol->tableAlias, pCtx->newTableAlias, TSDB_TABLE_NAME_LEN); + tstrncpy(pCol->tableAlias, pCtx->newTableAlias, TSDB_TABLE_NAME_LEN); } return DEAL_RES_CONTINUE; } @@ -3727,7 +3725,7 @@ static int32_t rewriteTailOptCreateProjectExpr(SFunctionNode* pFunc, SNode** ppN if (NULL == pExpr) { return code; } - strcpy(((SExprNode*)pExpr)->aliasName, pFunc->node.aliasName); + tstrncpy(((SExprNode*)pExpr)->aliasName, pFunc->node.aliasName, TSDB_COL_NAME_LEN); *ppNode = pExpr; return code; } @@ -3883,15 +3881,15 @@ static int32_t rewriteUniqueOptCreateFirstFunc(SFunctionNode* pSelectValue, SNod return code; } - strcpy(pFunc->functionName, "first"); + tstrncpy(pFunc->functionName, "first", TSDB_FUNC_NAME_LEN); if (NULL != pSelectValue) { - strcpy(pFunc->node.aliasName, pSelectValue->node.aliasName); + tstrncpy(pFunc->node.aliasName, pSelectValue->node.aliasName, TSDB_COL_NAME_LEN); } else { int64_t pointer = (int64_t)pFunc; char name[TSDB_FUNC_NAME_LEN + TSDB_POINTER_PRINT_BYTES + TSDB_NAME_DELIMITER_LEN + 1] = {0}; int32_t len = tsnprintf(name, sizeof(name) - 1, "%s.%" PRId64 "", pFunc->functionName, pointer); (void)taosHashBinary(name, len); - strncpy(pFunc->node.aliasName, name, TSDB_COL_NAME_LEN - 1); + tstrncpy(pFunc->node.aliasName, name, TSDB_COL_NAME_LEN); } SNode* pNew = NULL; code = nodesCloneNode(pCol, &pNew); @@ -3989,15 +3987,15 @@ static int32_t rewriteUniqueOptCreateProjectCol(SFunctionNode* pFunc, SNode** pp if (FUNCTION_TYPE_UNIQUE == pFunc->funcType) { SExprNode* pExpr = (SExprNode*)nodesListGetNode(pFunc->pParameterList, 0); if (QUERY_NODE_COLUMN == nodeType(pExpr)) { - strcpy(pCol->tableAlias, ((SColumnNode*)pExpr)->tableAlias); - strcpy(pCol->colName, ((SColumnNode*)pExpr)->colName); + tstrncpy(pCol->tableAlias, ((SColumnNode*)pExpr)->tableAlias, TSDB_TABLE_NAME_LEN); + tstrncpy(pCol->colName, ((SColumnNode*)pExpr)->colName, TSDB_COL_NAME_LEN); } else { - strcpy(pCol->colName, pExpr->aliasName); + tstrncpy(pCol->colName, pExpr->aliasName, TSDB_COL_NAME_LEN); } } else { - strcpy(pCol->colName, pFunc->node.aliasName); + tstrncpy(pCol->colName, pFunc->node.aliasName, TSDB_COL_NAME_LEN); } - strcpy(pCol->node.aliasName, pFunc->node.aliasName); + tstrncpy(pCol->node.aliasName, pFunc->node.aliasName, TSDB_COL_NAME_LEN); *ppNode = (SNode*)pCol; return code; } @@ -4366,7 +4364,7 @@ static int32_t lastRowScanBuildFuncTypes(SScanLogicNode* pScan, SColumnNode* pCo return terrno; } pFuncTypeParam->pCol->colId = pColNode->colId; - strcpy(pFuncTypeParam->pCol->name, pColNode->colName); + tstrncpy(pFuncTypeParam->pCol->name, pColNode->colName, TSDB_COL_NAME_LEN); if (NULL == taosArrayPush(pScan->pFuncTypes, pFuncTypeParam)) { taosMemoryFree(pFuncTypeParam); return terrno; @@ -4443,15 +4441,15 @@ static int32_t lastRowScanOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogic if (TSDB_CODE_SUCCESS != code) { break; } - sprintf(((SColumnNode*)newColNode)->colName, "#dup_col.%p", newColNode); - sprintf(((SColumnNode*)pParamNode)->colName, "#dup_col.%p", newColNode); + snprintf(((SColumnNode*)newColNode)->colName, TSDB_COL_NAME_LEN, "#dup_col.%p", newColNode); + snprintf(((SColumnNode*)pParamNode)->colName, TSDB_COL_NAME_LEN, "#dup_col.%p", newColNode); if (FUNCTION_TYPE_LAST_ROW == funcType && ((SColumnNode*)pParamNode)->colId == PRIMARYKEY_TIMESTAMP_COL_ID) { if (!adjLastRowTsColName) { adjLastRowTsColName = true; - strncpy(tsColName, ((SColumnNode*)pParamNode)->colName, TSDB_COL_NAME_LEN); + tstrncpy(tsColName, ((SColumnNode*)pParamNode)->colName, TSDB_COL_NAME_LEN); } else { - strncpy(((SColumnNode*)pParamNode)->colName, tsColName, TSDB_COL_NAME_LEN); + tstrncpy(((SColumnNode*)pParamNode)->colName, tsColName, TSDB_COL_NAME_LEN); nodesDestroyNode(newColNode); continue; } @@ -4573,7 +4571,7 @@ static int32_t lastRowScanOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogic ((cxt.pLastCols->length == 1 && nodesEqualNode((SNode*)pPKTsCol, nodesListGetNode(cxt.pLastCols, 0))) || (pScan->node.pTargets->length == 2 && cxt.pkBytes > 0))) { // when select last(ts),tbname,ts from ..., we add another ts to targets - sprintf(pPKTsCol->colName, "#sel_val.%p", pPKTsCol); + snprintf(pPKTsCol->colName, TSDB_COL_NAME_LEN, "#sel_val.%p", pPKTsCol); SNode* pNew = NULL; code = nodesCloneNode((SNode*)pPKTsCol, &pNew); if (TSDB_CODE_SUCCESS == code) { @@ -4590,7 +4588,7 @@ static int32_t lastRowScanOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogic if (pNonPKCol && cxt.pLastCols->length == 1 && nodesEqualNode((SNode*)pNonPKCol, nodesListGetNode(cxt.pLastCols, 0))) { // when select last(c1), c1 from ..., we add c1 to targets - sprintf(pNonPKCol->colName, "#sel_val.%p", pNonPKCol); + snprintf(pNonPKCol->colName, TSDB_COL_NAME_LEN, "#sel_val.%p", pNonPKCol); SNode* pNew = NULL; code = nodesCloneNode((SNode*)pNonPKCol, &pNew); if (TSDB_CODE_SUCCESS == code) { @@ -5359,10 +5357,10 @@ static bool tbCntScanOptIsEligibleLogicCond(STbCntScanOptInfo* pInfo, SLogicCond } if (!hasDbCond && 0 == strcmp(pCol->colName, "db_name")) { hasDbCond = true; - strcpy(pInfo->table.dbname, pVal->literal); + tstrncpy(pInfo->table.dbname, pVal->literal, TSDB_DB_NAME_LEN); } else if (!hasStbCond && 0 == strcmp(pCol->colName, "stable_name")) { hasStbCond = true; - strcpy(pInfo->table.tname, pVal->literal); + tstrncpy(pInfo->table.tname, pVal->literal, TSDB_TABLE_NAME_LEN); } else { return false; } @@ -5425,8 +5423,8 @@ static int32_t tbCntScanOptCreateTableCountFunc(SNode** ppNode) { if (NULL == pFunc) { return code; } - strcpy(pFunc->functionName, "_table_count"); - strcpy(pFunc->node.aliasName, "_table_count"); + tstrncpy(pFunc->functionName, "_table_count", TSDB_FUNC_NAME_LEN); + tstrncpy(pFunc->node.aliasName, "_table_count", TSDB_COL_NAME_LEN); code = fmGetFuncInfo(pFunc, NULL, 0); if (TSDB_CODE_SUCCESS != code) { nodesDestroyNode((SNode*)pFunc); @@ -5438,8 +5436,8 @@ static int32_t tbCntScanOptCreateTableCountFunc(SNode** ppNode) { static int32_t tbCntScanOptRewriteScan(STbCntScanOptInfo* pInfo) { pInfo->pScan->scanType = SCAN_TYPE_TABLE_COUNT; - strcpy(pInfo->pScan->tableName.dbname, pInfo->table.dbname); - strcpy(pInfo->pScan->tableName.tname, pInfo->table.tname); + tstrncpy(pInfo->pScan->tableName.dbname, pInfo->table.dbname, TSDB_DB_NAME_LEN); + tstrncpy(pInfo->pScan->tableName.tname, pInfo->table.tname, TSDB_TABLE_NAME_LEN); NODES_DESTORY_LIST(pInfo->pScan->node.pTargets); NODES_DESTORY_LIST(pInfo->pScan->pScanCols); NODES_DESTORY_NODE(pInfo->pScan->node.pConditions); @@ -6267,29 +6265,22 @@ static int32_t stbJoinOptCreateDynQueryCtrlNode(SLogicNode* pRoot, SLogicNode* p if (TSDB_CODE_SUCCESS == code) { pDynCtrl->node.pChildren = NULL; code = nodesMakeList(&pDynCtrl->node.pChildren); - if (NULL == pDynCtrl->node.pChildren) { - code = code; - } } if (TSDB_CODE_SUCCESS == code) { pDynCtrl->stbJoin.pVgList = NULL; code = nodesMakeList(&pDynCtrl->stbJoin.pVgList); - if (NULL == pDynCtrl->stbJoin.pVgList) { - code = code; - } } if (TSDB_CODE_SUCCESS == code) { pDynCtrl->stbJoin.pUidList = NULL; code = nodesMakeList(&pDynCtrl->stbJoin.pUidList); - if (NULL == pDynCtrl->stbJoin.pUidList) { - code = code; - } } SJoinLogicNode* pHJoin = (SJoinLogicNode*)pPrev; - code = nodesListStrictAppend(pDynCtrl->stbJoin.pUidList, nodesListGetNode(pHJoin->node.pTargets, 0)); + if (TSDB_CODE_SUCCESS == code) { + code = nodesListStrictAppend(pDynCtrl->stbJoin.pUidList, nodesListGetNode(pHJoin->node.pTargets, 0)); + } if (TSDB_CODE_SUCCESS == code) { code = nodesListStrictAppend(pDynCtrl->stbJoin.pUidList, nodesListGetNode(pHJoin->node.pTargets, 2)); } @@ -6308,9 +6299,6 @@ static int32_t stbJoinOptCreateDynQueryCtrlNode(SLogicNode* pRoot, SLogicNode* p if (TSDB_CODE_SUCCESS == code) { pDynCtrl->node.pTargets = NULL; code = nodesCloneList(pPost->pTargets, &pDynCtrl->node.pTargets); - if (!pDynCtrl->node.pTargets) { - code = code; - } } } @@ -7056,10 +7044,9 @@ int32_t tsmaOptCreateTsmaScanCols(const STSMAOptUsefulTsma* pTsma, const SNodeLi pCol->tableType = TSDB_SUPER_TABLE; pCol->tableId = pTsma->targetTbUid; pCol->colType = COLUMN_TYPE_COLUMN; - strcpy(pCol->tableName, pTsma->targetTbName); - strcpy(pCol->dbName, pTsma->pTsma->targetDbFName); - strcpy(pCol->colName, pFunc->node.aliasName); - strcpy(pCol->node.aliasName, pFunc->node.aliasName); + tstrncpy(pCol->tableName, pTsma->targetTbName, TSDB_TABLE_NAME_LEN); + tstrncpy(pCol->colName, pFunc->node.aliasName, TSDB_COL_NAME_LEN); + tstrncpy(pCol->node.aliasName, pFunc->node.aliasName, TSDB_COL_NAME_LEN); pCol->node.resType.type = TSDB_DATA_TYPE_BINARY; code = nodesListMakeStrictAppend(&pScanCols, (SNode*)pCol); } @@ -7083,8 +7070,8 @@ static int32_t tsmaOptRewriteTag(const STSMAOptCtx* pTsmaOptCtx, const STSMAOptU for (int32_t i = 0; i < pTsma->pTsma->pTags->size; ++i) { const SSchema* pSchema = taosArrayGet(pTsma->pTsma->pTags, i); if (strcmp(pTagCol->colName, pSchema->name) == 0) { - strcpy(pTagCol->tableName, pTsma->targetTbName); - strcpy(pTagCol->tableAlias, pTsma->targetTbName); + tstrncpy(pTagCol->tableName, pTsma->targetTbName, TSDB_TABLE_NAME_LEN); + tstrncpy(pTagCol->tableAlias, pTsma->targetTbName, TSDB_TABLE_NAME_LEN); pTagCol->tableId = pTsma->targetTbUid; pTagCol->tableType = TSDB_SUPER_TABLE; pTagCol->colId = pSchema->colId; @@ -7109,8 +7096,8 @@ static int32_t tsmaOptRewriteTbname(const STSMAOptCtx* pTsmaOptCtx, SNode** pTbN nodesDestroyNode(*pTbNameNode); SColumnNode* pCol = (SColumnNode*)pRewrittenFunc; const SSchema* pSchema = taosArrayGet(pTsma->pTsma->pTags, pTsma->pTsma->pTags->size - 1); - strcpy(pCol->tableName, pTsma->targetTbName); - strcpy(pCol->tableAlias, pTsma->targetTbName); + tstrncpy(pCol->tableName, pTsma->targetTbName, TSDB_TABLE_NAME_LEN); + tstrncpy(pCol->tableAlias, pTsma->targetTbName, TSDB_TABLE_NAME_LEN); pCol->tableId = pTsma->targetTbUid; pCol->tableType = TSDB_SUPER_TABLE; pCol->colId = pSchema->colId; @@ -7234,7 +7221,7 @@ static int32_t tsmaOptRewriteScan(STSMAOptCtx* pTsmaOptCtx, SScanLogicNode* pNew if (code == TSDB_CODE_SUCCESS) { pNewScan->stableId = pTsma->pTsma->destTbUid; pNewScan->tableId = pTsma->targetTbUid; - strcpy(pNewScan->tableName.tname, pTsma->targetTbName); + tstrncpy(pNewScan->tableName.tname, pTsma->targetTbName, TSDB_TABLE_NAME_LEN); } if (code == TSDB_CODE_SUCCESS) { code = tsmaOptRewriteNodeList(pNewScan->pScanPseudoCols, pTsmaOptCtx, pTsma, true, true); @@ -7287,12 +7274,12 @@ static int32_t tsmaOptCreateWStart(int8_t precision, SFunctionNode** pWStartOut) if (NULL == pWStart) { return code; } - strcpy(pWStart->functionName, "_wstart"); + tstrncpy(pWStart->functionName, "_wstart", TSDB_FUNC_NAME_LEN); int64_t pointer = (int64_t)pWStart; char name[TSDB_COL_NAME_LEN + TSDB_POINTER_PRINT_BYTES + TSDB_NAME_DELIMITER_LEN + 1] = {0}; int32_t len = tsnprintf(name, sizeof(name) - 1, "%s.%" PRId64 "", pWStart->functionName, pointer); (void)taosHashBinary(name, len); - strncpy(pWStart->node.aliasName, name, TSDB_COL_NAME_LEN - 1); + tstrncpy(pWStart->node.aliasName, name, TSDB_COL_NAME_LEN); pWStart->node.resType.precision = precision; code = fmGetFuncInfo(pWStart, NULL, 0); @@ -7395,12 +7382,12 @@ static int32_t tsmaOptGeneratePlan(STSMAOptCtx* pTsmaOptCtx) { for (int32_t j = 0; j < pTsmaOptCtx->pScan->pTsmas->size; ++j) { if (taosArrayGetP(pTsmaOptCtx->pScan->pTsmas, j) == pTsma->pTsma) { const STsmaTargetTbInfo* ptbInfo = taosArrayGet(pTsmaOptCtx->pScan->pTsmaTargetTbInfo, j); - strcpy(pTsma->targetTbName, ptbInfo->tableName); + tstrncpy(pTsma->targetTbName, ptbInfo->tableName, TSDB_TABLE_NAME_LEN); pTsma->targetTbUid = ptbInfo->uid; } } } else { - strcpy(pTsma->targetTbName, pTsma->pTsma->targetTb); + tstrncpy(pTsma->targetTbName, pTsma->pTsma->targetTb, TSDB_TABLE_NAME_LEN); pTsma->targetTbUid = pTsma->pTsma->destTbUid; } } diff --git a/source/libs/planner/src/planPhysiCreater.c b/source/libs/planner/src/planPhysiCreater.c index a0912ec8c7..16376ae792 100644 --- a/source/libs/planner/src/planPhysiCreater.c +++ b/source/libs/planner/src/planPhysiCreater.c @@ -41,9 +41,9 @@ static int32_t getSlotKey(SNode* pNode, const char* pStmtName, char** ppKey, int if (!*ppKey) { return terrno; } - strcat(*ppKey, pStmtName); - strcat(*ppKey, "."); - strcat(*ppKey, pCol->node.aliasName); + strncat(*ppKey, pStmtName, TSDB_TABLE_NAME_LEN); + strncat(*ppKey, ".", 2); + strncat(*ppKey, pCol->node.aliasName, TSDB_COL_NAME_LEN); *pLen = taosHashBinary(*ppKey, strlen(*ppKey)); return code; } else { @@ -51,7 +51,7 @@ static int32_t getSlotKey(SNode* pNode, const char* pStmtName, char** ppKey, int if (!*ppKey) { return terrno; } - strcat(*ppKey, pCol->node.aliasName); + strncat(*ppKey, pCol->node.aliasName, TSDB_COL_NAME_LEN); *pLen = strlen(*ppKey); return code; } @@ -61,7 +61,7 @@ static int32_t getSlotKey(SNode* pNode, const char* pStmtName, char** ppKey, int if (!*ppKey) { return terrno; } - strcat(*ppKey, pCol->colName); + strncat(*ppKey, pCol->colName, TSDB_COL_NAME_LEN); *pLen = strlen(*ppKey); return code; } @@ -70,9 +70,9 @@ static int32_t getSlotKey(SNode* pNode, const char* pStmtName, char** ppKey, int if (!*ppKey) { return terrno; } - strcat(*ppKey, pCol->tableAlias); - strcat(*ppKey, "."); - strcat(*ppKey, pCol->colName); + strncat(*ppKey, pCol->tableAlias, TSDB_TABLE_NAME_LEN); + strncat(*ppKey, ".", 2); + strncat(*ppKey, pCol->colName, TSDB_COL_NAME_LEN); *pLen = taosHashBinary(*ppKey, strlen(*ppKey)); return code; } else if (QUERY_NODE_FUNCTION == nodeType(pNode)) { @@ -85,9 +85,9 @@ static int32_t getSlotKey(SNode* pNode, const char* pStmtName, char** ppKey, int if (!*ppKey) { return terrno; } - strcat(*ppKey, pStmtName); - strcat(*ppKey, "."); - strcat(*ppKey, ((SExprNode*)pNode)->aliasName); + strncat(*ppKey, pStmtName, TSDB_TABLE_NAME_LEN); + strncat(*ppKey, ".", 2); + strncat(*ppKey, ((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN); *pLen = taosHashBinary(*ppKey, strlen(*ppKey)); return code; } @@ -95,9 +95,9 @@ static int32_t getSlotKey(SNode* pNode, const char* pStmtName, char** ppKey, int if (!*ppKey) { return terrno; } - strcat(*ppKey, pVal->literal); - strcat(*ppKey, "."); - strcat(*ppKey, ((SExprNode*)pNode)->aliasName); + strncat(*ppKey, pVal->literal, strlen(pVal->literal)); + strncat(*ppKey, ".", 2); + strncat(*ppKey, ((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN); *pLen = taosHashBinary(*ppKey, strlen(*ppKey)); return code; } @@ -109,9 +109,9 @@ static int32_t getSlotKey(SNode* pNode, const char* pStmtName, char** ppKey, int if (!*ppKey) { return terrno; } - strcat(*ppKey, pStmtName); - strcat(*ppKey, "."); - strcat(*ppKey, ((SExprNode*)pNode)->aliasName); + strncat(*ppKey, pStmtName, TSDB_TABLE_NAME_LEN); + strncat(*ppKey, ".", 2); + strncat(*ppKey, ((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN); *pLen = taosHashBinary(*ppKey, strlen(*ppKey)); return code; } @@ -120,7 +120,7 @@ static int32_t getSlotKey(SNode* pNode, const char* pStmtName, char** ppKey, int if (!*ppKey) { return terrno; } - strcat(*ppKey, ((SExprNode*)pNode)->aliasName); + strncat(*ppKey, ((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN); *pLen = strlen(*ppKey); return code; } @@ -229,7 +229,7 @@ static int32_t buildDataBlockSlots(SPhysiPlanContext* pCxt, SNodeList* pList, SD code = putSlotToHash(name, len, pDataBlockDesc->dataBlockId, slotId, pNode, pHash); if (TSDB_CODE_SUCCESS == code) { if (nodeType(pNode) == QUERY_NODE_COLUMN && ((SColumnNode*)pNode)->resIdx > 0) { - sprintf(name + strlen(name), "_%d", ((SColumnNode*)pNode)->resIdx); + snprintf(name + strlen(name), 16, "_%d", ((SColumnNode*)pNode)->resIdx); code = putSlotToHash(name, strlen(name), pDataBlockDesc->dataBlockId, slotId, pNode, pProjIdxDescHash); } } @@ -396,7 +396,7 @@ static EDealRes doSetSlotId(SNode* pNode, void* pContext) { } SSlotIndex *pIndex = NULL; if (((SColumnNode*)pNode)->projRefIdx > 0) { - sprintf(name + strlen(name), "_%d", ((SColumnNode*)pNode)->projRefIdx); + snprintf(name + strlen(name), 16, "_%d", ((SColumnNode*)pNode)->projRefIdx); pIndex = taosHashGet(pCxt->pLeftProjIdxHash, name, strlen(name)); if (!pIndex) { pIndex = taosHashGet(pCxt->pRightProdIdxHash, name, strlen(name)); @@ -567,9 +567,6 @@ static int32_t createScanPhysiNodeFinalize(SPhysiPlanContext* pCxt, SSubplan* pS if (TSDB_CODE_SUCCESS == code && NULL != pScanLogicNode->pScanPseudoCols) { pScanPhysiNode->pScanPseudoCols = NULL; code = nodesCloneList(pScanLogicNode->pScanPseudoCols, &pScanPhysiNode->pScanPseudoCols); - if (NULL == pScanPhysiNode->pScanPseudoCols) { - code = code; - } } if (TSDB_CODE_SUCCESS == code) { @@ -589,9 +586,6 @@ static int32_t createScanPhysiNodeFinalize(SPhysiPlanContext* pCxt, SSubplan* pS if (NULL != pScanLogicNode->pTagCond) { pSubplan->pTagCond = NULL; code = nodesCloneNode(pScanLogicNode->pTagCond, &pSubplan->pTagCond); - if (NULL == pSubplan->pTagCond) { - code = code; - } } } @@ -599,9 +593,6 @@ static int32_t createScanPhysiNodeFinalize(SPhysiPlanContext* pCxt, SSubplan* pS if (NULL != pScanLogicNode->pTagIndexCond) { pSubplan->pTagIndexCond = NULL; code = nodesCloneNode(pScanLogicNode->pTagIndexCond, &pSubplan->pTagIndexCond); - if (NULL == pSubplan->pTagIndexCond) { - code = code; - } } } @@ -1675,11 +1666,11 @@ static EDealRes collectAndRewrite(SRewritePrecalcExprsCxt* pCxt, SNode** pNode) SExprNode* pRewrittenExpr = (SExprNode*)pExpr; pCol->node.resType = pRewrittenExpr->resType; if ('\0' != pRewrittenExpr->aliasName[0]) { - strcpy(pCol->colName, pRewrittenExpr->aliasName); + tstrncpy(pCol->colName, pRewrittenExpr->aliasName, TSDB_COL_NAME_LEN); } else { snprintf(pRewrittenExpr->aliasName, sizeof(pRewrittenExpr->aliasName), "#expr_%d_%d", pCxt->planNodeId, pCxt->rewriteId); - strcpy(pCol->colName, pRewrittenExpr->aliasName); + tstrncpy(pCol->colName, pRewrittenExpr->aliasName, TSDB_COL_NAME_LEN); } nodesDestroyNode(*pNode); *pNode = (SNode*)pCol; @@ -1700,7 +1691,7 @@ static int32_t rewriteValueToOperator(SRewritePrecalcExprsCxt* pCxt, SNode** pNo } SValueNode* pVal = (SValueNode*)*pNode; pOper->node.resType = pVal->node.resType; - strcpy(pOper->node.aliasName, pVal->node.aliasName); + tstrncpy(pOper->node.aliasName, pVal->node.aliasName, TSDB_COL_NAME_LEN); pOper->opType = OP_TYPE_ASSIGN; pOper->pRight = *pNode; *pNode = (SNode*)pOper; @@ -1961,9 +1952,6 @@ static int32_t createInterpFuncPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pCh pInterpFunc->rangeInterval = pFuncLogicNode->rangeInterval; pInterpFunc->rangeIntervalUnit = pFuncLogicNode->rangeIntervalUnit; code = nodesCloneNode(pFuncLogicNode->pFillValues, &pInterpFunc->pFillValues); - if (TSDB_CODE_SUCCESS != code) { - code = code; - } } if (TSDB_CODE_SUCCESS == code) { @@ -2876,7 +2864,7 @@ static int32_t createQueryInserter(SPhysiPlanContext* pCxt, SVnodeModifyLogicNod pInserter->tableId = pModify->tableId; pInserter->stableId = pModify->stableId; pInserter->tableType = pModify->tableType; - strcpy(pInserter->tableName, pModify->tableName); + tstrncpy(pInserter->tableName, pModify->tableName, TSDB_TABLE_NAME_LEN); pInserter->explain = (QUERY_NODE_EXPLAIN_STMT == nodeType(pCxt->pPlanCxt->pAstRoot) ? true : false); if (pModify->pVgroupList) { pInserter->vgId = pModify->pVgroupList->vgroups[0].vgId; @@ -2888,9 +2876,6 @@ static int32_t createQueryInserter(SPhysiPlanContext* pCxt, SVnodeModifyLogicNod if (TSDB_CODE_SUCCESS == code) { pInserter->sink.pInputDataBlockDesc = NULL; code = nodesCloneNode((SNode*)pSubplan->pNode->pOutputDataBlockDesc, (SNode**)&pInserter->sink.pInputDataBlockDesc); - if (NULL == pInserter->sink.pInputDataBlockDesc) { - code = code; - } } if (TSDB_CODE_SUCCESS == code) { @@ -2929,8 +2914,8 @@ static int32_t createDataDeleter(SPhysiPlanContext* pCxt, SVnodeModifyLogicNode* pDeleter->tableId = pModify->tableId; pDeleter->tableType = pModify->tableType; - strcpy(pDeleter->tableFName, pModify->tableName); - strcpy(pDeleter->tsColName, pModify->tsColName); + tstrncpy(pDeleter->tableFName, pModify->tableName, TSDB_TABLE_NAME_LEN); + tstrncpy(pDeleter->tsColName, pModify->tsColName, TSDB_COL_NAME_LEN); pDeleter->deleteTimeRange = pModify->deleteTimeRange; code = setNodeSlotId(pCxt, pRoot->pOutputDataBlockDesc->dataBlockId, -1, pModify->pAffectedRows, @@ -2944,9 +2929,6 @@ static int32_t createDataDeleter(SPhysiPlanContext* pCxt, SVnodeModifyLogicNode* if (TSDB_CODE_SUCCESS == code) { pDeleter->sink.pInputDataBlockDesc = NULL; code = nodesCloneNode((SNode*)pRoot->pOutputDataBlockDesc, (SNode**)&pDeleter->sink.pInputDataBlockDesc); - if (NULL == pDeleter->sink.pInputDataBlockDesc) { - code = code; - } } if (TSDB_CODE_SUCCESS == code) { diff --git a/source/libs/planner/src/planSpliter.c b/source/libs/planner/src/planSpliter.c index fc8731e40e..36baa1ca9e 100644 --- a/source/libs/planner/src/planSpliter.c +++ b/source/libs/planner/src/planSpliter.c @@ -433,7 +433,7 @@ static int32_t stbSplAppendWStart(SNodeList* pFuncs, int32_t* pIndex, uint8_t pr char name[TSDB_COL_NAME_LEN + TSDB_POINTER_PRINT_BYTES + TSDB_NAME_DELIMITER_LEN + 1] = {0}; int32_t len = tsnprintf(name, sizeof(name) - 1, "%s.%" PRId64 "", pWStart->functionName, pointer); (void)taosHashBinary(name, len); - strncpy(pWStart->node.aliasName, name, TSDB_COL_NAME_LEN - 1); + tstrncpy(pWStart->node.aliasName, name, TSDB_COL_NAME_LEN); pWStart->node.resType.precision = precision; code = fmGetFuncInfo(pWStart, NULL, 0); @@ -465,7 +465,7 @@ static int32_t stbSplAppendWEnd(SWindowLogicNode* pWin, int32_t* pIndex) { char name[TSDB_COL_NAME_LEN + TSDB_POINTER_PRINT_BYTES + TSDB_NAME_DELIMITER_LEN + 1] = {0}; int32_t len = tsnprintf(name, sizeof(name) - 1, "%s.%" PRId64 "", pWEnd->functionName, pointer); (void)taosHashBinary(name, len); - strncpy(pWEnd->node.aliasName, name, TSDB_COL_NAME_LEN - 1); + tstrncpy(pWEnd->node.aliasName, name, TSDB_COL_NAME_LEN); code = fmGetFuncInfo(pWEnd, NULL, 0); if (TSDB_CODE_SUCCESS == code) { @@ -836,9 +836,6 @@ static int32_t stbSplSplitSessionForStream(SSplitContext* pCxt, SStableSplitInfo nodesDestroyNode(pMergeWin->pTsEnd); pMergeWin->pTsEnd = NULL; code = nodesCloneNode(nodesListGetNode(pPartWin->node.pTargets, index), &pMergeWin->pTsEnd); - if (NULL == pMergeWin->pTsEnd) { - code = code; - } } code = stbSplCreateExchangeNode(pCxt, pInfo->pSplitNode, pPartWindow); } @@ -1360,9 +1357,6 @@ static int32_t stbSplCreatePartSortNode(SSortLogicNode* pSort, SLogicNode** pOut int32_t code = TSDB_CODE_SUCCESS; SSortLogicNode* pPartSort = NULL; code = nodesCloneNode((SNode*)pSort, (SNode**)&pPartSort); - if (NULL == pPartSort) { - code = code; - } SNodeList* pMergeKeys = NULL; if (TSDB_CODE_SUCCESS == code) { @@ -1543,9 +1537,6 @@ static int32_t stbSplCreateMergeScanNode(SScanLogicNode* pScan, SLogicNode** pOu int32_t code = TSDB_CODE_SUCCESS; SScanLogicNode* pMergeScan = NULL; code = nodesCloneNode((SNode*)pScan, (SNode**)&pMergeScan); - if (NULL == pMergeScan) { - code = code; - } SNodeList* pMergeKeys = NULL; if (TSDB_CODE_SUCCESS == code) { diff --git a/source/libs/planner/src/planUtil.c b/source/libs/planner/src/planUtil.c index fd8670c23e..f03e2d8ab0 100644 --- a/source/libs/planner/src/planUtil.c +++ b/source/libs/planner/src/planUtil.c @@ -68,14 +68,14 @@ static EDealRes doCreateColumn(SNode* pNode, void* pContext) { return DEAL_RES_ERROR; } pCol->node.resType = pExpr->resType; - strcpy(pCol->colName, pExpr->aliasName); + tstrncpy(pCol->colName, pExpr->aliasName, TSDB_COL_NAME_LEN); if (QUERY_NODE_FUNCTION == nodeType(pNode)) { SFunctionNode* pFunc = (SFunctionNode*)pNode; if (pFunc->funcType == FUNCTION_TYPE_TBNAME) { SValueNode* pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 0); if (NULL != pVal) { - strcpy(pCol->tableAlias, pVal->literal); - strcpy(pCol->tableName, pVal->literal); + tstrncpy(pCol->tableAlias, pVal->literal, TSDB_TABLE_NAME_LEN); + tstrncpy(pCol->tableName, pVal->literal, TSDB_TABLE_NAME_LEN); } } } @@ -636,9 +636,9 @@ SFunctionNode* createGroupKeyAggFunc(SColumnNode* pGroupCol) { SFunctionNode* pFunc = NULL; int32_t code = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&pFunc); if (pFunc) { - strcpy(pFunc->functionName, "_group_key"); - strcpy(pFunc->node.aliasName, pGroupCol->node.aliasName); - strcpy(pFunc->node.userAlias, pGroupCol->node.userAlias); + tstrncpy(pFunc->functionName, "_group_key", TSDB_FUNC_NAME_LEN); + tstrncpy(pFunc->node.aliasName, pGroupCol->node.aliasName, TSDB_COL_NAME_LEN); + tstrncpy(pFunc->node.userAlias, pGroupCol->node.userAlias, TSDB_COL_NAME_LEN); SNode* pNew = NULL; code = nodesCloneNode((SNode*)pGroupCol, &pNew); if (TSDB_CODE_SUCCESS == code) { @@ -655,7 +655,7 @@ SFunctionNode* createGroupKeyAggFunc(SColumnNode* pGroupCol) { char name[TSDB_FUNC_NAME_LEN + TSDB_NAME_DELIMITER_LEN + TSDB_POINTER_PRINT_BYTES + 1] = {0}; int32_t len = tsnprintf(name, sizeof(name) - 1, "%s.%p", pFunc->functionName, pFunc); (void)taosHashBinary(name, len); - strncpy(pFunc->node.aliasName, name, TSDB_COL_NAME_LEN - 1); + tstrncpy(pFunc->node.aliasName, name, TSDB_COL_NAME_LEN); } } if (TSDB_CODE_SUCCESS != code) { From 2a8263efea092ffcddce91147e77259277c050da Mon Sep 17 00:00:00 2001 From: 54liuyao <54liuyao@163.com> Date: Tue, 3 Dec 2024 09:11:46 +0800 Subject: [PATCH 05/62] opt force window close memory --- source/libs/executor/src/streamfilloperator.c | 11 ++++++++++- source/libs/stream/src/tstreamFileState.c | 9 +++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/source/libs/executor/src/streamfilloperator.c b/source/libs/executor/src/streamfilloperator.c index c992bd15b7..9039a26f0b 100644 --- a/source/libs/executor/src/streamfilloperator.c +++ b/source/libs/executor/src/streamfilloperator.c @@ -987,7 +987,14 @@ _end: } void resetStreamFillSup(SStreamFillSupporter* pFillSup) { - tSimpleHashClear(pFillSup->pResMap); + _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY); + SSHashObj* pNewMap = tSimpleHashInit(16, hashFn); + if (pNewMap != NULL) { + tSimpleHashCleanup(pFillSup->pResMap); + pFillSup->pResMap = pNewMap; + } else { + tSimpleHashClear(pFillSup->pResMap); + } pFillSup->hasDelete = false; } void resetStreamFillInfo(SStreamFillOperatorInfo* pInfo) { @@ -1406,6 +1413,7 @@ static int32_t doStreamForceFillNext(SOperatorInfo* pOperator, SSDataBlock** ppR } pInfo->stateStore.streamStateClearExpiredState(pInfo->pState); + resetStreamFillInfo(pInfo); setStreamOperatorCompleted(pOperator); (*ppRes) = NULL; goto _end; @@ -1477,6 +1485,7 @@ static int32_t doStreamForceFillNext(SOperatorInfo* pOperator, SSDataBlock** ppR if ((*ppRes) == NULL) { pInfo->stateStore.streamStateClearExpiredState(pInfo->pState); + resetStreamFillInfo(pInfo); setStreamOperatorCompleted(pOperator); } diff --git a/source/libs/stream/src/tstreamFileState.c b/source/libs/stream/src/tstreamFileState.c index dcabadb8bd..592523e70b 100644 --- a/source/libs/stream/src/tstreamFileState.c +++ b/source/libs/stream/src/tstreamFileState.c @@ -1228,6 +1228,8 @@ void setFillInfo(SStreamFileState* pFileState) { } void clearExpiredState(SStreamFileState* pFileState) { + int32_t code = TSDB_CODE_SUCCESS; + int32_t lino = 0; SSHashObj* pSearchBuff = pFileState->searchBuff; void* pIte = NULL; int32_t iter = 0; @@ -1246,6 +1248,13 @@ void clearExpiredState(SStreamFileState* pFileState) { } taosArrayRemoveBatch(pWinStates, 0, size - 1, NULL); } + code = clearRowBuff(pFileState); + QUERY_CHECK_CODE(code, lino, _end); + +_end: + if (code != TSDB_CODE_SUCCESS) { + qError("%s failed at line %d since %s", __func__, lino, tstrerror(code)); + } } int32_t getStateSearchRowBuff(SStreamFileState* pFileState, const SWinKey* pKey, void** pVal, int32_t* pVLen, From 2c91e122044de3673849e42d324f8c7a56d2e404 Mon Sep 17 00:00:00 2001 From: factosea <285808407@qq.com> Date: Tue, 3 Dec 2024 09:30:10 +0800 Subject: [PATCH 06/62] fix: where or const contition --- source/libs/parser/src/parTranslater.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index 7e5d9375ac..2e167d3053 100755 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -5623,6 +5623,9 @@ static int32_t getTimeRange(SNode** pPrimaryKeyCond, STimeWindow* pTimeRange, bo int32_t code = scalarCalculateConstants(*pPrimaryKeyCond, &pNew); if (TSDB_CODE_SUCCESS == code) { *pPrimaryKeyCond = pNew; + if(nodeType(pNew) == QUERY_NODE_VALUE) { + *pTimeRange = TSWINDOW_INITIALIZER; + } code = filterGetTimeRange(*pPrimaryKeyCond, pTimeRange, pIsStrict); } return code; From 8b1125e5544ebef1b5ad9137720991ee36fadb43 Mon Sep 17 00:00:00 2001 From: dmchen Date: Tue, 3 Dec 2024 09:53:46 +0800 Subject: [PATCH 07/62] fix/exit-fail-retry-when-follower --- source/dnode/mnode/impl/src/mndTrans.c | 74 +++++++++++++++----------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/source/dnode/mnode/impl/src/mndTrans.c b/source/dnode/mnode/impl/src/mndTrans.c index e51500bf34..65d76a39bd 100644 --- a/source/dnode/mnode/impl/src/mndTrans.c +++ b/source/dnode/mnode/impl/src/mndTrans.c @@ -52,10 +52,17 @@ static bool mndTransPerformCommitStage(SMnode *pMnode, STrans *pTrans, bool t static bool mndTransPerformRollbackStage(SMnode *pMnode, STrans *pTrans, bool topHalf); static bool mndTransPerformFinishStage(SMnode *pMnode, STrans *pTrans, bool topHalf); -static bool mndCannotExecuteTransAction(SMnode *pMnode, bool topHalf) { - return (!pMnode->deploy && !mndIsLeader(pMnode)) || !topHalf; +static inline bool mndTransIsInSyncContext(bool topHalf) { return !topHalf; } + +static bool mndCannotExecuteTrans(SMnode *pMnode, bool topHalf) { + bool isLeader = mndIsLeader(pMnode); + bool ret = (!pMnode->deploy && !isLeader) || mndTransIsInSyncContext(topHalf); + if (ret) mDebug("cannot execute trans action, deploy:%d, isLeader:%d, topHalf:%d", pMnode->deploy, isLeader, topHalf); + return ret; } +static inline char *mndStrExecutionContext(bool topHalf) { return topHalf ? "transContext" : "syncContext"; } + static void mndTransSendRpcRsp(SMnode *pMnode, STrans *pTrans); static int32_t mndProcessTransTimer(SRpcMsg *pReq); static int32_t mndProcessTtl(SRpcMsg *pReq); @@ -1327,7 +1334,7 @@ static int32_t mndTransWriteSingleLog(SMnode *pMnode, STrans *pTrans, STransActi // execute in trans context static int32_t mndTransSendSingleMsg(SMnode *pMnode, STrans *pTrans, STransAction *pAction, bool topHalf) { if (pAction->msgSent) return 0; - if (mndCannotExecuteTransAction(pMnode, topHalf)) { + if (mndCannotExecuteTrans(pMnode, topHalf)) { TAOS_RETURN(TSDB_CODE_MND_TRANS_CTX_SWITCH); } @@ -1473,8 +1480,8 @@ static int32_t mndTransExecuteActions(SMnode *pMnode, STrans *pTrans, SArray *pA static int32_t mndTransExecuteRedoActions(SMnode *pMnode, STrans *pTrans, bool topHalf) { int32_t code = mndTransExecuteActions(pMnode, pTrans, pTrans->redoActions, topHalf); if (code != 0 && code != TSDB_CODE_ACTION_IN_PROGRESS && code != TSDB_CODE_MND_TRANS_CTX_SWITCH) { - mError("trans:%d, failed to execute redoActions since:%s, code:0x%x, topHalf(TransContext):%d", pTrans->id, - terrstr(), terrno, topHalf); + mError("trans:%d, failed to execute redoActions since:%s, code:0x%x, in %s", pTrans->id, terrstr(), terrno, + mndStrExecutionContext(topHalf)); } return code; } @@ -1482,8 +1489,8 @@ static int32_t mndTransExecuteRedoActions(SMnode *pMnode, STrans *pTrans, bool t static int32_t mndTransExecuteUndoActions(SMnode *pMnode, STrans *pTrans, bool topHalf) { int32_t code = mndTransExecuteActions(pMnode, pTrans, pTrans->undoActions, topHalf); if (code != 0 && code != TSDB_CODE_ACTION_IN_PROGRESS && code != TSDB_CODE_MND_TRANS_CTX_SWITCH) { - mError("trans:%d, failed to execute undoActions since %s. topHalf(TransContext):%d", pTrans->id, terrstr(), - topHalf); + mError("trans:%d, failed to execute undoActions since %s. in %s", pTrans->id, terrstr(), + mndStrExecutionContext(topHalf)); } return code; } @@ -1491,8 +1498,8 @@ static int32_t mndTransExecuteUndoActions(SMnode *pMnode, STrans *pTrans, bool t static int32_t mndTransExecuteCommitActions(SMnode *pMnode, STrans *pTrans, bool topHalf) { int32_t code = mndTransExecuteActions(pMnode, pTrans, pTrans->commitActions, topHalf); if (code != 0 && code != TSDB_CODE_ACTION_IN_PROGRESS && code != TSDB_CODE_MND_TRANS_CTX_SWITCH) { - mError("trans:%d, failed to execute commitActions since %s. topHalf(TransContext):%d", pTrans->id, terrstr(), - topHalf); + mError("trans:%d, failed to execute commitActions since %s. in %s", pTrans->id, terrstr(), + mndStrExecutionContext(topHalf)); } return code; } @@ -1512,7 +1519,7 @@ static int32_t mndTransExecuteActionsSerial(SMnode *pMnode, STrans *pTrans, SArr for (int32_t action = pTrans->actionPos; action < numOfActions; ++action) { STransAction *pAction = taosArrayGet(pActions, action); - mInfo("trans:%d, current action:%d, stage:%s, actionType(0:log,1:msg):%d", pTrans->id, pTrans->actionPos, + mInfo("trans:%d, current action:%d, stage:%s, actionType(1:msg,2:log):%d", pTrans->id, pTrans->actionPos, mndTransStr(pAction->stage), pAction->actionType); code = mndTransExecSingleAction(pMnode, pTrans, pAction, topHalf); @@ -1543,11 +1550,11 @@ static int32_t mndTransExecuteActionsSerial(SMnode *pMnode, STrans *pTrans, SArr } mndSetTransLastAction(pTrans, pAction); - if (mndCannotExecuteTransAction(pMnode, topHalf)) { + if (mndCannotExecuteTrans(pMnode, topHalf)) { pTrans->lastErrorNo = code; pTrans->code = code; - mInfo("trans:%d, %s:%d, topHalf(TransContext):%d, not execute next action, code:%s", pTrans->id, - mndTransStr(pAction->stage), action, topHalf, tstrerror(code)); + mInfo("trans:%d, %s:%d, cannot execute next action in %s, code:%s", pTrans->id, mndTransStr(pAction->stage), + action, mndStrExecutionContext(topHalf), tstrerror(code)); break; } @@ -1648,21 +1655,25 @@ static bool mndTransPerformRedoActionStage(SMnode *pMnode, STrans *pTrans, bool code = mndTransExecuteRedoActions(pMnode, pTrans, topHalf); } - if (mndCannotExecuteTransAction(pMnode, topHalf)) { + if (code != 0 && code != TSDB_CODE_MND_TRANS_CTX_SWITCH && mndTransIsInSyncContext(topHalf)) { pTrans->lastErrorNo = code; pTrans->code = code; - bool continueExec = true; - if (code != 0 && code != TSDB_CODE_MND_TRANS_CTX_SWITCH) { - taosMsleep(100); - continueExec = true; - } else { - continueExec = false; + mInfo( + "trans:%d, failed to execute, will retry redo action stage in 100 ms , in %s, " + "continueExec:%d, code:%s", + pTrans->id, mndStrExecutionContext(topHalf), continueExec, tstrerror(code)); + taosMsleep(100); + return true; + } else { + if (mndCannotExecuteTrans(pMnode, topHalf)) { + mInfo("trans:%d, cannot continue to execute redo action stage in %s, continueExec:%d, code:%s", pTrans->id, + mndStrExecutionContext(topHalf), continueExec, tstrerror(code)); + return false; } - mInfo("trans:%d, cannot execute redo action stage, topHalf(TransContext):%d, continueExec:%d, code:%s", pTrans->id, - topHalf, continueExec, tstrerror(code)); - - return continueExec; } + + // if (mndCannotExecuteTrans(pMnode, topHalf)) return false; + terrno = code; if (code == 0) { @@ -1704,9 +1715,9 @@ static bool mndTransPerformRedoActionStage(SMnode *pMnode, STrans *pTrans, bool return continueExec; } -// in trans context +// execute in trans context static bool mndTransPerformCommitStage(SMnode *pMnode, STrans *pTrans, bool topHalf) { - if (mndCannotExecuteTransAction(pMnode, topHalf)) return false; + if (mndCannotExecuteTrans(pMnode, topHalf)) return false; bool continueExec = true; int32_t code = mndTransCommit(pMnode, pTrans); @@ -1760,7 +1771,7 @@ static bool mndTransPerformUndoActionStage(SMnode *pMnode, STrans *pTrans, bool code = mndTransExecuteUndoActions(pMnode, pTrans, topHalf); } - if (mndCannotExecuteTransAction(pMnode, topHalf)) return false; + if (mndCannotExecuteTrans(pMnode, topHalf)) return false; terrno = code; if (code == 0) { @@ -1781,7 +1792,7 @@ static bool mndTransPerformUndoActionStage(SMnode *pMnode, STrans *pTrans, bool // in trans context static bool mndTransPerformRollbackStage(SMnode *pMnode, STrans *pTrans, bool topHalf) { - if (mndCannotExecuteTransAction(pMnode, topHalf)) return false; + if (mndCannotExecuteTrans(pMnode, topHalf)) return false; bool continueExec = true; int32_t code = mndTransRollback(pMnode, pTrans); @@ -1798,8 +1809,9 @@ static bool mndTransPerformRollbackStage(SMnode *pMnode, STrans *pTrans, bool to return continueExec; } +// excute in trans context static bool mndTransPerformPreFinishStage(SMnode *pMnode, STrans *pTrans, bool topHalf) { - if (mndCannotExecuteTransAction(pMnode, topHalf)) return false; + if (mndCannotExecuteTrans(pMnode, topHalf)) return false; bool continueExec = true; int32_t code = mndTransPreFinish(pMnode, pTrans); @@ -1842,8 +1854,8 @@ void mndTransExecuteImp(SMnode *pMnode, STrans *pTrans, bool topHalf) { bool continueExec = true; while (continueExec) { - mInfo("trans:%d, continue to execute, stage:%s createTime:%" PRId64 " topHalf(TransContext):%d", pTrans->id, - mndTransStr(pTrans->stage), pTrans->createdTime, topHalf); + mInfo("trans:%d, continue to execute stage:%s in %s, createTime:%" PRId64 "", pTrans->id, + mndTransStr(pTrans->stage), mndStrExecutionContext(topHalf), pTrans->createdTime); pTrans->lastExecTime = taosGetTimestampMs(); switch (pTrans->stage) { case TRN_STAGE_PREPARE: From f4aedcf6fd86b21e4b236651fe5d249f3aa0f463 Mon Sep 17 00:00:00 2001 From: dmchen Date: Tue, 3 Dec 2024 09:58:14 +0800 Subject: [PATCH 08/62] fix/exit-fail-retry-when-follower --- source/dnode/mnode/impl/src/mndTrans.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/source/dnode/mnode/impl/src/mndTrans.c b/source/dnode/mnode/impl/src/mndTrans.c index 65d76a39bd..3d78067634 100644 --- a/source/dnode/mnode/impl/src/mndTrans.c +++ b/source/dnode/mnode/impl/src/mndTrans.c @@ -1671,9 +1671,6 @@ static bool mndTransPerformRedoActionStage(SMnode *pMnode, STrans *pTrans, bool return false; } } - - // if (mndCannotExecuteTrans(pMnode, topHalf)) return false; - terrno = code; if (code == 0) { From 3e0ccd335bd8dd1e64997353d676abbad872a0ef Mon Sep 17 00:00:00 2001 From: yihaoDeng Date: Tue, 3 Dec 2024 15:14:12 +0800 Subject: [PATCH 09/62] update alter-multi-tag doc --- docs/en/14-reference/03-taos-sql/03-table.md | 2 +- docs/zh/14-reference/03-taos-sql/03-table.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/14-reference/03-taos-sql/03-table.md b/docs/en/14-reference/03-taos-sql/03-table.md index 030d88cf63..9727cb98ef 100644 --- a/docs/en/14-reference/03-taos-sql/03-table.md +++ b/docs/en/14-reference/03-taos-sql/03-table.md @@ -194,7 +194,7 @@ alter_table_option: { ### Modify Subtable Tag Value ```sql -ALTER TABLE tb_name SET tag tag_name=new_tag_value; +ALTER TABLE tb_name SET TAG tag_name1=new_tag_value1,tag_nam2=new_tag_value2...; ``` ### Modify Table Lifespan diff --git a/docs/zh/14-reference/03-taos-sql/03-table.md b/docs/zh/14-reference/03-taos-sql/03-table.md index 4bf1bd5b87..9e2cdc89c8 100644 --- a/docs/zh/14-reference/03-taos-sql/03-table.md +++ b/docs/zh/14-reference/03-taos-sql/03-table.md @@ -195,7 +195,7 @@ alter_table_option: { ### 修改子表标签值 ``` -ALTER TABLE tb_name SET TAG tag_name=new_tag_value; +ALTER TABLE tb_name SET TAG tag_name1=new_tag_value1,tag_nam2=new_tag_value2...; ``` ### 修改表生命周期 From 0f3d290c27992ce57e0de3d000085359981cc494 Mon Sep 17 00:00:00 2001 From: yihaoDeng Date: Tue, 3 Dec 2024 15:14:37 +0800 Subject: [PATCH 10/62] update alter-multi-tag doc --- docs/en/14-reference/03-taos-sql/03-table.md | 2 +- docs/zh/14-reference/03-taos-sql/03-table.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/14-reference/03-taos-sql/03-table.md b/docs/en/14-reference/03-taos-sql/03-table.md index 9727cb98ef..3c047eb19e 100644 --- a/docs/en/14-reference/03-taos-sql/03-table.md +++ b/docs/en/14-reference/03-taos-sql/03-table.md @@ -194,7 +194,7 @@ alter_table_option: { ### Modify Subtable Tag Value ```sql -ALTER TABLE tb_name SET TAG tag_name1=new_tag_value1,tag_nam2=new_tag_value2...; +ALTER TABLE tb_name SET TAG tag_name1=new_tag_value1,tag_name2=new_tag_value2...; ``` ### Modify Table Lifespan diff --git a/docs/zh/14-reference/03-taos-sql/03-table.md b/docs/zh/14-reference/03-taos-sql/03-table.md index 9e2cdc89c8..a9f9ddb517 100644 --- a/docs/zh/14-reference/03-taos-sql/03-table.md +++ b/docs/zh/14-reference/03-taos-sql/03-table.md @@ -195,7 +195,7 @@ alter_table_option: { ### 修改子表标签值 ``` -ALTER TABLE tb_name SET TAG tag_name1=new_tag_value1,tag_nam2=new_tag_value2...; +ALTER TABLE tb_name SET TAG tag_name1=new_tag_value1,tag_name2=new_tag_value2...; ``` ### 修改表生命周期 From 8c453d5d2c3d2b2b0ca81b6bd1062d2943d0727f Mon Sep 17 00:00:00 2001 From: factosea <285808407@qq.com> Date: Tue, 3 Dec 2024 15:37:28 +0800 Subject: [PATCH 11/62] test case --- tests/system-test/2-query/and_or_for_byte.py | 12 +++++++++++ tests/system-test/2-query/max_partition.py | 4 ++++ tests/system-test/2-query/normal.py | 21 +++++++++++++++++++- tests/system-test/2-query/not.py | 9 +++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/tests/system-test/2-query/and_or_for_byte.py b/tests/system-test/2-query/and_or_for_byte.py index ca9c1f2bef..22ec7ef29b 100644 --- a/tests/system-test/2-query/and_or_for_byte.py +++ b/tests/system-test/2-query/and_or_for_byte.py @@ -515,6 +515,18 @@ class TDTestCase: tdSql.query(f"select t1 from {dbname}.stb1 where abs(c1+t1)=1") tdSql.checkRows(1) tdSql.checkData(0,0,0) + tdSql.query(f"select * from {dbname}.stb1") + rows = tdSql.queryRows + tdSql.query(f"select t1 from {dbname}.stb1 where abs(c1+t1)=1 or (1<2)") + tdSql.checkRows(rows) + tdSql.query(f"select t1 from {dbname}.stb1 where abs(c1+t1)=1 and (1<2)") + tdSql.checkRows(1) + tdSql.checkData(0,0,0) + tdSql.query(f"select t1 from {dbname}.stb1 where abs(c1+t1)=1 and (1>2)") + tdSql.checkRows(0) + tdSql.query(f"select t1 from {dbname}.stb1 where abs(c1+t1)=1 or (1>2)") + tdSql.checkRows(1) + tdSql.checkData(0,0,0) tdSql.query( f"select abs(c1+t1)*t1 from {dbname}.stb1 where abs(c1)/floor(abs(ceil(t1))) ==1") diff --git a/tests/system-test/2-query/max_partition.py b/tests/system-test/2-query/max_partition.py index c4635dcf50..824488652f 100644 --- a/tests/system-test/2-query/max_partition.py +++ b/tests/system-test/2-query/max_partition.py @@ -64,6 +64,10 @@ class TDTestCase: tdSql.query(f"select tbname , max(c1) from {dbname}.sub_stb_1 where c1 is null group by c1 order by c1 desc ") tdSql.checkRows(1) tdSql.checkData(0,0,"sub_stb_1") + tdSql.query(f"select tbname , max(c1) from {dbname}.sub_stb_1 group by c1 order by c1 desc ") + rows = tdSql.queryRows + tdSql.query(f"select tbname , max(c1) from {dbname}.sub_stb_1 where c1 is null or (1<2) group by c1 order by c1 desc ") + tdSql.checkRows(rows) tdSql.query(f"select max(c1) ,c2 ,t2,tbname from {dbname}.stb group by abs(c1) order by abs(c1)") tdSql.checkRows(self.row_nums+1) diff --git a/tests/system-test/2-query/normal.py b/tests/system-test/2-query/normal.py index 161a9e610d..32357d2a37 100644 --- a/tests/system-test/2-query/normal.py +++ b/tests/system-test/2-query/normal.py @@ -75,6 +75,25 @@ class TDTestCase: tdSql.checkData(1, 1, 3) tdSql.checkData(2, 1, 9) + tdSql.query(f"select * from {dbname}.stb_1 order by ts") + rows = tdSql.queryRows + tdSql.query(f"select * from {dbname}.stb_1 where col1 in (1, 2) or (1<2) order by ts") + tdSql.checkRows(rows) + + tdSql.query(f"select * from (select * from {dbname}.stb_1 where col1 in (1, 9, 3) or (1<2) order by ts)") + tdSql.checkRows(rows) + + tdSql.query(f"select * from {dbname}.stb_1 where col1 in (1, 2) and (1<2) order by ts") + tdSql.checkRows(2) + tdSql.checkData(0, 1, 1) + tdSql.checkData(1, 1, 2) + + tdSql.query(f"select * from {dbname}.stb_1 where col1 in (1, 9, 3) and (1<2) order by ts") + tdSql.checkRows(3) + tdSql.checkData(0, 1, 1) + tdSql.checkData(1, 1, 3) + tdSql.checkData(2, 1, 9) + tdSql.query(f"select * from {dbname}.stb_1 where col1 in (1, 9, 3, 'xy') order by ts") tdSql.checkRows(3) tdSql.checkData(0, 1, 1) @@ -160,7 +179,7 @@ class TDTestCase: tdSql.prepare() self.timeZoneTest() - # self.inAndNotinTest() + self.inAndNotinTest() def stop(self): diff --git a/tests/system-test/2-query/not.py b/tests/system-test/2-query/not.py index 1254226db3..9f4813bebc 100644 --- a/tests/system-test/2-query/not.py +++ b/tests/system-test/2-query/not.py @@ -28,6 +28,10 @@ class TDTestCase: for type_name in stype: tdsql.execute(f"drop table if exists {dbname}.{stbname}") tdsql.execute(f"create table if not exists {dbname}.{stbname} (ts timestamp, v1 {type_name}) tags(t1 {type_name})") + + tdsql.query(f"select t1, * from {dbname}.{stbname} where t1 not in (1, 2) or (1<2) order by t1") + tdsql.checkRows(0) + tdsql.execute(f"insert into {dbname}.sub_1 using {dbname}.{stbname} tags(1) values({self.ts}, 10)") tdsql.execute(f"insert into {dbname}.sub_2 using {dbname}.{stbname} tags(2) values({self.ts + 1000}, 20)") tdsql.execute(f"insert into {dbname}.sub_3 using {dbname}.{stbname} tags(3) values({self.ts + 2000}, 30)") @@ -36,6 +40,11 @@ class TDTestCase: tdsql.query(f"select t1, * from {dbname}.{stbname} where t1 not in (1, 2) order by t1") tdsql.checkRows(1) tdsql.checkData(0, 0, 3) + tdsql.query(f"select * from {dbname}.{stbname} where t1 not in (1, 2) or (1<2) order by t1") + tdsql.checkRows(3) + tdsql.checkData(0, 1, 10) + tdsql.checkData(1, 1, 20) + tdsql.checkData(2, 1, 30) # Test case 2: NOT BETWEEN tdsql.query(f"select * from {dbname}.{stbname} where v1 not between 10 and 20 order by t1") From a1bda29ffc4f40fc42de513c535a4eb118deca77 Mon Sep 17 00:00:00 2001 From: happyguoxy Date: Tue, 3 Dec 2024 16:54:17 +0800 Subject: [PATCH 12/62] test: refine debug --- tests/ci/container_build_newmachine.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ci/container_build_newmachine.sh b/tests/ci/container_build_newmachine.sh index 3c87cf156f..369429b99f 100755 --- a/tests/ci/container_build_newmachine.sh +++ b/tests/ci/container_build_newmachine.sh @@ -80,7 +80,7 @@ else fi -mv ${REP_REAL_PATH}/debug ${WORKDIR}/debugSan +rm -rf ${REP_REAL_PATH}/debug date ret=$? From b18a76f0c6ff7dbf3894e1eac9b49080976a0989 Mon Sep 17 00:00:00 2001 From: happyguoxy Date: Tue, 3 Dec 2024 17:16:36 +0800 Subject: [PATCH 13/62] test: refine debug --- tests/run_all_ci_cases.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/run_all_ci_cases.sh b/tests/run_all_ci_cases.sh index 486c47ff4c..959af66d19 100644 --- a/tests/run_all_ci_cases.sh +++ b/tests/run_all_ci_cases.sh @@ -27,7 +27,6 @@ function runCasesOneByOne () { || echo -e "${RED}$case failed${NC}" | tee -a $TDENGINE_ALLCI_REPORT end_time=`date +%s` echo execution time of $case was `expr $end_time - $start_time`s. | tee -a $TDENGINE_ALLCI_REPORT - if $case failed elif [[ "$line" == *"$2"* ]]; then if [[ "$cmd" == *"pytest.sh"* ]]; then From cd274063d51f686859ea4b05115434fec5cc2d67 Mon Sep 17 00:00:00 2001 From: Yu Chen <74105241+yu285@users.noreply.github.com> Date: Wed, 4 Dec 2024 09:23:24 +0800 Subject: [PATCH 14/62] docs/ optimize the description regarding native connection --- docs/zh/07-develop/01-connect/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/07-develop/01-connect/index.md b/docs/zh/07-develop/01-connect/index.md index 94f55967ec..2381c49d93 100644 --- a/docs/zh/07-develop/01-connect/index.md +++ b/docs/zh/07-develop/01-connect/index.md @@ -37,7 +37,7 @@ TDengine 提供了丰富的应用程序开发接口,为了便于用户快速 关键不同点在于: -1. 使用 原生连接,需要保证客户端的驱动程序 taosc 和服务端的 TDengine 版本配套。 +1. 使用 原生连接,需要保证客户端的驱动程序 taosc 和服务端的 TDengine 版本保持一致。 2. 使用 REST 连接,用户无需安装客户端驱动程序 taosc,具有跨平台易用的优势,但是无法体验数据订阅和二进制数据类型等功能。另外与 原生连接 和 WebSocket 连接相比,REST连接的性能最低。REST 接口是无状态的。在使用 REST 连接时,需要在 SQL 中指定表、超级表的数据库名称。 3. 使用 WebSocket 连接,用户也无需安装客户端驱动程序 taosc。 4. 连接云服务实例,必须使用 REST 连接 或 WebSocket 连接。 From e3fa2b775f43b624b2e3de997c1755b6cd4f7a48 Mon Sep 17 00:00:00 2001 From: facetosea <25808407@qq.com> Date: Wed, 4 Dec 2024 09:35:21 +0800 Subject: [PATCH 15/62] enh: time range when or const value --- source/libs/parser/src/parTranslater.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index 2e167d3053..3c5aeb142e 100755 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -5623,10 +5623,11 @@ static int32_t getTimeRange(SNode** pPrimaryKeyCond, STimeWindow* pTimeRange, bo int32_t code = scalarCalculateConstants(*pPrimaryKeyCond, &pNew); if (TSDB_CODE_SUCCESS == code) { *pPrimaryKeyCond = pNew; - if(nodeType(pNew) == QUERY_NODE_VALUE) { + if (nodeType(pNew) == QUERY_NODE_VALUE) { *pTimeRange = TSWINDOW_INITIALIZER; + } else { + code = filterGetTimeRange(*pPrimaryKeyCond, pTimeRange, pIsStrict); } - code = filterGetTimeRange(*pPrimaryKeyCond, pTimeRange, pIsStrict); } return code; } From 3847ed2dc9ae52ae6384a217509787ef7bde0934 Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Wed, 4 Dec 2024 09:43:51 +0800 Subject: [PATCH 16/62] refactor: 1) adjust wal scan interval to be 500ms, 2) record the checkpointVer to be timestamp for force_window_close, 3) do some other internal refactor. --- source/dnode/vnode/src/tq/tqSink.c | 8 +- source/dnode/vnode/src/tq/tqStreamTask.c | 106 ++++++++---------- source/libs/stream/src/streamBackendRocksdb.c | 1 - source/libs/stream/src/streamExec.c | 65 ++++++----- source/libs/stream/src/streamSched.c | 13 ++- 5 files changed, 96 insertions(+), 97 deletions(-) diff --git a/source/dnode/vnode/src/tq/tqSink.c b/source/dnode/vnode/src/tq/tqSink.c index be41f7e99e..51ef02de56 100644 --- a/source/dnode/vnode/src/tq/tqSink.c +++ b/source/dnode/vnode/src/tq/tqSink.c @@ -13,9 +13,7 @@ * along with this program. If not, see . */ -#include #include "tcommon.h" -#include "tmsg.h" #include "tq.h" #define IS_NEW_SUBTB_RULE(_t) (((_t)->ver >= SSTREAM_TASK_SUBTABLE_CHANGED_VER) && ((_t)->subtableWithoutMd5 != 1)) @@ -50,7 +48,7 @@ static int32_t doPutSinkTableInfoIntoCache(SSHashObj* pSinkTableMap, STableSinkI static bool doGetSinkTableInfoFromCache(SSHashObj* pTableInfoMap, uint64_t groupId, STableSinkInfo** pInfo); static int32_t doRemoveSinkTableInfoInCache(SSHashObj* pSinkTableMap, uint64_t groupId, const char* id); static int32_t checkTagSchema(SStreamTask* pTask, SVnode* pVnode); -static void reubuildAndSendMultiResBlock(SStreamTask* pTask, const SArray* pBlocks, SVnode* pVnode, int64_t earlyTs); +static void rebuildAndSendMultiResBlock(SStreamTask* pTask, const SArray* pBlocks, SVnode* pVnode, int64_t earlyTs); static int32_t handleResultBlockMsg(SStreamTask* pTask, SSDataBlock* pDataBlock, int32_t index, SVnode* pVnode, int64_t earlyTs); @@ -1062,7 +1060,7 @@ void tqSinkDataIntoDstTable(SStreamTask* pTask, void* vnode, void* data) { return; } - reubuildAndSendMultiResBlock(pTask, pBlocks, pVnode, earlyTs); + rebuildAndSendMultiResBlock(pTask, pBlocks, pVnode, earlyTs); } } @@ -1165,7 +1163,7 @@ int32_t doBuildAndSendDeleteMsg(SVnode* pVnode, char* stbFullName, SSDataBlock* return TSDB_CODE_SUCCESS; } -void reubuildAndSendMultiResBlock(SStreamTask* pTask, const SArray* pBlocks, SVnode* pVnode, int64_t earlyTs) { +void rebuildAndSendMultiResBlock(SStreamTask* pTask, const SArray* pBlocks, SVnode* pVnode, int64_t earlyTs) { int32_t code = 0; const char* id = pTask->id.idStr; int32_t vgId = pTask->pMeta->vgId; diff --git a/source/dnode/vnode/src/tq/tqStreamTask.c b/source/dnode/vnode/src/tq/tqStreamTask.c index 29372c5da7..bc7e2e28e3 100644 --- a/source/dnode/vnode/src/tq/tqStreamTask.c +++ b/source/dnode/vnode/src/tq/tqStreamTask.c @@ -17,19 +17,20 @@ #include "vnd.h" #define MAX_REPEAT_SCAN_THRESHOLD 3 -#define SCAN_WAL_IDLE_DURATION 100 +#define SCAN_WAL_IDLE_DURATION 500 // idle for 500ms to do next wal scan typedef struct SBuildScanWalMsgParam { int64_t metaId; int32_t numOfTasks; } SBuildScanWalMsgParam; -static int32_t doScanWalForAllTasks(SStreamMeta* pStreamMeta, bool* pScanIdle); +static int32_t doScanWalForAllTasks(SStreamMeta* pStreamMeta); static int32_t setWalReaderStartOffset(SStreamTask* pTask, int32_t vgId); static bool handleFillhistoryScanComplete(SStreamTask* pTask, int64_t ver); static bool taskReadyForDataFromWal(SStreamTask* pTask); static int32_t doPutDataIntoInputQ(SStreamTask* pTask, int64_t maxVer, int32_t* numOfItems, bool* pSucc); static int32_t tqScanWalInFuture(STQ* pTq, int32_t numOfTasks, int32_t idleDuration); +static int32_t doScanWalAsync(STQ* pTq, bool ckPause); // extract data blocks(submit/delete) from WAL, and add them into the input queue for all the sources tasks. int32_t tqScanWal(STQ* pTq) { @@ -37,12 +38,11 @@ int32_t tqScanWal(STQ* pTq) { int32_t vgId = pMeta->vgId; int64_t st = taosGetTimestampMs(); int32_t numOfTasks = 0; - bool shouldIdle = true; tqDebug("vgId:%d continue to check if data in wal are available, scanCounter:%d", vgId, pMeta->scanInfo.scanCounter); // check all tasks - int32_t code = doScanWalForAllTasks(pMeta, &shouldIdle); + int32_t code = doScanWalForAllTasks(pMeta); if (code) { tqError("vgId:%d failed to start all tasks, try next time, code:%s", vgId, tstrerror(code)); return code; @@ -133,10 +133,9 @@ int32_t tqScanWalInFuture(STQ* pTq, int32_t numOfTasks, int32_t idleDuration) { } int32_t tqScanWalAsync(STQ* pTq, bool ckPause) { - int32_t vgId = TD_VID(pTq->pVnode); SStreamMeta* pMeta = pTq->pStreamMeta; bool alreadyRestored = pTq->pVnode->restored; - int32_t numOfTasks = 0; + int32_t code = 0; // do not launch the stream tasks, if it is a follower or not restored vnode. if (!(vnodeIsRoleLeader(pTq->pVnode) && alreadyRestored)) { @@ -144,47 +143,8 @@ int32_t tqScanWalAsync(STQ* pTq, bool ckPause) { } streamMetaWLock(pMeta); - - numOfTasks = taosArrayGetSize(pMeta->pTaskList); - if (numOfTasks == 0) { - tqDebug("vgId:%d no stream tasks existed to run", vgId); - streamMetaWUnLock(pMeta); - return 0; - } - - if (pMeta->startInfo.startAllTasks) { - tqTrace("vgId:%d in restart procedure, not scan wal", vgId); - streamMetaWUnLock(pMeta); - return 0; - } - - pMeta->scanInfo.scanCounter += 1; - if (pMeta->scanInfo.scanCounter > MAX_REPEAT_SCAN_THRESHOLD) { - pMeta->scanInfo.scanCounter = MAX_REPEAT_SCAN_THRESHOLD; - } - - if (pMeta->scanInfo.scanCounter > 1) { - tqDebug("vgId:%d wal read task has been launched, remain scan times:%d", vgId, pMeta->scanInfo.scanCounter); - streamMetaWUnLock(pMeta); - return 0; - } - - int32_t numOfPauseTasks = pMeta->numOfPausedTasks; - if (ckPause && numOfTasks == numOfPauseTasks) { - tqDebug("vgId:%d ignore all submit, all streams had been paused, reset the walScanCounter", vgId); - - // reset the counter value, since we do not launch the scan wal operation. - pMeta->scanInfo.scanCounter = 0; - streamMetaWUnLock(pMeta); - return 0; - } - - tqDebug("vgId:%d create msg to start wal scan to launch stream tasks, numOfTasks:%d, vnd restored:%d", vgId, - numOfTasks, alreadyRestored); - - int32_t code = streamTaskSchedTask(&pTq->pVnode->msgCb, vgId, 0, 0, STREAM_EXEC_T_EXTRACT_WAL_DATA); + code = doScanWalAsync(pTq, ckPause); streamMetaWUnLock(pMeta); - return code; } @@ -368,11 +328,8 @@ int32_t doPutDataIntoInputQ(SStreamTask* pTask, int64_t maxVer, int32_t* numOfIt return code; } -int32_t doScanWalForAllTasks(SStreamMeta* pStreamMeta, bool* pScanIdle) { - *pScanIdle = true; - bool noDataInWal = true; +int32_t doScanWalForAllTasks(SStreamMeta* pStreamMeta) { int32_t vgId = pStreamMeta->vgId; - int32_t numOfTasks = taosArrayGetSize(pStreamMeta->pTaskList); if (numOfTasks == 0) { return TSDB_CODE_SUCCESS; @@ -410,8 +367,6 @@ int32_t doScanWalForAllTasks(SStreamMeta* pStreamMeta, bool* pScanIdle) { continue; } - *pScanIdle = false; - // seek the stored version and extract data from WAL code = setWalReaderStartOffset(pTask, vgId); if (code != TSDB_CODE_SUCCESS) { @@ -437,7 +392,6 @@ int32_t doScanWalForAllTasks(SStreamMeta* pStreamMeta, bool* pScanIdle) { streamMutexUnlock(&pTask->lock); if ((numOfItems > 0) || hasNewData) { - noDataInWal = false; code = streamTrySchedExec(pTask); if (code != TSDB_CODE_SUCCESS) { streamMetaReleaseTask(pStreamMeta, pTask); @@ -449,11 +403,47 @@ int32_t doScanWalForAllTasks(SStreamMeta* pStreamMeta, bool* pScanIdle) { streamMetaReleaseTask(pStreamMeta, pTask); } - // all wal are checked, and no new data available in wal. - if (noDataInWal) { - *pScanIdle = true; - } - taosArrayDestroy(pTaskList); return TSDB_CODE_SUCCESS; } + +int32_t doScanWalAsync(STQ* pTq, bool ckPause) { + SStreamMeta* pMeta = pTq->pStreamMeta; + bool alreadyRestored = pTq->pVnode->restored; + int32_t vgId = pMeta->vgId; + int32_t numOfTasks = taosArrayGetSize(pMeta->pTaskList); + + if (numOfTasks == 0) { + tqDebug("vgId:%d no stream tasks existed to run", vgId); + return 0; + } + + if (pMeta->startInfo.startAllTasks) { + tqTrace("vgId:%d in restart procedure, not scan wal", vgId); + return 0; + } + + pMeta->scanInfo.scanCounter += 1; + if (pMeta->scanInfo.scanCounter > MAX_REPEAT_SCAN_THRESHOLD) { + pMeta->scanInfo.scanCounter = MAX_REPEAT_SCAN_THRESHOLD; + } + + if (pMeta->scanInfo.scanCounter > 1) { + tqDebug("vgId:%d wal read task has been launched, remain scan times:%d", vgId, pMeta->scanInfo.scanCounter); + return 0; + } + + int32_t numOfPauseTasks = pMeta->numOfPausedTasks; + if (ckPause && numOfTasks == numOfPauseTasks) { + tqDebug("vgId:%d ignore all submit, all streams had been paused, reset the walScanCounter", vgId); + + // reset the counter value, since we do not launch the scan wal operation. + pMeta->scanInfo.scanCounter = 0; + return 0; + } + + tqDebug("vgId:%d create msg to start wal scan to launch stream tasks, numOfTasks:%d, vnd restored:%d", vgId, + numOfTasks, alreadyRestored); + + return streamTaskSchedTask(&pTq->pVnode->msgCb, vgId, 0, 0, STREAM_EXEC_T_EXTRACT_WAL_DATA); +} diff --git a/source/libs/stream/src/streamBackendRocksdb.c b/source/libs/stream/src/streamBackendRocksdb.c index 09f4e95376..394c6408ba 100644 --- a/source/libs/stream/src/streamBackendRocksdb.c +++ b/source/libs/stream/src/streamBackendRocksdb.c @@ -4378,7 +4378,6 @@ void streamStateParTagSeekKeyNext_rocksdb(SStreamState* pState, const int64_t gr } int32_t streamStateParTagGetKVByCur_rocksdb(SStreamStateCur* pCur, int64_t* pGroupId, const void** pVal, int32_t* pVLen) { - stDebug("streamStateFillGetKVByCur_rocksdb"); if (!pCur) { return -1; } diff --git a/source/libs/stream/src/streamExec.c b/source/libs/stream/src/streamExec.c index 318720b5b0..85f287f301 100644 --- a/source/libs/stream/src/streamExec.c +++ b/source/libs/stream/src/streamExec.c @@ -522,7 +522,10 @@ static int32_t doSetStreamInputBlock(SStreamTask* pTask, const void* pInput, int if (pItem->type == STREAM_INPUT__GET_RES) { const SStreamTrigger* pTrigger = (const SStreamTrigger*)pInput; code = qSetMultiStreamInput(pExecutor, pTrigger->pBlock, 1, STREAM_INPUT__DATA_BLOCK); - + if (pTask->info.trigger == STREAM_TRIGGER_FORCE_WINDOW_CLOSE) { + stDebug("s-task:%s set force_window_close as source block, skey:%"PRId64, id, pTrigger->pBlock->info.window.skey); + (*pVer) = pTrigger->pBlock->info.window.skey; + } } else if (pItem->type == STREAM_INPUT__DATA_SUBMIT) { const SStreamDataSubmit* pSubmit = (const SStreamDataSubmit*)pInput; code = qSetMultiStreamInput(pExecutor, &pSubmit->submit, 1, STREAM_INPUT__DATA_SUBMIT); @@ -671,7 +674,7 @@ static int32_t doStreamTaskExecImpl(SStreamTask* pTask, SStreamQueueItem* pBlock doRecordThroughput(&pTask->execInfo, totalBlocks, totalSize, blockSize, st, pTask->id.idStr); - // update the currentVer if processing the submit blocks. + // update the currentVer if processing the submitted blocks. if (!(pInfo->checkpointVer <= pInfo->nextProcessVer && ver >= pInfo->checkpointVer)) { stError("s-task:%s invalid info, checkpointVer:%" PRId64 ", nextProcessVer:%" PRId64 " currentVer:%" PRId64, id, pInfo->checkpointVer, pInfo->nextProcessVer, ver); @@ -688,6 +691,34 @@ static int32_t doStreamTaskExecImpl(SStreamTask* pTask, SStreamQueueItem* pBlock return code; } +// do nothing after sync executor state to storage backend, untill checkpoint is completed. +static int32_t doHandleChkptBlock(SStreamTask* pTask) { + int32_t code = 0; + const char* id = pTask->id.idStr; + + streamMutexLock(&pTask->lock); + SStreamTaskState pState = streamTaskGetStatus(pTask); + if (pState.state == TASK_STATUS__CK) { // todo other thread may change the status + stDebug("s-task:%s checkpoint block received, set status:%s", id, pState.name); + code = streamTaskBuildCheckpoint(pTask); // ignore this error msg, and continue + } else { // todo refactor + if (pTask->info.taskLevel == TASK_LEVEL__SOURCE) { + code = streamTaskSendCheckpointSourceRsp(pTask); + } else { + code = streamTaskSendCheckpointReadyMsg(pTask); + } + + if (code != TSDB_CODE_SUCCESS) { + // todo: let's retry send rsp to upstream/mnode + stError("s-task:%s failed to send checkpoint rsp to upstream, checkpointId:%d, code:%s", id, 0, + tstrerror(code)); + } + } + + streamMutexUnlock(&pTask->lock); + return code; +} + int32_t flushStateDataInExecutor(SStreamTask* pTask, SStreamQueueItem* pCheckpointBlock) { const char* id = pTask->id.idStr; @@ -832,36 +863,16 @@ static int32_t doStreamExecTask(SStreamTask* pTask) { } } - if (type != STREAM_INPUT__CHECKPOINT) { + if (type == STREAM_INPUT__CHECKPOINT) { + code = doHandleChkptBlock(pTask); + streamFreeQitem(pInput); + return code; + } else { code = doStreamTaskExecImpl(pTask, pInput, numOfBlocks); streamFreeQitem(pInput); if (code) { return code; } - } else { // todo other thread may change the status - // do nothing after sync executor state to storage backend, untill the vnode-level checkpoint is completed. - streamMutexLock(&pTask->lock); - SStreamTaskState pState = streamTaskGetStatus(pTask); - if (pState.state == TASK_STATUS__CK) { - stDebug("s-task:%s checkpoint block received, set status:%s", id, pState.name); - code = streamTaskBuildCheckpoint(pTask); // ignore this error msg, and continue - } else { // todo refactor - if (pTask->info.taskLevel == TASK_LEVEL__SOURCE) { - code = streamTaskSendCheckpointSourceRsp(pTask); - } else { - code = streamTaskSendCheckpointReadyMsg(pTask); - } - - if (code != TSDB_CODE_SUCCESS) { - // todo: let's retry send rsp to upstream/mnode - stError("s-task:%s failed to send checkpoint rsp to upstream, checkpointId:%d, code:%s", id, 0, - tstrerror(code)); - } - } - - streamMutexUnlock(&pTask->lock); - streamFreeQitem(pInput); - return code; } } } diff --git a/source/libs/stream/src/streamSched.c b/source/libs/stream/src/streamSched.c index 468c5f2139..bf402234ba 100644 --- a/source/libs/stream/src/streamSched.c +++ b/source/libs/stream/src/streamSched.c @@ -214,7 +214,6 @@ static int32_t doCreateForceWindowTrigger(SStreamTask* pTask, int32_t* pNextTrig // check whether the time window gaps exist or not int64_t now = taosGetTimestamp(precision); - int64_t ekey = pTrigger->pBlock->info.window.skey + pTask->info.interval.interval; // there are gaps, needs to be filled STimeWindow w = pTrigger->pBlock->info.window; @@ -226,13 +225,15 @@ static int32_t doCreateForceWindowTrigger(SStreamTask* pTask, int32_t* pNextTrig } pTask->status.latestForceWindow = w; - if (ekey + pTask->info.watermark + pTask->info.interval.interval > now) { + if (w.ekey + pTask->info.watermark + pTask->info.interval.interval > now) { int64_t prev = convertTimePrecision(*pNextTrigger, precision, TSDB_TIME_PRECISION_MILLI); - *pNextTrigger = ekey + pTask->info.watermark + pTask->info.interval.interval - now; + *pNextTrigger = w.ekey + pTask->info.watermark + pTask->info.interval.interval - now; *pNextTrigger = convertTimePrecision(*pNextTrigger, precision, TSDB_TIME_PRECISION_MILLI); - stDebug("s-task:%s generate %d time window(s), trigger delay adjust from %" PRId64 " to %d", id, num, prev, - *pNextTrigger); + + pTask->chkInfo.nextProcessVer = w.ekey + pTask->info.interval.interval; + stDebug("s-task:%s generate %d time window(s), trigger delay adjust from %" PRId64 " to %d, set ver:%" PRId64, id, + num, prev, *pNextTrigger, pTask->chkInfo.nextProcessVer); return code; } else { stDebug("s-task:%s gap exist for force_window_close, current force_window_skey:%" PRId64, id, w.skey); @@ -289,7 +290,7 @@ void streamTaskSchedHelper(void* param, void* tmrId) { } if (streamTaskGetStatus(pTask).state == TASK_STATUS__CK) { - nextTrigger = TRIGGER_RECHECK_INTERVAL; // retry in 10 seec + nextTrigger = TRIGGER_RECHECK_INTERVAL; // retry in 10 sec stDebug("s-task:%s in checkpoint procedure, not retrieve result, next:%dms", id, TRIGGER_RECHECK_INTERVAL); } else { if (pTask->info.trigger == STREAM_TRIGGER_FORCE_WINDOW_CLOSE && pTask->info.taskLevel == TASK_LEVEL__SOURCE) { From 4cf63805f5cdbccad28c2b5f4fdd12e5555ca565 Mon Sep 17 00:00:00 2001 From: Yibo Liu Date: Wed, 4 Dec 2024 11:27:16 +0800 Subject: [PATCH 17/62] Update index.mdx Added TDengine Alert function description to the TDinsight manual Introduced the 14 newly added alert rules in a table format --- .../01-components/12-tdinsight/index.mdx | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx index e5f44a1080..5c22dbf57a 100644 --- a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx +++ b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx @@ -145,6 +145,44 @@ TDinsight 仪表盘旨在提供 TDengine 相关资源的使用情况和状态, 还有上述分类的细分维度折线图。 +### 预配置告警规则自动导入 + +涛思总结用户使用经验,整理出14个常用的告警规则(alert rule),能够对集群关键指标进行监测并及时上报指标异常、超限等告警信息。 +从TDengine-server 3.3.4.3版本(tdengine-datasource 3.6.3)开始,TDengine Datasource 支持预配置告警规则自动导入功能,用户可将14个告警规则一键导入Grafana,直接使用。 +预配置告警规则导入方法如下图所示,在tdengine-datasource setting界面,打开Load TDengine Alert开关,即可导入所有预配置告警规则;如不需要,点击Clear TDengine Alert按钮即可删除所有预配置告警规则。 + +![TDengine Alert](./assets/TDengine-Alert.webp) + +导入后,点击Grafana左侧Alert rules,可查看当前所有告警规则。 +用户只需配置联络点(Contact points),即可获取告警通知。联络点配置方法见[告警配置](https://docs.taosdata.com/third-party/visual/grafana/#%E5%91%8A%E8%AD%A6%E9%85%8D%E7%BD%AE)。 + +![Alert-rules](./assets/Alert-rules.webp) + +14个告警规则具体配置如下: + +| 规则名称| 规则阈值| 无监控数据时的行为 | 数据扫描间隔 |持续时间 | 执行SQL | +| ------ | --------- | ---------------- | ----------- |------- |----------------------| +|dnode 节点的CPU负载|均值 > 80%|触发告警|5分钟|5分钟 |select now(), dnode_id, last(cpu_system) as cup_use from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts < now partition by dnode_id having first(_ts) > 0 | +|dnode 节点的的内存 |均值 > 60%|触发告警|5分钟|5分钟|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 80%|触发告警|5分钟|5分钟|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts = (now- 5m) and _ts = 90%|触发告警|1天|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 100|不触发报警|1分钟|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 300秒|不触发报警|1分钟|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts = (now- 5m) and _ts = (now- 5m) and _ts 0|不触发报警|30秒|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 5|不触发报警|30秒|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 5|不触发报警|30秒|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts = (now- 5m) and _ts last(update_time)|触发告警|90秒|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts Date: Wed, 4 Dec 2024 11:28:52 +0800 Subject: [PATCH 18/62] Add files via upload --- .../12-tdinsight/assets/Alert-Used-Only.webp | Bin 0 -> 217469 bytes .../12-tdinsight/assets/Alert-rules.webp | Bin 0 -> 227473 bytes .../12-tdinsight/assets/TDengine-Alert.webp | Bin 0 -> 97309 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/zh/14-reference/01-components/12-tdinsight/assets/Alert-Used-Only.webp create mode 100644 docs/zh/14-reference/01-components/12-tdinsight/assets/Alert-rules.webp create mode 100644 docs/zh/14-reference/01-components/12-tdinsight/assets/TDengine-Alert.webp diff --git a/docs/zh/14-reference/01-components/12-tdinsight/assets/Alert-Used-Only.webp b/docs/zh/14-reference/01-components/12-tdinsight/assets/Alert-Used-Only.webp new file mode 100644 index 0000000000000000000000000000000000000000..8824ee588952d72992e966578dba07a1a8dc4da3 GIT binary patch literal 217469 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�~bXf4}MA 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 literal 0 HcmV?d00001 diff --git a/docs/zh/14-reference/01-components/12-tdinsight/assets/Alert-rules.webp b/docs/zh/14-reference/01-components/12-tdinsight/assets/Alert-rules.webp new file mode 100644 index 0000000000000000000000000000000000000000..e9f91c0488638078f4b1ad37c677a9c2675c1dc9 GIT binary patch literal 227473 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

=w_*lZUk4jxX*Pa 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 literal 0 HcmV?d00001 diff --git a/docs/zh/14-reference/01-components/12-tdinsight/assets/TDengine-Alert.webp b/docs/zh/14-reference/01-components/12-tdinsight/assets/TDengine-Alert.webp new file mode 100644 index 0000000000000000000000000000000000000000..a0d9b695f49f2703368126ac27767f5f59166f95 GIT binary patch literal 97309 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

1j)n#P3B#ORS8P-P(wx}lU?_RB-;;& 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 J@1T4e`4_BYsOJCx literal 0 HcmV?d00001 From 4a0b6adca49e116cc3dbe6e438521df36f8c1a89 Mon Sep 17 00:00:00 2001 From: factosea <285808407@qq.com> Date: Wed, 4 Dec 2024 11:50:17 +0800 Subject: [PATCH 19/62] fix: group_const_value --- source/libs/function/src/builtins.c | 2 +- tests/system-test/2-query/group_partition.py | 69 ++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/source/libs/function/src/builtins.c b/source/libs/function/src/builtins.c index f8f8fc705e..e018f89dc4 100644 --- a/source/libs/function/src/builtins.c +++ b/source/libs/function/src/builtins.c @@ -4944,7 +4944,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = { .paramInfoPattern = 0, .outputParaInfo = {.validDataType = FUNC_PARAM_SUPPORT_ALL_TYPE}}, .translateFunc = translateSelectValue, - .getEnvFunc = getSelectivityFuncEnv, + .getEnvFunc = getGroupKeyFuncEnv, .initFunc = functionSetup, .processFunc = groupConstValueFunction, .finalizeFunc = groupConstValueFinalize, diff --git a/tests/system-test/2-query/group_partition.py b/tests/system-test/2-query/group_partition.py index 74f5e86267..f3c5bb171c 100644 --- a/tests/system-test/2-query/group_partition.py +++ b/tests/system-test/2-query/group_partition.py @@ -451,7 +451,74 @@ class TDTestCase: sql = "select avg(c1), concat(t9,t10) from db.stb group by concat(t9,t10), concat(t9,t10),tbname" tdSql.query(sql, queryTimes=1) tdSql.checkRows(5) + + def test_TS_5727(self): + tdSql.execute(f" use {self.dbname} ") + stableName = "test5727" + sql = f"CREATE STABLE {self.dbname}.{stableName} (`ts` TIMESTAMP, `WaterConsumption` FLOAT, \ + `ElecConsumption` INT, `Status` BOOL, `status2` BOOL, `online` BOOL) \ + TAGS (`ActivationTime` TIMESTAMP, `ProductId` INT, \ + `ProductMac` VARCHAR(24), `location` INT)" + tdSql.execute(sql) + + sql = f'CREATE TABLE {self.dbname}.`d00` USING {self.dbname}.{stableName} \ + (`ActivationTime`, `ProductId`, `ProductMac`, `location`) \ + TAGS (1733124710578, 1001, "00:11:22:33:44:55", 100000)' + tdSql.execute(sql) + sql = f'CREATE TABLE {self.dbname}.`d01` USING {self.dbname}.{stableName} \ + (`ActivationTime`, `ProductId`, `ProductMac`, `location`) \ + TAGS (1733124723572, 1002, "00:12:22:33:44:55", 200000)' + tdSql.execute(sql) + sql = f'CREATE TABLE {self.dbname}.`d02` USING {self.dbname}.{stableName} \ + (`ActivationTime`, `ProductId`, `ProductMac`, `location`) \ + TAGS (1733124730908, 1003, "00:11:23:33:44:55", 100000)' + tdSql.execute(sql) + + sql = f'insert into {self.dbname}.d00 values(now - 2s, 5, 5, true, true, false);' + tdSql.execute(sql) + sql = f'insert into {self.dbname}.d01 values(now - 1s, 6, 5, true, true, true);' + tdSql.execute(sql) + sql = f'insert into {self.dbname}.d02 values(now, 6, 7, true, true, true);' + tdSql.execute(sql) + + sql = f'select `location`, tbname from {self.dbname}.{stableName} where ts < now group by tbname order by tbname;' + tdSql.query(sql) + tdSql.checkRows(3) + tdSql.checkData(0, 0, 100000) + tdSql.checkData(1, 0, 200000) + tdSql.checkData(2, 0, 100000) + tdSql.checkData(0, 1, "d00") + tdSql.checkData(1, 1, "d01") + tdSql.checkData(2, 1, "d02") + + sql = f'select tbname,last(online) as online,location from {self.dbname}.{stableName} where ts < now group by tbname order by tbname;' + tdSql.query(sql) + tdSql.checkRows(3) + tdSql.checkData(0, 0, "d00") + tdSql.checkData(1, 0, "d01") + tdSql.checkData(2, 0, "d02") + tdSql.checkData(0, 1, False) + tdSql.checkData(1, 1, True) + tdSql.checkData(2, 1, True) + tdSql.checkData(0, 2, 100000) + tdSql.checkData(1, 2, 200000) + tdSql.checkData(2, 2, 100000) + + sql = f'select location,tbname,last_row(online) as online from {self.dbname}.{stableName} where ts < now group by tbname order by tbname;' + tdSql.query(sql) + tdSql.checkRows(3) + tdSql.checkData(0, 0, 100000) + tdSql.checkData(1, 0, 200000) + tdSql.checkData(2, 0, 100000) + tdSql.checkData(0, 1, "d00") + tdSql.checkData(1, 1, "d01") + tdSql.checkData(2, 1, "d02") + tdSql.checkData(0, 2, False) + tdSql.checkData(1, 2, True) + tdSql.checkData(2, 2, True) + + def run(self): tdSql.prepare() self.prepare_db() @@ -493,6 +560,8 @@ class TDTestCase: # self.test_groupby('group', 5, 5) self.test_error() + + self.test_TS_5727() def stop(self): From 2bf3da74150eed886fb6ef4fe1763458464b5305 Mon Sep 17 00:00:00 2001 From: wangjiaming0909 <604227650@qq.com> Date: Tue, 3 Dec 2024 08:56:53 +0800 Subject: [PATCH 20/62] fix tests --- source/libs/parser/src/parAstCreater.c | 35 +++++++++++---------- source/libs/parser/src/parTranslater.c | 4 +-- source/libs/parser/src/parUtil.c | 12 ++++---- source/libs/parser/src/parser.c | 6 ++-- source/libs/planner/src/planPhysiCreater.c | 36 +++++++++++----------- 5 files changed, 48 insertions(+), 45 deletions(-) diff --git a/source/libs/parser/src/parAstCreater.c b/source/libs/parser/src/parAstCreater.c index de8353046e..531c6afc73 100644 --- a/source/libs/parser/src/parAstCreater.c +++ b/source/libs/parser/src/parAstCreater.c @@ -50,12 +50,12 @@ } \ } while (0) -#define COPY_STRING_FORM_ID_TOKEN(buf, pToken) tstrncpy(buf, (pToken)->z, TMIN((pToken)->n + 1, sizeof(buf))) -#define COPY_STRING_FORM_STR_TOKEN(buf, pToken) \ - do { \ - if ((pToken)->n > 2) { \ - tstrncpy(buf, (pToken)->z + 1, TMIN((pToken)->n - 1, sizeof(buf))); \ - } \ +#define COPY_STRING_FORM_ID_TOKEN(buf, pToken) strncpy(buf, (pToken)->z, TMIN((pToken)->n, sizeof(buf) - 1)) +#define COPY_STRING_FORM_STR_TOKEN(buf, pToken) \ + do { \ + if ((pToken)->n > 2) { \ + strncpy(buf, (pToken)->z + 1, TMIN((pToken)->n - 2, sizeof(buf) - 1)); \ + } \ } while (0) SToken nil_token = {.type = TK_NK_NIL, .n = 0, .z = NULL}; @@ -113,7 +113,7 @@ static bool checkPassword(SAstCreateContext* pCxt, const SToken* pPasswordToken, } else if (pPasswordToken->n >= (TSDB_USET_PASSWORD_LEN + 2)) { pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NAME_OR_PASSWD_TOO_LONG); } else { - tstrncpy(pPassword, pPasswordToken->z, TMIN(TSDB_USET_PASSWORD_LEN, pPasswordToken->n + 1)); + strncpy(pPassword, pPasswordToken->z, pPasswordToken->n); (void)strdequote(pPassword); if (strtrim(pPassword) <= 0) { pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_PASSWD_EMPTY); @@ -151,7 +151,7 @@ static int32_t parseEndpoint(SAstCreateContext* pCxt, const SToken* pEp, char* p tstrncpy(pFqdn, ep, TSDB_FQDN_LEN); return TSDB_CODE_SUCCESS; } - tstrncpy(pFqdn, ep, pColon - ep + 1); + strncpy(pFqdn, ep, pColon - ep); return parsePort(pCxt, pColon + 1, pPort); } @@ -327,14 +327,15 @@ SNode* releaseRawExprNode(SAstCreateContext* pCxt, SNode* pNode) { tstrncpy(pExpr->userAlias, ((SFunctionNode*)pExpr)->functionName, TSDB_COL_NAME_LEN); tstrncpy(pExpr->aliasName, ((SFunctionNode*)pExpr)->functionName, TSDB_COL_NAME_LEN); } else { - int32_t len = TMIN(sizeof(pExpr->aliasName), pRawExpr->n + 1); + int32_t len = TMIN(sizeof(pExpr->aliasName) - 1, pRawExpr->n); // See TS-3398. // Len of pRawExpr->p could be larger than len of aliasName[TSDB_COL_NAME_LEN]. // If aliasName is truncated, hash value of aliasName could be the same. uint64_t hashVal = MurmurHash3_64(pRawExpr->p, pRawExpr->n); snprintf(pExpr->aliasName, TSDB_COL_NAME_LEN, "%" PRIu64, hashVal); - tstrncpy(pExpr->userAlias, pRawExpr->p, len); + strncpy(pExpr->userAlias, pRawExpr->p, len); + pExpr->userAlias[len] = 0; } } pRawExpr->pNode = NULL; @@ -1022,7 +1023,7 @@ static SNode* createPrimaryKeyCol(SAstCreateContext* pCxt, const SToken* pFuncNa if (NULL == pFuncName) { tstrncpy(pCol->colName, ROWTS_PSEUDO_COLUMN_NAME, TSDB_COL_NAME_LEN); } else { - tstrncpy(pCol->colName, pFuncName->z, pFuncName->n + 1); + strncpy(pCol->colName, pFuncName->z, pFuncName->n); } pCol->isPrimTs = true; return (SNode*)pCol; @@ -1524,9 +1525,11 @@ SNode* setProjectionAlias(SAstCreateContext* pCxt, SNode* pNode, SToken* pAlias) CHECK_PARSER_STATUS(pCxt); trimEscape(pAlias); SExprNode* pExpr = (SExprNode*)pNode; - int32_t len = TMIN(sizeof(pExpr->aliasName), pAlias->n + 1); - tstrncpy(pExpr->aliasName, pAlias->z, len); - tstrncpy(pExpr->userAlias, pAlias->z, len); + int32_t len = TMIN(sizeof(pExpr->aliasName) - 1, pAlias->n); + strncpy(pExpr->aliasName, pAlias->z, len); + pExpr->aliasName[len] = '\0'; + strncpy(pExpr->userAlias, pAlias->z, len); + pExpr->userAlias[len] = '\0'; pExpr->asAlias = true; return pNode; _err: @@ -2242,7 +2245,7 @@ SNode* setColumnOptions(SAstCreateContext* pCxt, SNode* pOptions, const SToken* char optionType[TSDB_CL_OPTION_LEN]; memset(optionType, 0, TSDB_CL_OPTION_LEN); - tstrncpy(optionType, pVal1->z, TMIN(pVal1->n, TSDB_CL_OPTION_LEN)); + strncpy(optionType, pVal1->z, TMIN(pVal1->n, TSDB_CL_OPTION_LEN)); if (0 == strlen(optionType)) { pCxt->errCode = TSDB_CODE_PAR_SYNTAX_ERROR; return pOptions; @@ -2374,7 +2377,7 @@ SNode* createCreateSubTableFromFileClause(SAstCreateContext* pCxt, bool ignoreEx if (TK_NK_STRING == pFilePath->type) { (void)trimString(pFilePath->z, pFilePath->n, pStmt->filePath, PATH_MAX); } else { - tstrncpy(pStmt->filePath, pFilePath->z, TMIN(PATH_MAX, pFilePath->n + 1)); + strncpy(pStmt->filePath, pFilePath->z, pFilePath->n); } nodesDestroyNode(pUseRealTable); diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index 476d9e1b1c..141e65a111 100755 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -2131,7 +2131,7 @@ static EDealRes translateNormalValue(STranslateContext* pCxt, SValueNode* pVal, return generateDealNodeErrMsg(pCxt, terrno); } varDataSetLen(pVal->datum.p, len); - tstrncpy(varDataVal(pVal->datum.p), pVal->literal, len); + strncpy(varDataVal(pVal->datum.p), pVal->literal, len); break; } case TSDB_DATA_TYPE_TIMESTAMP: { @@ -4395,7 +4395,7 @@ static EDealRes doTranslateTbName(SNode** pNode, void* pContext) { return DEAL_RES_ERROR; } varDataSetLen(pVal->datum.p, tbLen); - tstrncpy(varDataVal(pVal->datum.p), pVal->literal, tbLen); + tstrncpy(varDataVal(pVal->datum.p), pVal->literal, tbLen + 1); tstrncpy(pVal->node.userAlias, pFunc->node.userAlias, TSDB_COL_NAME_LEN); tstrncpy(pVal->node.aliasName, pFunc->node.aliasName, TSDB_COL_NAME_LEN); nodesDestroyNode(*pNode); diff --git a/source/libs/parser/src/parUtil.c b/source/libs/parser/src/parUtil.c index bb54864066..bfe9513594 100644 --- a/source/libs/parser/src/parUtil.c +++ b/source/libs/parser/src/parUtil.c @@ -606,7 +606,7 @@ static int32_t getIntegerFromAuthStr(const char* pStart, char** pNext) { tstrncpy(buf, pStart, 10); *pNext = NULL; } else { - tstrncpy(buf, pStart, p - pStart + 1); + strncpy(buf, pStart, p - pStart); *pNext = ++p; } return taosStr2Int32(buf, NULL, 10); @@ -618,7 +618,7 @@ static void getStringFromAuthStr(const char* pStart, char* pStr, char** pNext) { tstrncpy(pStr, pStart, strlen(pStart) + 1); *pNext = NULL; } else { - tstrncpy(pStr, pStart, p - pStart + 1); + strncpy(pStr, pStart, p - pStart); *pNext = ++p; } if (*pStart == '`' && *(pStart + 1) == '`') { @@ -652,7 +652,7 @@ static int32_t buildTableReq(SHashObj* pTablesHash, SArray** pTables) { size_t len = 0; char* pKey = taosHashGetKey(p, &len); char fullName[TSDB_TABLE_FNAME_LEN] = {0}; - tstrncpy(fullName, pKey, len); + strncpy(fullName, pKey, len); SName name = {0}; int32_t code = tNameFromString(&name, fullName, T_NAME_ACCT | T_NAME_DB | T_NAME_TABLE); if (TSDB_CODE_SUCCESS == code) { @@ -683,7 +683,7 @@ static int32_t buildDbReq(SHashObj* pDbsHash, SArray** pDbs) { size_t len = 0; char* pKey = taosHashGetKey(p, &len); char fullName[TSDB_DB_FNAME_LEN] = {0}; - tstrncpy(fullName, pKey, len); + strncpy(fullName, pKey, len); if (NULL == taosArrayPush(*pDbs, fullName)) { taosHashCancelIterate(pDbsHash, p); taosArrayDestroy(*pDbs); @@ -737,7 +737,7 @@ static int32_t buildUserAuthReq(SHashObj* pUserAuthHash, SArray** pUserAuth) { size_t len = 0; char* pKey = taosHashGetKey(p, &len); char key[USER_AUTH_KEY_MAX_LEN] = {0}; - tstrncpy(key, pKey, len); + strncpy(key, pKey, len); SUserAuthInfo userAuth = {0}; stringToUserAuth(key, len, &userAuth); if (NULL == taosArrayPush(*pUserAuth, &userAuth)) { @@ -763,7 +763,7 @@ static int32_t buildUdfReq(SHashObj* pUdfHash, SArray** pUdf) { size_t len = 0; char* pFunc = taosHashGetKey(p, &len); char func[TSDB_FUNC_NAME_LEN] = {0}; - tstrncpy(func, pFunc, len); + strncpy(func, pFunc, len); if (NULL == taosArrayPush(*pUdf, func)) { taosHashCancelIterate(pUdfHash, p); taosArrayDestroy(*pUdf); diff --git a/source/libs/parser/src/parser.c b/source/libs/parser/src/parser.c index c7ce5334d6..e569ffddf6 100644 --- a/source/libs/parser/src/parser.c +++ b/source/libs/parser/src/parser.c @@ -109,7 +109,7 @@ bool qParseDbName(const char* pStr, size_t length, char** pDbName) { if (*pDbName == NULL) { return false; } - tstrncpy(*pDbName, t.z, dbNameLen); + strncpy(*pDbName, t.z, dbNameLen); (*pDbName)[dbNameLen] = '\0'; return true; } @@ -185,7 +185,7 @@ static int32_t setValueByBindParam(SValueNode* pVal, TAOS_MULTI_BIND* pParam) { return terrno; } varDataSetLen(pVal->datum.p, pVal->node.resType.bytes); - tstrncpy(varDataVal(pVal->datum.p), (const char*)pParam->buffer, pVal->node.resType.bytes); + strncpy(varDataVal(pVal->datum.p), (const char*)pParam->buffer, pVal->node.resType.bytes); pVal->node.resType.bytes += VARSTR_HEADER_SIZE; break; case TSDB_DATA_TYPE_NCHAR: { @@ -472,7 +472,7 @@ static int32_t setValueByBindParam2(SValueNode* pVal, TAOS_STMT2_BIND* pParam) { return terrno; } varDataSetLen(pVal->datum.p, pVal->node.resType.bytes); - tstrncpy(varDataVal(pVal->datum.p), (const char*)pParam->buffer, pVal->node.resType.bytes); + strncpy(varDataVal(pVal->datum.p), (const char*)pParam->buffer, pVal->node.resType.bytes); pVal->node.resType.bytes += VARSTR_HEADER_SIZE; break; case TSDB_DATA_TYPE_NCHAR: { diff --git a/source/libs/planner/src/planPhysiCreater.c b/source/libs/planner/src/planPhysiCreater.c index 16376ae792..af232c667d 100644 --- a/source/libs/planner/src/planPhysiCreater.c +++ b/source/libs/planner/src/planPhysiCreater.c @@ -41,9 +41,9 @@ static int32_t getSlotKey(SNode* pNode, const char* pStmtName, char** ppKey, int if (!*ppKey) { return terrno; } - strncat(*ppKey, pStmtName, TSDB_TABLE_NAME_LEN); - strncat(*ppKey, ".", 2); - strncat(*ppKey, pCol->node.aliasName, TSDB_COL_NAME_LEN); + TAOS_STRNCAT(*ppKey, pStmtName, TSDB_TABLE_NAME_LEN); + TAOS_STRNCAT(*ppKey, ".", 2); + TAOS_STRNCAT(*ppKey, pCol->node.aliasName, TSDB_COL_NAME_LEN); *pLen = taosHashBinary(*ppKey, strlen(*ppKey)); return code; } else { @@ -51,7 +51,7 @@ static int32_t getSlotKey(SNode* pNode, const char* pStmtName, char** ppKey, int if (!*ppKey) { return terrno; } - strncat(*ppKey, pCol->node.aliasName, TSDB_COL_NAME_LEN); + TAOS_STRNCAT(*ppKey, pCol->node.aliasName, TSDB_COL_NAME_LEN); *pLen = strlen(*ppKey); return code; } @@ -61,7 +61,7 @@ static int32_t getSlotKey(SNode* pNode, const char* pStmtName, char** ppKey, int if (!*ppKey) { return terrno; } - strncat(*ppKey, pCol->colName, TSDB_COL_NAME_LEN); + TAOS_STRNCAT(*ppKey, pCol->colName, TSDB_COL_NAME_LEN); *pLen = strlen(*ppKey); return code; } @@ -70,9 +70,9 @@ static int32_t getSlotKey(SNode* pNode, const char* pStmtName, char** ppKey, int if (!*ppKey) { return terrno; } - strncat(*ppKey, pCol->tableAlias, TSDB_TABLE_NAME_LEN); - strncat(*ppKey, ".", 2); - strncat(*ppKey, pCol->colName, TSDB_COL_NAME_LEN); + TAOS_STRNCAT(*ppKey, pCol->tableAlias, TSDB_TABLE_NAME_LEN); + TAOS_STRNCAT(*ppKey, ".", 2); + TAOS_STRNCAT(*ppKey, pCol->colName, TSDB_COL_NAME_LEN); *pLen = taosHashBinary(*ppKey, strlen(*ppKey)); return code; } else if (QUERY_NODE_FUNCTION == nodeType(pNode)) { @@ -85,9 +85,9 @@ static int32_t getSlotKey(SNode* pNode, const char* pStmtName, char** ppKey, int if (!*ppKey) { return terrno; } - strncat(*ppKey, pStmtName, TSDB_TABLE_NAME_LEN); - strncat(*ppKey, ".", 2); - strncat(*ppKey, ((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN); + TAOS_STRNCAT(*ppKey, pStmtName, TSDB_TABLE_NAME_LEN); + TAOS_STRNCAT(*ppKey, ".", 2); + TAOS_STRNCAT(*ppKey, ((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN); *pLen = taosHashBinary(*ppKey, strlen(*ppKey)); return code; } @@ -95,9 +95,9 @@ static int32_t getSlotKey(SNode* pNode, const char* pStmtName, char** ppKey, int if (!*ppKey) { return terrno; } - strncat(*ppKey, pVal->literal, strlen(pVal->literal)); - strncat(*ppKey, ".", 2); - strncat(*ppKey, ((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN); + TAOS_STRNCAT(*ppKey, pVal->literal, strlen(pVal->literal)); + TAOS_STRNCAT(*ppKey, ".", 2); + TAOS_STRNCAT(*ppKey, ((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN); *pLen = taosHashBinary(*ppKey, strlen(*ppKey)); return code; } @@ -109,9 +109,9 @@ static int32_t getSlotKey(SNode* pNode, const char* pStmtName, char** ppKey, int if (!*ppKey) { return terrno; } - strncat(*ppKey, pStmtName, TSDB_TABLE_NAME_LEN); - strncat(*ppKey, ".", 2); - strncat(*ppKey, ((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN); + TAOS_STRNCAT(*ppKey, pStmtName, TSDB_TABLE_NAME_LEN); + TAOS_STRNCAT(*ppKey, ".", 2); + TAOS_STRNCAT(*ppKey, ((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN); *pLen = taosHashBinary(*ppKey, strlen(*ppKey)); return code; } @@ -120,7 +120,7 @@ static int32_t getSlotKey(SNode* pNode, const char* pStmtName, char** ppKey, int if (!*ppKey) { return terrno; } - strncat(*ppKey, ((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN); + TAOS_STRNCAT(*ppKey, ((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN); *pLen = strlen(*ppKey); return code; } From 888f02f2fa4a33826454e31ad77b792851859d12 Mon Sep 17 00:00:00 2001 From: Yibo Liu Date: Wed, 4 Dec 2024 16:48:53 +0800 Subject: [PATCH 21/62] Update index.mdx --- .../01-components/12-tdinsight/index.mdx | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx index 5c22dbf57a..3d0177807b 100644 --- a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx +++ b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx @@ -163,19 +163,19 @@ TDinsight 仪表盘旨在提供 TDengine 相关资源的使用情况和状态, | 规则名称| 规则阈值| 无监控数据时的行为 | 数据扫描间隔 |持续时间 | 执行SQL | | ------ | --------- | ---------------- | ----------- |------- |----------------------| |dnode 节点的CPU负载|均值 > 80%|触发告警|5分钟|5分钟 |select now(), dnode_id, last(cpu_system) as cup_use from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts < now partition by dnode_id having first(_ts) > 0 | -|dnode 节点的的内存 |均值 > 60%|触发告警|5分钟|5分钟|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 80%|触发告警|5分钟|5分钟|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts = (now- 5m) and _ts = 90%|触发告警|1天|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 100|不触发报警|1分钟|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 300秒|不触发报警|1分钟|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts = (now- 5m) and _ts = (now- 5m) and _ts 0|不触发报警|30秒|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 5|不触发报警|30秒|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 5|不触发报警|30秒|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts = (now- 5m) and _ts last(update_time)|触发告警|90秒|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 60%|触发告警|5分钟|5分钟|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 80%|触发告警|5分钟|5分钟|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts = (now- 5m) and _ts = 90%|触发告警|1天|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 100|不触发报警|1分钟|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 300秒|不触发报警|1分钟|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts = (now- 5m) and _ts = (now- 5m) and _ts 0|不触发报警|30秒|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 5|不触发报警|30秒|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 5|不触发报警|30秒|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts = (now- 5m) and _ts last(update_time)|触发告警|90秒|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts Date: Wed, 4 Dec 2024 16:50:28 +0800 Subject: [PATCH 22/62] Update index.mdx From c06303201822b116e074f6a791b2c40884b806e6 Mon Sep 17 00:00:00 2001 From: Yibo Liu Date: Wed, 4 Dec 2024 16:51:14 +0800 Subject: [PATCH 23/62] Update index.mdx --- docs/zh/14-reference/01-components/12-tdinsight/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx index 3d0177807b..c330c890c0 100644 --- a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx +++ b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx @@ -163,7 +163,7 @@ TDinsight 仪表盘旨在提供 TDengine 相关资源的使用情况和状态, | 规则名称| 规则阈值| 无监控数据时的行为 | 数据扫描间隔 |持续时间 | 执行SQL | | ------ | --------- | ---------------- | ----------- |------- |----------------------| |dnode 节点的CPU负载|均值 > 80%|触发告警|5分钟|5分钟 |select now(), dnode_id, last(cpu_system) as cup_use from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts < now partition by dnode_id having first(_ts) > 0 | -|dnode 节点的的内存 |均值 > 60%|触发告警|5分钟|5分钟|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 60%|触发告警|5分钟|5分钟|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 80%|触发告警|5分钟|5分钟|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts = (now- 5m) and _ts = 90%|触发告警|1天|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts Date: Wed, 4 Dec 2024 16:52:01 +0800 Subject: [PATCH 24/62] Update index.mdx --- docs/zh/14-reference/01-components/12-tdinsight/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx index c330c890c0..3d0177807b 100644 --- a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx +++ b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx @@ -163,7 +163,7 @@ TDinsight 仪表盘旨在提供 TDengine 相关资源的使用情况和状态, | 规则名称| 规则阈值| 无监控数据时的行为 | 数据扫描间隔 |持续时间 | 执行SQL | | ------ | --------- | ---------------- | ----------- |------- |----------------------| |dnode 节点的CPU负载|均值 > 80%|触发告警|5分钟|5分钟 |select now(), dnode_id, last(cpu_system) as cup_use from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts < now partition by dnode_id having first(_ts) > 0 | -|dnode 节点的的内存 |均值 > 60%|触发告警|5分钟|5分钟|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 60%|触发告警|5分钟|5分钟|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 80%|触发告警|5分钟|5分钟|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts = (now- 5m) and _ts = 90%|触发告警|1天|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts Date: Wed, 4 Dec 2024 17:00:50 +0800 Subject: [PATCH 25/62] Update index.mdx --- .../01-components/12-tdinsight/index.mdx | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx index 3d0177807b..9f7f6bafa4 100644 --- a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx +++ b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx @@ -162,20 +162,20 @@ TDinsight 仪表盘旨在提供 TDengine 相关资源的使用情况和状态, | 规则名称| 规则阈值| 无监控数据时的行为 | 数据扫描间隔 |持续时间 | 执行SQL | | ------ | --------- | ---------------- | ----------- |------- |----------------------| -|dnode 节点的CPU负载|均值 > 80%|触发告警|5分钟|5分钟 |select now(), dnode_id, last(cpu_system) as cup_use from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts < now partition by dnode_id having first(_ts) > 0 | -|dnode 节点的的内存 |均值 > 60%|触发告警|5分钟|5分钟|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 80%|触发告警|5分钟|5分钟|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts = (now- 5m) and _ts = 90%|触发告警|1天|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 100|不触发报警|1分钟|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 300秒|不触发报警|1分钟|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts = (now- 5m) and _ts = (now- 5m) and _ts 0|不触发报警|30秒|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 5|不触发报警|30秒|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 5|不触发报警|30秒|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts = (now- 5m) and _ts last(update_time)|触发告警|90秒|0秒|select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 80%|触发告警|5分钟|5分钟 |`select now(), dnode_id, last(cpu_system) as cup_use from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts < now partition by dnode_id having first(_ts) > 0 `| +|dnode 节点的的内存 |均值 > 60%|触发告警|5分钟|5分钟|`select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 80%|触发告警|5分钟|5分钟|`select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts = (now- 5m) and _ts = 90%|触发告警|1天|0秒|`select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 100|不触发报警|1分钟|0秒|`select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 300秒|不触发报警|1分钟|0秒|`select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts = (now- 5m) and _ts = (now- 5m) and _ts 0|不触发报警|30秒|0秒|`select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 5|不触发报警|30秒|0秒|`select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 5|不触发报警|30秒|0秒|`select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts = (now- 5m) and _ts last(update_time)|触发告警|90秒|0秒|`select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts Date: Wed, 4 Dec 2024 22:19:37 +0800 Subject: [PATCH 26/62] fix(stream): fix deadlock when update checkpoint info failed. --- source/libs/stream/src/streamCheckpoint.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/source/libs/stream/src/streamCheckpoint.c b/source/libs/stream/src/streamCheckpoint.c index d619351a93..3ca283ce98 100644 --- a/source/libs/stream/src/streamCheckpoint.c +++ b/source/libs/stream/src/streamCheckpoint.c @@ -634,9 +634,11 @@ int32_t streamTaskUpdateTaskCheckpointInfo(SStreamTask* pTask, bool restored, SV pInfo->processedVer <= pReq->checkpointVer); if (!valid) { - stFatal("invalid checkpoint id check, current checkpointId:%" PRId64 " checkpointVer:%" PRId64 - " processedVer:%" PRId64 " req checkpointId:%" PRId64 " checkpointVer:%" PRId64, - pInfo->checkpointId, pInfo->checkpointVer, pInfo->processedVer, pReq->checkpointId, pReq->checkpointVer); + stFatal("s-task:%s invalid checkpointId update info recv, current checkpointId:%" PRId64 " checkpointVer:%" PRId64 + " processedVer:%" PRId64 " req checkpointId:%" PRId64 " checkpointVer:%" PRId64 " discard it", + id, pInfo->checkpointId, pInfo->checkpointVer, pInfo->processedVer, pReq->checkpointId, + pReq->checkpointVer); + streamMutexUnlock(&pTask->lock); return TSDB_CODE_STREAM_INTERNAL_ERROR; } From b6aa299a3ce652bdf0428418846e01d94290a22c Mon Sep 17 00:00:00 2001 From: 54liuyao <54liuyao@163.com> Date: Thu, 5 Dec 2024 08:57:12 +0800 Subject: [PATCH 27/62] opt stream build twa result --- .../src/streamintervalsliceoperator.c | 70 ++++++++++++------- source/libs/stream/src/tstreamFileState.c | 4 ++ .../tsim/stream/streamTwaFwcInterval.sim | 58 +++++++++++++++ 3 files changed, 108 insertions(+), 24 deletions(-) diff --git a/source/libs/executor/src/streamintervalsliceoperator.c b/source/libs/executor/src/streamintervalsliceoperator.c index e7a9c58710..86dc7649c4 100644 --- a/source/libs/executor/src/streamintervalsliceoperator.c +++ b/source/libs/executor/src/streamintervalsliceoperator.c @@ -120,6 +120,36 @@ void initIntervalSlicePoint(SStreamAggSupporter* pAggSup, STimeWindow* pTWin, in pPoint->pLastRow = POINTER_SHIFT(pPoint->pFinished, sizeof(bool)); } +int32_t getIntervalSlicePrevStateBuf(SStreamAggSupporter* pAggSup, SInterval* pInterval, SWinKey* pCurKey, + SInervalSlicePoint* pPrevPoint) { + int32_t code = TSDB_CODE_SUCCESS; + int32_t lino = 0; + SWinKey prevKey = {.groupId = pCurKey->groupId}; + SET_WIN_KEY_INVALID(prevKey.ts); + int32_t prevVLen = 0; + int32_t prevWinCode = TSDB_CODE_SUCCESS; + code = pAggSup->stateStore.streamStateGetPrev(pAggSup->pState, pCurKey, &prevKey, (void**)&pPrevPoint->pResPos, + &prevVLen, &prevWinCode); + QUERY_CHECK_CODE(code, lino, _end); + + if (prevWinCode == TSDB_CODE_SUCCESS) { + STimeWindow prevSTW = {.skey = prevKey.ts}; + prevSTW.ekey = taosTimeGetIntervalEnd(prevSTW.skey, pInterval); + initIntervalSlicePoint(pAggSup, &prevSTW, pCurKey->groupId, pPrevPoint); + qDebug("===stream=== set stream twa prev point buf.ts:%" PRId64 ", groupId:%" PRIu64 ", res:%d", + pPrevPoint->winKey.win.skey, pPrevPoint->winKey.groupId, prevWinCode); + } else { + SET_WIN_KEY_INVALID(pPrevPoint->winKey.win.skey); + SET_WIN_KEY_INVALID(pPrevPoint->winKey.win.ekey); + } + +_end: + if (code != TSDB_CODE_SUCCESS) { + qError("%s failed at line %d since %s", __func__, lino, tstrerror(code)); + } + return code; +} + static int32_t getIntervalSliceCurStateBuf(SStreamAggSupporter* pAggSup, SInterval* pInterval, bool needPrev, STimeWindow* pTWin, int64_t groupId, SInervalSlicePoint* pCurPoint, SInervalSlicePoint* pPrevPoint, int32_t* pWinCode) { int32_t code = TSDB_CODE_SUCCESS; @@ -136,24 +166,8 @@ static int32_t getIntervalSliceCurStateBuf(SStreamAggSupporter* pAggSup, SInterv initIntervalSlicePoint(pAggSup, pTWin, groupId, pCurPoint); if (needPrev) { - SWinKey prevKey = {.groupId = groupId}; - SET_WIN_KEY_INVALID(prevKey.ts); - int32_t prevVLen = 0; - int32_t prevWinCode = TSDB_CODE_SUCCESS; - code = pAggSup->stateStore.streamStateGetPrev(pAggSup->pState, &curKey, &prevKey, (void**)&pPrevPoint->pResPos, - &prevVLen, &prevWinCode); + code = getIntervalSlicePrevStateBuf(pAggSup, pInterval, &curKey, pPrevPoint); QUERY_CHECK_CODE(code, lino, _end); - - if (prevWinCode == TSDB_CODE_SUCCESS) { - STimeWindow prevSTW = {.skey = prevKey.ts}; - prevSTW.ekey = taosTimeGetIntervalEnd(prevSTW.skey, pInterval); - initIntervalSlicePoint(pAggSup, &prevSTW, groupId, pPrevPoint); - qDebug("===stream=== set stream twa prev point buf.ts:%" PRId64 ", groupId:%" PRIu64 ", res:%d", pPrevPoint->winKey.win.skey, - pPrevPoint->winKey.groupId, prevWinCode); - } else { - SET_WIN_KEY_INVALID(pPrevPoint->winKey.win.skey); - SET_WIN_KEY_INVALID(pPrevPoint->winKey.win.ekey); - } } _end: @@ -265,13 +279,15 @@ static int32_t doStreamIntervalSliceAggImpl(SOperatorInfo* pOperator, SSDataBloc STimeWindow curWin = getActiveTimeWindow(NULL, pResultRowInfo, curTs, &pInfo->interval, TSDB_ORDER_ASC); while (1) { - if (curTs > pInfo->endTs) { - break; - } - int32_t winCode = TSDB_CODE_SUCCESS; - code = getIntervalSliceCurStateBuf(&pInfo->streamAggSup, &pInfo->interval, pInfo->hasInterpoFunc, &curWin, groupId, &curPoint, &prevPoint, &winCode); - QUERY_CHECK_CODE(code, lino, _end); + if (curTs <= pInfo->endTs) { + code = getIntervalSliceCurStateBuf(&pInfo->streamAggSup, &pInfo->interval, pInfo->hasInterpoFunc, &curWin, groupId, &curPoint, &prevPoint, &winCode); + QUERY_CHECK_CODE(code, lino, _end); + } else if (pInfo->hasInterpoFunc) { + SWinKey curKey = {.ts = curWin.skey, .groupId = groupId}; + code = getIntervalSlicePrevStateBuf(&pInfo->streamAggSup, &pInfo->interval, &curKey, &prevPoint); + QUERY_CHECK_CODE(code, lino, _end); + } if (pInfo->hasInterpoFunc && IS_VALID_WIN_KEY(prevPoint.winKey.win.skey) && isInterpoWindowFinished(&prevPoint) == false) { code = setIntervalSliceOutputBuf(&prevPoint, pSup->pCtx, numOfOutput, pSup->rowEntryInfoOffset); @@ -288,6 +304,12 @@ static int32_t doStreamIntervalSliceAggImpl(SOperatorInfo* pOperator, SSDataBloc code = saveWinResult(&prevKey, prevPoint.pResPos, pInfo->pUpdatedMap); QUERY_CHECK_CODE(code, lino, _end); setInterpoWindowFinished(&prevPoint); + } else if (IS_VALID_WIN_KEY(prevPoint.winKey.win.skey)) { + releaseOutputBuf(pInfo->streamAggSup.pState, prevPoint.pResPos, &pInfo->streamAggSup.stateStore); + } + + if (curTs > pInfo->endTs) { + break; } code = setIntervalSliceOutputBuf(&curPoint, pSup->pCtx, numOfOutput, pSup->rowEntryInfoOffset); @@ -300,7 +322,7 @@ static int32_t doStreamIntervalSliceAggImpl(SOperatorInfo* pOperator, SSDataBloc forwardRows = getNumOfRowsInTimeWindow(&pBlock->info, tsCols, startPos, curWin.ekey, binarySearchForKey, NULL, TSDB_ORDER_ASC); int32_t prevEndPos = (forwardRows - 1) + startPos; - if (pInfo->hasInterpoFunc && winCode != TSDB_CODE_SUCCESS) { + if (pInfo->hasInterpoFunc) { int32_t endRowId = getQualifiedRowNumDesc(pSup, pBlock, tsCols, prevEndPos, false); TSKEY endRowTs = tsCols[endRowId]; transBlockToSliceResultRow(pBlock, endRowId, endRowTs, curPoint.pLastRow, 0, NULL, NULL, pInfo->pOffsetInfo); diff --git a/source/libs/stream/src/tstreamFileState.c b/source/libs/stream/src/tstreamFileState.c index 592523e70b..05edad0f5f 100644 --- a/source/libs/stream/src/tstreamFileState.c +++ b/source/libs/stream/src/tstreamFileState.c @@ -947,6 +947,7 @@ int32_t recoverSession(SStreamFileState* pFileState, int64_t ckId) { } SRowBuffPos* pPos = createSessionWinBuff(pFileState, &key, pVal, &vlen); + pPos->beUsed = false; winRes = putSessionWinResultBuff(pFileState, pPos); if (winRes != TSDB_CODE_SUCCESS) { break; @@ -1008,6 +1009,7 @@ int32_t recoverSnapshot(SStreamFileState* pFileState, int64_t ckId) { memcpy(pNewPos->pRowBuff, pVal, vlen); taosMemoryFreeClear(pVal); pNewPos->beFlushed = true; + pNewPos->beUsed = false; qDebug("===stream=== read checkpoint state from disc. %s", __func__); code = tSimpleHashPut(pFileState->rowStateBuff, pNewPos->pKey, pFileState->keyLen, &pNewPos, POINTER_BYTES); if (code != TSDB_CODE_SUCCESS) { @@ -1090,6 +1092,7 @@ int32_t recoverFillSnapshot(SStreamFileState* pFileState, int64_t ckId) { if (vlen != pFileState->rowSize) { qError("row size mismatch, expect:%d, actual:%d", pFileState->rowSize, vlen); + destroyRowBuffPos(pNewPos); code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR; taosMemoryFreeClear(pVal); QUERY_CHECK_CODE(code, lino, _end); @@ -1098,6 +1101,7 @@ int32_t recoverFillSnapshot(SStreamFileState* pFileState, int64_t ckId) { memcpy(pNewPos->pRowBuff, pVal, vlen); taosMemoryFreeClear(pVal); pNewPos->beFlushed = true; + pNewPos->beUsed = false; qDebug("===stream=== read checkpoint state from disc. %s", __func__); winRes = tSimpleHashPut(pFileState->rowStateBuff, pNewPos->pKey, pFileState->keyLen, &pNewPos, POINTER_BYTES); if (winRes != TSDB_CODE_SUCCESS) { diff --git a/tests/script/tsim/stream/streamTwaFwcInterval.sim b/tests/script/tsim/stream/streamTwaFwcInterval.sim index 8640650310..5151d7caff 100644 --- a/tests/script/tsim/stream/streamTwaFwcInterval.sim +++ b/tests/script/tsim/stream/streamTwaFwcInterval.sim @@ -289,6 +289,64 @@ if $data51 != $query1_data51 then goto loop3 endi +print ======step3 +sql create database test3 vgroups 1; +sql use test3; + +sql create stable st(ts timestamp, a int, b int , c int)tags(ta int,tb int,tc int); +sql create table t1 using st tags(1,1,1); +sql create table t2 using st tags(2,2,2); + +sql create stream streams3 trigger force_window_close IGNORE EXPIRED 1 IGNORE UPDATE 1 into streamt3 as select _wstart, twa(a), ta from st partition by tbname,ta interval(10s); + +run tsim/stream/checkTaskStatus.sim + +sql insert into t1 values(now + 3000a,1,1,1); +sql flush database test; +sql insert into t1 values(now + 3001a,10,10,10); +sql insert into t1 values(now + 13s,50,50,50); + +sleep 1000 + +print sql select _wstart, twa(a), ta from st partition by tbname,ta interval(10s) order by 1; +sql select _wstart, twa(a), ta from st partition by tbname,ta interval(10s) order by 1; + +$query_data01 = $data01 + +print $data00 $data01 $data02 $data03 $data04 +print $data10 $data11 $data12 $data13 $data14 +print $data20 $data21 $data22 $data23 $data24 +print $data30 $data31 $data32 $data33 $data34 +print $data40 $data41 $data42 $data43 $data44 +print $data50 $data51 $data52 $data53 $data54 + + +$loop_count = 0 +loop4: + +sleep 2000 + +$loop_count = $loop_count + 1 +if $loop_count == 20 then + return -1 +endi + +print 2 sql select * from streamt3 order by 1; +sql select * from streamt3 order by 1; + +print $data00 $data01 $data02 $data03 $data04 +print $data10 $data11 $data12 $data13 $data14 +print $data20 $data21 $data22 $data23 $data24 +print $data30 $data31 $data32 $data33 $data34 +print $data40 $data41 $data42 $data43 $data44 +print $data50 $data51 $data52 $data53 $data54 + +if $data01 != $query_data01 then + print ======data01======$data01 + print ====query_data01=$query_data01 + goto loop4 +endi + print end system sh/exec.sh -n dnode1 -s stop -x SIGINT From af3423b714c1d182f04d1c14b6c58a51ebbc6279 Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Thu, 5 Dec 2024 09:32:42 +0800 Subject: [PATCH 28/62] fix(stream): fix a deadlock in update checkpoint info in case of failed. --- source/libs/stream/src/streamCheckpoint.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/source/libs/stream/src/streamCheckpoint.c b/source/libs/stream/src/streamCheckpoint.c index d619351a93..3ca283ce98 100644 --- a/source/libs/stream/src/streamCheckpoint.c +++ b/source/libs/stream/src/streamCheckpoint.c @@ -634,9 +634,11 @@ int32_t streamTaskUpdateTaskCheckpointInfo(SStreamTask* pTask, bool restored, SV pInfo->processedVer <= pReq->checkpointVer); if (!valid) { - stFatal("invalid checkpoint id check, current checkpointId:%" PRId64 " checkpointVer:%" PRId64 - " processedVer:%" PRId64 " req checkpointId:%" PRId64 " checkpointVer:%" PRId64, - pInfo->checkpointId, pInfo->checkpointVer, pInfo->processedVer, pReq->checkpointId, pReq->checkpointVer); + stFatal("s-task:%s invalid checkpointId update info recv, current checkpointId:%" PRId64 " checkpointVer:%" PRId64 + " processedVer:%" PRId64 " req checkpointId:%" PRId64 " checkpointVer:%" PRId64 " discard it", + id, pInfo->checkpointId, pInfo->checkpointVer, pInfo->processedVer, pReq->checkpointId, + pReq->checkpointVer); + streamMutexUnlock(&pTask->lock); return TSDB_CODE_STREAM_INTERNAL_ERROR; } From c8d418d93a099994e6767628729aced2ef31c485 Mon Sep 17 00:00:00 2001 From: Yibo Liu Date: Thu, 5 Dec 2024 09:55:21 +0800 Subject: [PATCH 29/62] Update index.mdx --- .../01-components/12-tdinsight/index.mdx | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx index 9f7f6bafa4..649396e499 100644 --- a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx +++ b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx @@ -148,8 +148,8 @@ TDinsight 仪表盘旨在提供 TDengine 相关资源的使用情况和状态, ### 预配置告警规则自动导入 涛思总结用户使用经验,整理出14个常用的告警规则(alert rule),能够对集群关键指标进行监测并及时上报指标异常、超限等告警信息。 -从TDengine-server 3.3.4.3版本(tdengine-datasource 3.6.3)开始,TDengine Datasource 支持预配置告警规则自动导入功能,用户可将14个告警规则一键导入Grafana,直接使用。 -预配置告警规则导入方法如下图所示,在tdengine-datasource setting界面,打开Load TDengine Alert开关,即可导入所有预配置告警规则;如不需要,点击Clear TDengine Alert按钮即可删除所有预配置告警规则。 +从TDengine-server 3.3.4.3版本(tdengine-datasource 3.6.3)开始,TDengine Datasource 支持预配置告警规则自动导入功能,用户可将14个告警规则一键导入Grafana(11.x版本),直接使用。 +预配置告警规则导入方法如下图所示,在tdengine-datasource setting界面,打开 “Load Tengine Alert” 开关,点击 “Save & test” 按钮后,插件会自动加载上述告警规则, 规则会放入以数据源名称 + “-alert” 的 grafana 告警目录中。如不需要,关闭Load TDengine Alert开关。点击 “Clear TDengine Alert” 旁边的按钮则会清除此数据源导入的所有告警。 ![TDengine Alert](./assets/TDengine-Alert.webp) @@ -164,18 +164,18 @@ TDinsight 仪表盘旨在提供 TDengine 相关资源的使用情况和状态, | ------ | --------- | ---------------- | ----------- |------- |----------------------| |dnode 节点的CPU负载|均值 > 80%|触发告警|5分钟|5分钟 |`select now(), dnode_id, last(cpu_system) as cup_use from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts < now partition by dnode_id having first(_ts) > 0 `| |dnode 节点的的内存 |均值 > 60%|触发告警|5分钟|5分钟|`select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 80%|触发告警|5分钟|5分钟|`select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts = (now- 5m) and _ts = 90%|触发告警|1天|0秒|`select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 100|不触发报警|1分钟|0秒|`select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 300秒|不触发报警|1分钟|0秒|`select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts = (now- 5m) and _ts = (now- 5m) and _ts 0|不触发报警|30秒|0秒|`select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 5|不触发报警|30秒|0秒|`select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 5|不触发报警|30秒|0秒|`select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts = (now- 5m) and _ts last(update_time)|触发告警|90秒|0秒|`select now(), dnode_id, last(mem_engine) / last(mem_total) * 100 as taosd from log.taosd_dnodes_info where _ts >= (now- 5m) and _ts 80%|触发告警|5分钟|5分钟|`select now(), dnode_id, data_dir_level, data_dir_name, last(used) / last(total) * 100 as used from log.taosd_dnodes_data_dirs where _ts >= (now - 5m) and _ts < now partition by dnode_id, data_dir_level, data_dir_name`| +|集群授权到期 |< 60天|触发告警|1天|0秒|`select now(), cluster_id, last(grants_expire_time) / 86400 as expire_time from log.taosd_cluster_info where _ts >= (now - 24h) and _ts < now partition by cluster_id having first(_ts) > 0 `| +|测点数达到授权测点数|>= 90%|触发告警|1天|0秒|`select now(), cluster_id, CASE WHEN max(grants_timeseries_total) > 0.0 THEN max(grants_timeseries_used) /max(grants_timeseries_total) * 100.0 ELSE 0.0 END AS result from log.taosd_cluster_info where _ts >= (now - 30s) and _ts < now partition by cluster_id having timetruncate(first(_ts), 1m) > 0`| +|查询并发请求数 | > 100|不触发报警|1分钟|0秒|`select now() as ts, count(*) as slow_count from performance_schema.perf_queries`| +|慢查询执行最长时间 (无时间窗口) |> 300秒|不触发报警|1分钟|0秒|`select now() as ts, count(*) as slow_count from performance_schema.perf_queries where exec_usec>300000000`| +|dnode下线 |total != alive|触发告警|30秒|0秒|`select now(), cluster_id, last(dnodes_total) - last(dnodes_alive) as dnode_offline from log.taosd_cluster_info where _ts >= (now -30s) and _ts < now partition by cluster_id having first(_ts) > 0`| +|vnode下线 |total != alive|触发告警|30秒|0秒|`select now(), cluster_id, last(vnodes_total) - last(vnodes_alive) as vnode_offline from log.taosd_cluster_info where _ts >= (now - 30s) and _ts < now partition by cluster_id having first(_ts) > 0 `| +|数据删除请求数 |> 0|不触发报警|30秒|0秒|`select now(), count(`count`) as `delete_count` from log.taos_sql_req where sql_type = 'delete' and _ts >= (now -30s) and _ts < now`| +|Adapter RESTful 请求失败 |> 5|不触发报警|30秒|0秒|`select now(), sum(`fail`) as `Failed` from log.adapter_requests where req_type=0 and ts >= (now -30s) and ts < now;`| +|Adapter WebSocket 请求失败 |> 5|不触发报警|30秒|0秒|`select now(), sum(`fail`) as `Failed` from log.adapter_requests where req_type=1 and ts >= (now -30s) and ts < now`| +|dnode 数据上报缺少 |< 3|触发告警|180秒|0秒|`select now(), cluster_id, count(*) as dnode_report from log.taosd_cluster_info where _ts >= (now -180s) and _ts < now partition by cluster_id having timetruncate(first(_ts), 1h) > 0`| +|dnode 重启 |max(update_time) > last(update_time)|触发告警|90秒|0秒|`select now(), dnode_id, max(uptime) - last(uptime) as dnode_restart from log.taosd_dnodes_info where _ts >= (now - 90s) and _ts < now partition by dnode_id`| 用户可参考上述告警规则,根据自己业务需求进行修改与完善。 Grafana7.5及以下版本,Dashboards与Alert rules功能合在一起,而之后的新版本两个功能是分开的。为兼容Grafana7.5及以下版本,TDinsight面板中增加了Alert Used Only面板,仅Grafana7.5及以下版本需要使用。 From 082b172738090c0abd09bcaf2f91352ce7ce9dd6 Mon Sep 17 00:00:00 2001 From: Yibo Liu Date: Thu, 5 Dec 2024 10:17:28 +0800 Subject: [PATCH 30/62] Update index.mdx --- docs/zh/14-reference/01-components/12-tdinsight/index.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx index 649396e499..db8cdd73c1 100644 --- a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx +++ b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx @@ -149,7 +149,7 @@ TDinsight 仪表盘旨在提供 TDengine 相关资源的使用情况和状态, 涛思总结用户使用经验,整理出14个常用的告警规则(alert rule),能够对集群关键指标进行监测并及时上报指标异常、超限等告警信息。 从TDengine-server 3.3.4.3版本(tdengine-datasource 3.6.3)开始,TDengine Datasource 支持预配置告警规则自动导入功能,用户可将14个告警规则一键导入Grafana(11.x版本),直接使用。 -预配置告警规则导入方法如下图所示,在tdengine-datasource setting界面,打开 “Load Tengine Alert” 开关,点击 “Save & test” 按钮后,插件会自动加载上述告警规则, 规则会放入以数据源名称 + “-alert” 的 grafana 告警目录中。如不需要,关闭Load TDengine Alert开关。点击 “Clear TDengine Alert” 旁边的按钮则会清除此数据源导入的所有告警。 +预配置告警规则导入方法如下图所示,在tdengine-datasource setting界面,打开 “Load Tengine Alert” 开关,点击 “Save & test” 按钮后,插件会自动加载上述告警规则, 规则会放入以数据源名称 + “-alert” 的 grafana 告警目录中。如不需要,关闭Load TDengine Alert开关。点击 “Clear TDengine Alert” 旁边的按钮则会清除此数据源已导入的所有告警规则。 ![TDengine Alert](./assets/TDengine-Alert.webp) @@ -171,9 +171,9 @@ TDinsight 仪表盘旨在提供 TDengine 相关资源的使用情况和状态, |慢查询执行最长时间 (无时间窗口) |> 300秒|不触发报警|1分钟|0秒|`select now() as ts, count(*) as slow_count from performance_schema.perf_queries where exec_usec>300000000`| |dnode下线 |total != alive|触发告警|30秒|0秒|`select now(), cluster_id, last(dnodes_total) - last(dnodes_alive) as dnode_offline from log.taosd_cluster_info where _ts >= (now -30s) and _ts < now partition by cluster_id having first(_ts) > 0`| |vnode下线 |total != alive|触发告警|30秒|0秒|`select now(), cluster_id, last(vnodes_total) - last(vnodes_alive) as vnode_offline from log.taosd_cluster_info where _ts >= (now - 30s) and _ts < now partition by cluster_id having first(_ts) > 0 `| -|数据删除请求数 |> 0|不触发报警|30秒|0秒|`select now(), count(`count`) as `delete_count` from log.taos_sql_req where sql_type = 'delete' and _ts >= (now -30s) and _ts < now`| -|Adapter RESTful 请求失败 |> 5|不触发报警|30秒|0秒|`select now(), sum(`fail`) as `Failed` from log.adapter_requests where req_type=0 and ts >= (now -30s) and ts < now;`| -|Adapter WebSocket 请求失败 |> 5|不触发报警|30秒|0秒|`select now(), sum(`fail`) as `Failed` from log.adapter_requests where req_type=1 and ts >= (now -30s) and ts < now`| +|数据删除请求数 |> 0|不触发报警|30秒|0秒|``select now(), count(`count`) as `delete_count` from log.taos_sql_req where sql_type = 'delete' and _ts >= (now -30s) and _ts < now``| +|Adapter RESTful 请求失败 |> 5|不触发报警|30秒|0秒|``select now(), sum(`fail`) as `Failed` from log.adapter_requests where req_type=0 and ts >= (now -30s) and ts < now``| +|Adapter WebSocket 请求失败 |> 5|不触发报警|30秒|0秒|``select now(), sum(`fail`) as `Failed` from log.adapter_requests where req_type=1 and ts >= (now -30s) and ts < now``| |dnode 数据上报缺少 |< 3|触发告警|180秒|0秒|`select now(), cluster_id, count(*) as dnode_report from log.taosd_cluster_info where _ts >= (now -180s) and _ts < now partition by cluster_id having timetruncate(first(_ts), 1h) > 0`| |dnode 重启 |max(update_time) > last(update_time)|触发告警|90秒|0秒|`select now(), dnode_id, max(uptime) - last(uptime) as dnode_restart from log.taosd_dnodes_info where _ts >= (now - 90s) and _ts < now partition by dnode_id`| From f30acae2c60dd366cfb0df1402da985e9c75d798 Mon Sep 17 00:00:00 2001 From: Yibo Liu Date: Thu, 5 Dec 2024 11:27:08 +0800 Subject: [PATCH 31/62] Update index.mdx --- docs/zh/14-reference/01-components/12-tdinsight/index.mdx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx index db8cdd73c1..615378a28f 100644 --- a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx +++ b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx @@ -193,10 +193,11 @@ Grafana7.5及以下版本,Dashboards与Alert rules功能合在一起,而之 针对不同的安装方式,卸载时: - 用图形界面,在 ”TDengine Datasource“ 插件页面点击 ”Uninstall“ 卸载。 - 通过 `TDinsight.sh` 脚本安装的 TDinsight,可以使用命令行 `TDinsight.sh -R` 清理相关资源。 -- 手动安装的 TDinsight,要完全卸载,需要清理以下内容: +- 手动安装的 TDinsight,要完全卸载,需要按照顺序清理以下内容: 1. Grafana 中的 TDinsight Dashboard。 - 2. Grafana 中的 Data Source 数据源。 - 3. 从插件安装目录删除 `tdengine-datasource` 插件。 + 2. Grafana 中的 Alert rules 告警规则。 + 3. Grafana 中的 Data Source 数据源。 + 4. 从插件安装目录删除 `tdengine-datasource` 插件。 ## 附录 From 302758db1b0dc7ffe42847f2870efed52d7994f4 Mon Sep 17 00:00:00 2001 From: dmchen Date: Thu, 5 Dec 2024 17:08:18 +0800 Subject: [PATCH 32/62] fix/skip-trim-during-restore --- source/dnode/vnode/src/vnd/vnodeSvr.c | 5 +++++ source/libs/sync/src/syncMain.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/source/dnode/vnode/src/vnd/vnodeSvr.c b/source/dnode/vnode/src/vnd/vnodeSvr.c index 328c2c1585..d15bc68832 100644 --- a/source/dnode/vnode/src/vnd/vnodeSvr.c +++ b/source/dnode/vnode/src/vnd/vnodeSvr.c @@ -977,6 +977,11 @@ void vnodeUpdateMetaRsp(SVnode *pVnode, STableMetaRsp *pMetaRsp) { extern int32_t vnodeAsyncRetention(SVnode *pVnode, int64_t now); static int32_t vnodeProcessTrimReq(SVnode *pVnode, int64_t ver, void *pReq, int32_t len, SRpcMsg *pRsp) { + if (!pVnode->restored) { + vInfo("vgId:%d, ignore trim req during restoring. ver:%" PRId64, TD_VID(pVnode), ver); + return 0; + } + int32_t code = 0; SVTrimDbReq trimReq = {0}; diff --git a/source/libs/sync/src/syncMain.c b/source/libs/sync/src/syncMain.c index 0fe074084f..5ae5a47e3c 100644 --- a/source/libs/sync/src/syncMain.c +++ b/source/libs/sync/src/syncMain.c @@ -1464,7 +1464,7 @@ int32_t syncNodeRestore(SSyncNode* pSyncNode) { // if (endIndex != lastVer + 1) return TSDB_CODE_SYN_INTERNAL_ERROR; pSyncNode->commitIndex = TMAX(pSyncNode->commitIndex, commitIndex); - sInfo("vgId:%d, restore sync until commitIndex:%" PRId64, pSyncNode->vgId, pSyncNode->commitIndex); + sInfo("vgId:%d, start to restore sync until commitIndex:%" PRId64, pSyncNode->vgId, pSyncNode->commitIndex); if (pSyncNode->fsmState != SYNC_FSM_STATE_INCOMPLETE && (code = syncLogBufferCommit(pSyncNode->pLogBuf, pSyncNode, pSyncNode->commitIndex)) < 0) { From 406e8777005e02a38b330e15fa818f192cba0998 Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Fri, 6 Dec 2024 00:11:51 +0800 Subject: [PATCH 33/62] fix(stream): send chkpt-source rsp to mnd even if it is failed. --- source/dnode/vnode/src/tq/tq.c | 116 ++++++++++++--------------------- 1 file changed, 41 insertions(+), 75 deletions(-) diff --git a/source/dnode/vnode/src/tq/tq.c b/source/dnode/vnode/src/tq/tq.c index bd78f62cae..937bc6e268 100644 --- a/source/dnode/vnode/src/tq/tq.c +++ b/source/dnode/vnode/src/tq/tq.c @@ -1108,91 +1108,76 @@ _OVER: return code; } +// always return success to mnode +//todo: handle failure of build and send msg to mnode +static void doSendChkptSourceRsp(SStreamCheckpointSourceReq* pReq, SRpcHandleInfo* pRpcInfo, int32_t code, + int32_t taskId) { + SRpcMsg rsp = {0}; + int32_t ret = streamTaskBuildCheckpointSourceRsp(pReq, pRpcInfo, &rsp, code); + if (ret) { // suppress the error in build checkpoint source rsp + tqError("s-task:0x%x failed to build checkpoint-source rsp, code:%s", taskId, tstrerror(ret)); + } + tmsgSendRsp(&rsp); // error occurs +} + // no matter what kinds of error happened, make sure the mnode will receive the success execution code. int32_t tqProcessTaskCheckPointSourceReq(STQ* pTq, SRpcMsg* pMsg, SRpcMsg* pRsp) { - int32_t vgId = TD_VID(pTq->pVnode); - SStreamMeta* pMeta = pTq->pStreamMeta; - char* msg = POINTER_SHIFT(pMsg->pCont, sizeof(SMsgHead)); - int32_t len = pMsg->contLen - sizeof(SMsgHead); - int32_t code = 0; + int32_t vgId = TD_VID(pTq->pVnode); + SStreamMeta* pMeta = pTq->pStreamMeta; + char* msg = POINTER_SHIFT(pMsg->pCont, sizeof(SMsgHead)); + int32_t len = pMsg->contLen - sizeof(SMsgHead); + int32_t code = 0; + SStreamCheckpointSourceReq req = {0}; + SDecoder decoder = {0}; + SStreamTask* pTask = NULL; + int64_t checkpointId = 0; // disable auto rsp to mnode pRsp->info.handle = NULL; - SStreamCheckpointSourceReq req = {0}; - SDecoder decoder; tDecoderInit(&decoder, (uint8_t*)msg, len); if (tDecodeStreamCheckpointSourceReq(&decoder, &req) < 0) { code = TSDB_CODE_MSG_DECODE_ERROR; tDecoderClear(&decoder); tqError("vgId:%d failed to decode checkpoint-source msg, code:%s", vgId, tstrerror(code)); - - SRpcMsg rsp = {0}; - int32_t ret = streamTaskBuildCheckpointSourceRsp(&req, &pMsg->info, &rsp, TSDB_CODE_SUCCESS); - if (ret) { // suppress the error in build checkpointsource rsp - tqError("s-task:0x%x failed to build checkpoint-source rsp, code:%s", req.taskId, tstrerror(code)); - } - - tmsgSendRsp(&rsp); // error occurs - return TSDB_CODE_SUCCESS; // always return success to mnode, todo: handle failure of build and send msg to mnode + doSendChkptSourceRsp(&req, &pMsg->info, TSDB_CODE_SUCCESS, req.taskId); + return TSDB_CODE_SUCCESS; // always return success to mnode, } + tDecoderClear(&decoder); if (!vnodeIsRoleLeader(pTq->pVnode)) { tqDebug("vgId:%d not leader, ignore checkpoint-source msg, s-task:0x%x", vgId, req.taskId); - SRpcMsg rsp = {0}; - int32_t ret = streamTaskBuildCheckpointSourceRsp(&req, &pMsg->info, &rsp, TSDB_CODE_SUCCESS); - if (ret) { // suppress the error in build checkpointsource rsp - tqError("s-task:0x%x failed to build checkpoint-source rsp, code:%s", req.taskId, tstrerror(code)); - } - - tmsgSendRsp(&rsp); // error occurs - return TSDB_CODE_SUCCESS; // always return success to mnode, todo: handle failure of build and send msg to mnode + doSendChkptSourceRsp(&req, &pMsg->info, TSDB_CODE_SUCCESS, req.taskId); + return TSDB_CODE_SUCCESS; // always return success to mnode } if (!pTq->pVnode->restored) { tqDebug("vgId:%d checkpoint-source msg received during restoring, checkpointId:%" PRId64 ", transId:%d s-task:0x%x ignore it", vgId, req.checkpointId, req.transId, req.taskId); - SRpcMsg rsp = {0}; - int32_t ret = streamTaskBuildCheckpointSourceRsp(&req, &pMsg->info, &rsp, TSDB_CODE_SUCCESS); - if (ret) { // suppress the error in build checkpointsource rsp - tqError("s-task:0x%x failed to build checkpoint-source rsp, code:%s", req.taskId, tstrerror(code)); - } - - tmsgSendRsp(&rsp); // error occurs - return TSDB_CODE_SUCCESS; // always return success to mnode, , todo: handle failure of build and send msg to mnode + doSendChkptSourceRsp(&req, &pMsg->info, TSDB_CODE_SUCCESS, req.taskId); + return TSDB_CODE_SUCCESS; // always return success to mnode } - SStreamTask* pTask = NULL; code = streamMetaAcquireTask(pMeta, req.streamId, req.taskId, &pTask); if (pTask == NULL || code != 0) { tqError("vgId:%d failed to find s-task:0x%x, ignore checkpoint msg. checkpointId:%" PRId64 " transId:%d it may have been destroyed", vgId, req.taskId, req.checkpointId, req.transId); - SRpcMsg rsp = {0}; - int32_t ret = streamTaskBuildCheckpointSourceRsp(&req, &pMsg->info, &rsp, TSDB_CODE_SUCCESS); - if (ret) { // suppress the error in build checkpointsource rsp - tqError("s-task:%s failed to build checkpoint-source rsp, code:%s", pTask->id.idStr, tstrerror(code)); - } - tmsgSendRsp(&rsp); // error occurs + doSendChkptSourceRsp(&req, &pMsg->info, TSDB_CODE_SUCCESS, req.taskId); return TSDB_CODE_SUCCESS; } if (pTask->status.downstreamReady != 1) { - streamTaskSetFailedChkptInfo(pTask, req.transId, req.checkpointId); // record the latest failed checkpoint id + // record the latest failed checkpoint id + streamTaskSetFailedChkptInfo(pTask, req.transId, req.checkpointId); tqError("s-task:%s not ready for checkpoint, since downstream not ready, ignore this checkpointId:%" PRId64 ", transId:%d set it failed", pTask->id.idStr, req.checkpointId, req.transId); + streamMetaReleaseTask(pMeta, pTask); - - SRpcMsg rsp = {0}; - int32_t ret = streamTaskBuildCheckpointSourceRsp(&req, &pMsg->info, &rsp, TSDB_CODE_SUCCESS); - if (ret) { // suppress the error in build checkpointsource rsp - tqError("s-task:%s failed to build checkpoint-source rsp, code:%s", pTask->id.idStr, tstrerror(code)); - } - - tmsgSendRsp(&rsp); // error occurs + doSendChkptSourceRsp(&req, &pMsg->info, TSDB_CODE_SUCCESS, req.taskId); return TSDB_CODE_SUCCESS; // todo retry handle error } @@ -1207,14 +1192,7 @@ int32_t tqProcessTaskCheckPointSourceReq(STQ* pTq, SRpcMsg* pMsg, SRpcMsg* pRsp) streamMutexUnlock(&pTask->lock); streamMetaReleaseTask(pMeta, pTask); - - SRpcMsg rsp = {0}; - int32_t ret = streamTaskBuildCheckpointSourceRsp(&req, &pMsg->info, &rsp, TSDB_CODE_SUCCESS); - if (ret) { // suppress the error in build checkpointsource rsp - tqError("s-task:%s failed to build checkpoint-source rsp, code:%s", pTask->id.idStr, tstrerror(code)); - } - - tmsgSendRsp(&rsp); // error occurs + doSendChkptSourceRsp(&req, &pMsg->info, TSDB_CODE_SUCCESS, req.taskId); return TSDB_CODE_SUCCESS; } } else { @@ -1226,7 +1204,6 @@ int32_t tqProcessTaskCheckPointSourceReq(STQ* pTq, SRpcMsg* pMsg, SRpcMsg* pRsp) // check if the checkpoint msg already sent or not. if (status == TASK_STATUS__CK) { - int64_t checkpointId = 0; streamTaskGetActiveCheckpointInfo(pTask, NULL, &checkpointId); tqWarn("s-task:%s repeatly recv checkpoint-source msg checkpointId:%" PRId64 @@ -1235,7 +1212,7 @@ int32_t tqProcessTaskCheckPointSourceReq(STQ* pTq, SRpcMsg* pMsg, SRpcMsg* pRsp) streamMutexUnlock(&pTask->lock); streamMetaReleaseTask(pMeta, pTask); - + doSendChkptSourceRsp(&req, &pMsg->info, TSDB_CODE_SYN_PROPOSE_NOT_READY, req.taskId); return TSDB_CODE_SUCCESS; } else { // checkpoint already finished, and not in checkpoint status if (req.checkpointId <= pTask->chkInfo.checkpointId) { @@ -1245,15 +1222,7 @@ int32_t tqProcessTaskCheckPointSourceReq(STQ* pTq, SRpcMsg* pMsg, SRpcMsg* pRsp) streamMutexUnlock(&pTask->lock); streamMetaReleaseTask(pMeta, pTask); - - SRpcMsg rsp = {0}; - int32_t ret = streamTaskBuildCheckpointSourceRsp(&req, &pMsg->info, &rsp, TSDB_CODE_SUCCESS); - if (ret) { // suppress the error in build checkpointsource rsp - tqError("s-task:%s failed to build checkpoint-source rsp, code:%s", pTask->id.idStr, tstrerror(code)); - } - - tmsgSendRsp(&rsp); // error occurs - + doSendChkptSourceRsp(&req, &pMsg->info, TSDB_CODE_SUCCESS, req.taskId); return TSDB_CODE_SUCCESS; } } @@ -1264,7 +1233,9 @@ int32_t tqProcessTaskCheckPointSourceReq(STQ* pTq, SRpcMsg* pMsg, SRpcMsg* pRsp) if (code) { qError("s-task:%s (vgId:%d) failed to process checkpoint-source req, code:%s", pTask->id.idStr, vgId, tstrerror(code)); - return code; + streamMetaReleaseTask(pMeta, pTask); + doSendChkptSourceRsp(&req, &pMsg->info, TSDB_CODE_SUCCESS, req.taskId); + return TSDB_CODE_SUCCESS; } if (req.mndTrigger) { @@ -1279,13 +1250,8 @@ int32_t tqProcessTaskCheckPointSourceReq(STQ* pTq, SRpcMsg* pMsg, SRpcMsg* pRsp) code = streamAddCheckpointSourceRspMsg(&req, &pMsg->info, pTask); if (code != TSDB_CODE_SUCCESS) { - SRpcMsg rsp = {0}; - int32_t ret = streamTaskBuildCheckpointSourceRsp(&req, &pMsg->info, &rsp, TSDB_CODE_SUCCESS); - if (ret) { // suppress the error in build checkpointsource rsp - tqError("s-task:%s failed to build checkpoint-source rsp, code:%s", pTask->id.idStr, tstrerror(code)); - } - tmsgSendRsp(&rsp); // error occurs - return TSDB_CODE_SUCCESS; + streamTaskSetCheckpointFailed(pTask); // set the checkpoint failed + doSendChkptSourceRsp(&req, &pMsg->info, TSDB_CODE_SUCCESS, req.taskId); } streamMetaReleaseTask(pMeta, pTask); From d2f77ffca02c1a6c51e59603a7316010cee1b286 Mon Sep 17 00:00:00 2001 From: dmchen Date: Fri, 6 Dec 2024 08:48:10 +0800 Subject: [PATCH 34/62] fix/skip-trim-during-restore --- source/libs/sync/src/syncMain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/libs/sync/src/syncMain.c b/source/libs/sync/src/syncMain.c index 5ae5a47e3c..ed9eb4b224 100644 --- a/source/libs/sync/src/syncMain.c +++ b/source/libs/sync/src/syncMain.c @@ -1464,7 +1464,7 @@ int32_t syncNodeRestore(SSyncNode* pSyncNode) { // if (endIndex != lastVer + 1) return TSDB_CODE_SYN_INTERNAL_ERROR; pSyncNode->commitIndex = TMAX(pSyncNode->commitIndex, commitIndex); - sInfo("vgId:%d, start to restore sync until commitIndex:%" PRId64, pSyncNode->vgId, pSyncNode->commitIndex); + sInfo("vgId:%d, restore began, and keep syncing until commitIndex:%" PRId64, pSyncNode->vgId, pSyncNode->commitIndex); if (pSyncNode->fsmState != SYNC_FSM_STATE_INCOMPLETE && (code = syncLogBufferCommit(pSyncNode->pLogBuf, pSyncNode, pSyncNode->commitIndex)) < 0) { From e6b36413c70745b3c20dbcd8841c4cb2de16327b Mon Sep 17 00:00:00 2001 From: Yibo Liu Date: Fri, 6 Dec 2024 09:03:47 +0800 Subject: [PATCH 35/62] Update index.mdx --- docs/zh/14-reference/01-components/12-tdinsight/index.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx index 615378a28f..e2ffff4adc 100644 --- a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx +++ b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx @@ -148,12 +148,12 @@ TDinsight 仪表盘旨在提供 TDengine 相关资源的使用情况和状态, ### 预配置告警规则自动导入 涛思总结用户使用经验,整理出14个常用的告警规则(alert rule),能够对集群关键指标进行监测并及时上报指标异常、超限等告警信息。 -从TDengine-server 3.3.4.3版本(tdengine-datasource 3.6.3)开始,TDengine Datasource 支持预配置告警规则自动导入功能,用户可将14个告警规则一键导入Grafana(11.x版本),直接使用。 -预配置告警规则导入方法如下图所示,在tdengine-datasource setting界面,打开 “Load Tengine Alert” 开关,点击 “Save & test” 按钮后,插件会自动加载上述告警规则, 规则会放入以数据源名称 + “-alert” 的 grafana 告警目录中。如不需要,关闭Load TDengine Alert开关。点击 “Clear TDengine Alert” 旁边的按钮则会清除此数据源已导入的所有告警规则。 +从 TDengine-server 3.3.4.3版本(tdengine-datasource 3.6.3)开始,TDengine Datasource 支持预配置告警规则自动导入功能,用户可将14个告警规则一键导入 Grafana(11及以上版本),直接使用。 +预配置告警规则导入方法如下图所示,在 tdengine-datasource setting 界面,打开 “Load Tengine Alert” 开关,点击 “Save & test” 按钮后,插件会自动加载上述告警规则, 规则会放入以数据源名称 + “-alert” 的 grafana 告警目录中。如不需要,关闭 “Load TDengine Alert” 开关,点击 “Clear TDengine Alert” 旁边的按钮则会清除此数据源已导入的所有告警规则。 ![TDengine Alert](./assets/TDengine-Alert.webp) -导入后,点击Grafana左侧Alert rules,可查看当前所有告警规则。 +导入后,点击 Grafana 左侧 “Alert rules” ,可查看当前所有告警规则。 用户只需配置联络点(Contact points),即可获取告警通知。联络点配置方法见[告警配置](https://docs.taosdata.com/third-party/visual/grafana/#%E5%91%8A%E8%AD%A6%E9%85%8D%E7%BD%AE)。 ![Alert-rules](./assets/Alert-rules.webp) @@ -178,7 +178,7 @@ TDinsight 仪表盘旨在提供 TDengine 相关资源的使用情况和状态, |dnode 重启 |max(update_time) > last(update_time)|触发告警|90秒|0秒|`select now(), dnode_id, max(uptime) - last(uptime) as dnode_restart from log.taosd_dnodes_info where _ts >= (now - 90s) and _ts < now partition by dnode_id`| 用户可参考上述告警规则,根据自己业务需求进行修改与完善。 -Grafana7.5及以下版本,Dashboards与Alert rules功能合在一起,而之后的新版本两个功能是分开的。为兼容Grafana7.5及以下版本,TDinsight面板中增加了Alert Used Only面板,仅Grafana7.5及以下版本需要使用。 +Grafana7.5 及以下版本,Dashboards 与 Alert rules 功能合在一起,而之后的新版本两个功能是分开的。为兼容 Grafana7.5及以下版本,TDinsight 面板中增加了 Alert Used Only 面板,仅 Grafana7.5及以下版本需要使用。 ![Alert Used Only](./assets/Alert-Used-Only.webp) From 0e08aa413f4ce6395a860e50515bece61067dd1f Mon Sep 17 00:00:00 2001 From: wangjiaming0909 <604227650@qq.com> Date: Fri, 6 Dec 2024 09:11:08 +0800 Subject: [PATCH 36/62] fix different byte length when union all with varchar --- source/libs/scalar/src/scalar.c | 1 - tests/system-test/2-query/union.py | 9 +++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/source/libs/scalar/src/scalar.c b/source/libs/scalar/src/scalar.c index 209110b014..b3610d035f 100644 --- a/source/libs/scalar/src/scalar.c +++ b/source/libs/scalar/src/scalar.c @@ -1241,7 +1241,6 @@ EDealRes sclRewriteFunction(SNode **pNode, SScalarCtx *ctx) { ctx->code = TSDB_CODE_OUT_OF_MEMORY; return DEAL_RES_ERROR; } - res->node.resType.bytes = varDataTLen(output.columnData->pData); (void)memcpy(res->datum.p, output.columnData->pData, varDataTLen(output.columnData->pData)); } else { ctx->code = nodesSetValueNodeValue(res, output.columnData->pData); diff --git a/tests/system-test/2-query/union.py b/tests/system-test/2-query/union.py index 5104489592..fc6dd4fb32 100644 --- a/tests/system-test/2-query/union.py +++ b/tests/system-test/2-query/union.py @@ -426,6 +426,15 @@ class TDTestCase: tdLog.printNoPrefix("==========step4:after wal, all check again ") self.all_test() + self.test_TD_33137() + + def test_TD_33137(self): + sql = "select 'asd' union all select 'asdasd'" + tdSql.query(sql, queryTimes=1) + tdSql.checkRows(2) + sql = "select db_name `TABLE_CAT`, '' `TABLE_SCHEM`, stable_name `TABLE_NAME`, 'TABLE' `TABLE_TYPE`, table_comment `REMARKS` from information_schema.ins_stables union all select db_name `TABLE_CAT`, '' `TABLE_SCHEM`, table_name `TABLE_NAME`, case when `type`='SYSTEM_TABLE' then 'TABLE' when `type`='NORMAL_TABLE' then 'TABLE' when `type`='CHILD_TABLE' then 'TABLE' else 'UNKNOWN' end `TABLE_TYPE`, table_comment `REMARKS` from information_schema.ins_tables union all select db_name `TABLE_CAT`, '' `TABLE_SCHEM`, view_name `TABLE_NAME`, 'VIEW' `TABLE_TYPE`, NULL `REMARKS` from information_schema.ins_views" + tdSql.query(sql, queryTimes=1) + tdSql.checkRows(47) def stop(self): tdSql.close() From 43ad35f91165825a41c4f4f15ffecb6a747407e1 Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Fri, 6 Dec 2024 09:20:39 +0800 Subject: [PATCH 37/62] refactor: adjust the lock procedure for unregister stream tasks. --- source/dnode/vnode/src/sma/smaRollup.c | 3 ++- source/dnode/vnode/src/tqCommon/tqCommon.c | 3 --- source/libs/stream/src/streamCheckpoint.c | 6 ------ source/libs/stream/src/streamMeta.c | 6 ------ 4 files changed, 2 insertions(+), 16 deletions(-) diff --git a/source/dnode/vnode/src/sma/smaRollup.c b/source/dnode/vnode/src/sma/smaRollup.c index 80c04a3276..bcacac20a2 100644 --- a/source/dnode/vnode/src/sma/smaRollup.c +++ b/source/dnode/vnode/src/sma/smaRollup.c @@ -254,11 +254,12 @@ static void tdRSmaTaskInit(SStreamMeta *pMeta, SRSmaInfoItem *pItem, SStreamTask } static void tdRSmaTaskRemove(SStreamMeta *pMeta, int64_t streamId, int32_t taskId) { + streamMetaWLock(pMeta); + int32_t code = streamMetaUnregisterTask(pMeta, streamId, taskId); if (code != 0) { smaError("vgId:%d, rsma task:%" PRIi64 ",%d drop failed since %s", pMeta->vgId, streamId, taskId, tstrerror(code)); } - streamMetaWLock(pMeta); int32_t numOfTasks = streamMetaGetNumOfTasks(pMeta); if (streamMetaCommit(pMeta) < 0) { // persist to disk diff --git a/source/dnode/vnode/src/tqCommon/tqCommon.c b/source/dnode/vnode/src/tqCommon/tqCommon.c index 1ea524dc78..68fb651566 100644 --- a/source/dnode/vnode/src/tqCommon/tqCommon.c +++ b/source/dnode/vnode/src/tqCommon/tqCommon.c @@ -718,8 +718,6 @@ int32_t tqStreamTaskProcessDropReq(SStreamMeta* pMeta, char* msg, int32_t msgLen } } - streamMetaWUnLock(pMeta); - // drop the related fill-history task firstly if (hTaskId.taskId != 0 && hTaskId.streamId != 0) { tqDebug("s-task:0x%x vgId:%d drop rel fill-history task:0x%x firstly", pReq->taskId, vgId, (int32_t)hTaskId.taskId); @@ -737,7 +735,6 @@ int32_t tqStreamTaskProcessDropReq(SStreamMeta* pMeta, char* msg, int32_t msgLen } // commit the update - streamMetaWLock(pMeta); int32_t numOfTasks = streamMetaGetNumOfTasks(pMeta); tqDebug("vgId:%d task:0x%x dropped, remain tasks:%d", vgId, pReq->taskId, numOfTasks); diff --git a/source/libs/stream/src/streamCheckpoint.c b/source/libs/stream/src/streamCheckpoint.c index 3ca283ce98..641f41daa9 100644 --- a/source/libs/stream/src/streamCheckpoint.c +++ b/source/libs/stream/src/streamCheckpoint.c @@ -591,7 +591,6 @@ int32_t streamTaskUpdateTaskCheckpointInfo(SStreamTask* pTask, bool restored, SV { // destroy the related fill-history tasks // drop task should not in the meta-lock, and drop the related fill-history task now - streamMetaWUnLock(pMeta); if (pReq->dropRelHTask) { code = streamMetaUnregisterTask(pMeta, pReq->hStreamId, pReq->hTaskId); int32_t numOfTasks = streamMetaGetNumOfTasks(pMeta); @@ -599,7 +598,6 @@ int32_t streamTaskUpdateTaskCheckpointInfo(SStreamTask* pTask, bool restored, SV id, vgId, pReq->taskId, numOfTasks); } - streamMetaWLock(pMeta); if (pReq->dropRelHTask) { code = streamMetaCommit(pMeta); } @@ -675,8 +673,6 @@ int32_t streamTaskUpdateTaskCheckpointInfo(SStreamTask* pTask, bool restored, SV return TSDB_CODE_SUCCESS; } - streamMetaWUnLock(pMeta); - // drop task should not in the meta-lock, and drop the related fill-history task now if (pReq->dropRelHTask) { code = streamMetaUnregisterTask(pMeta, pReq->hStreamId, pReq->hTaskId); @@ -685,9 +681,7 @@ int32_t streamTaskUpdateTaskCheckpointInfo(SStreamTask* pTask, bool restored, SV (int32_t)pReq->hTaskId, numOfTasks); } - streamMetaWLock(pMeta); code = streamMetaCommit(pMeta); - return TSDB_CODE_SUCCESS; } diff --git a/source/libs/stream/src/streamMeta.c b/source/libs/stream/src/streamMeta.c index a6f87711bf..23a98ef3ae 100644 --- a/source/libs/stream/src/streamMeta.c +++ b/source/libs/stream/src/streamMeta.c @@ -501,8 +501,6 @@ _err: void streamMetaInitBackend(SStreamMeta* pMeta) { pMeta->streamBackend = streamBackendInit(pMeta->path, pMeta->chkpId, pMeta->vgId); if (pMeta->streamBackend == NULL) { - streamMetaWUnLock(pMeta); - while (1) { streamMetaWLock(pMeta); pMeta->streamBackend = streamBackendInit(pMeta->path, pMeta->chkpId, pMeta->vgId); @@ -908,8 +906,6 @@ int32_t streamMetaUnregisterTask(SStreamMeta* pMeta, int64_t streamId, int32_t t int32_t code = 0; STaskId id = {.streamId = streamId, .taskId = taskId}; - streamMetaWLock(pMeta); - code = streamMetaAcquireTaskUnsafe(pMeta, &id, &pTask); if (code == 0) { // desc the paused task counter @@ -958,10 +954,8 @@ int32_t streamMetaUnregisterTask(SStreamMeta* pMeta, int64_t streamId, int32_t t } streamMetaReleaseTask(pMeta, pTask); - streamMetaWUnLock(pMeta); } else { stDebug("vgId:%d failed to find the task:0x%x, it may have been dropped already", vgId, taskId); - streamMetaWUnLock(pMeta); } return 0; From ea32cad5e4c33466f3db8ec79a35fbfac392efdc Mon Sep 17 00:00:00 2001 From: danielclow <106956386+danielclow@users.noreply.github.com> Date: Fri, 6 Dec 2024 10:33:44 +0800 Subject: [PATCH 38/62] docs: fix tabs on connector page --- docs/en/07-develop/01-connect.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/en/07-develop/01-connect.md b/docs/en/07-develop/01-connect.md index 97e96f98a4..66bd9b6b16 100644 --- a/docs/en/07-develop/01-connect.md +++ b/docs/en/07-develop/01-connect.md @@ -164,9 +164,6 @@ If you are using Maven to manage your project, simply add the following dependen pip3 install taospy[ws] ``` - - - - **Installation Verification** @@ -199,8 +196,8 @@ import taosws + - Edit `go.mod` to add the `driver-go` dependency. From 1cf60b94762499f0ac580b3fc656011782cb46c3 Mon Sep 17 00:00:00 2001 From: Yibo Liu Date: Fri, 6 Dec 2024 10:37:19 +0800 Subject: [PATCH 39/62] Update index.mdx --- docs/zh/14-reference/01-components/12-tdinsight/index.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx index e2ffff4adc..0f6ea46ffd 100644 --- a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx +++ b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx @@ -147,8 +147,8 @@ TDinsight 仪表盘旨在提供 TDengine 相关资源的使用情况和状态, ### 预配置告警规则自动导入 -涛思总结用户使用经验,整理出14个常用的告警规则(alert rule),能够对集群关键指标进行监测并及时上报指标异常、超限等告警信息。 -从 TDengine-server 3.3.4.3版本(tdengine-datasource 3.6.3)开始,TDengine Datasource 支持预配置告警规则自动导入功能,用户可将14个告警规则一键导入 Grafana(11及以上版本),直接使用。 +涛思总结用户使用经验,整理出 14 个常用的告警规则(alert rule),能够对集群关键指标进行监测并及时上报指标异常、超限等告警信息。 +从 TDengine-server 3.3.4.3 版本(tdengine-datasource 3.6.3)开始,TDengine Datasource 支持预配置告警规则自动导入功能,用户可将 14 个告警规则一键导入 Grafana(11 及以上版本),直接使用。 预配置告警规则导入方法如下图所示,在 tdengine-datasource setting 界面,打开 “Load Tengine Alert” 开关,点击 “Save & test” 按钮后,插件会自动加载上述告警规则, 规则会放入以数据源名称 + “-alert” 的 grafana 告警目录中。如不需要,关闭 “Load TDengine Alert” 开关,点击 “Clear TDengine Alert” 旁边的按钮则会清除此数据源已导入的所有告警规则。 ![TDengine Alert](./assets/TDengine-Alert.webp) @@ -158,7 +158,7 @@ TDinsight 仪表盘旨在提供 TDengine 相关资源的使用情况和状态, ![Alert-rules](./assets/Alert-rules.webp) -14个告警规则具体配置如下: +14 个告警规则具体配置如下: | 规则名称| 规则阈值| 无监控数据时的行为 | 数据扫描间隔 |持续时间 | 执行SQL | | ------ | --------- | ---------------- | ----------- |------- |----------------------| @@ -178,7 +178,7 @@ TDinsight 仪表盘旨在提供 TDengine 相关资源的使用情况和状态, |dnode 重启 |max(update_time) > last(update_time)|触发告警|90秒|0秒|`select now(), dnode_id, max(uptime) - last(uptime) as dnode_restart from log.taosd_dnodes_info where _ts >= (now - 90s) and _ts < now partition by dnode_id`| 用户可参考上述告警规则,根据自己业务需求进行修改与完善。 -Grafana7.5 及以下版本,Dashboards 与 Alert rules 功能合在一起,而之后的新版本两个功能是分开的。为兼容 Grafana7.5及以下版本,TDinsight 面板中增加了 Alert Used Only 面板,仅 Grafana7.5及以下版本需要使用。 +Grafana7.5 及以下版本,Dashboards 与 Alert rules 功能合在一起,而之后的新版本两个功能是分开的。为兼容 Grafana7.5 及以下版本,TDinsight 面板中增加了 Alert Used Only 面板,仅 Grafana7.5 及以下版本需要使用。 ![Alert Used Only](./assets/Alert-Used-Only.webp) From 8c128ca05d06f057b7fc3d4907d174fd88b370fa Mon Sep 17 00:00:00 2001 From: yihaoDeng Date: Fri, 6 Dec 2024 15:08:59 +0800 Subject: [PATCH 40/62] add perf log to blocking-sys-call --- source/os/src/osSocket.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/source/os/src/osSocket.c b/source/os/src/osSocket.c index 32b1023ed7..9433a76469 100644 --- a/source/os/src/osSocket.c +++ b/source/os/src/osSocket.c @@ -233,15 +233,19 @@ int32_t taosBlockSIGPIPE() { } int32_t taosGetIpv4FromFqdn(const char *fqdn, uint32_t *ip) { + int32_t code = 0; OS_PARAM_CHECK(fqdn); OS_PARAM_CHECK(ip); + int64_t limitMs = 1000; + int64_t st = taosGetTimestampMs(), cost = 0; #ifdef WINDOWS // Initialize Winsock WSADATA wsaData; int iResult; iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); if (iResult != 0) { - return TAOS_SYSTEM_WINSOCKET_ERROR(WSAGetLastError()); + code = TAOS_SYSTEM_WINSOCKET_ERROR(WSAGetLastError()); + goto _err; } #endif @@ -260,12 +264,12 @@ int32_t taosGetIpv4FromFqdn(const char *fqdn, uint32_t *ip) { inRetry = true; continue; } else if (EAI_SYSTEM == ret) { - terrno = TAOS_SYSTEM_ERROR(errno); - return terrno; + code = TAOS_SYSTEM_ERROR(errno); + goto _err; } - terrno = TAOS_SYSTEM_ERROR(errno); - return terrno; + code = TAOS_SYSTEM_ERROR(errno); + goto _err; } struct sockaddr *sa = result->ai_addr; @@ -275,8 +279,7 @@ int32_t taosGetIpv4FromFqdn(const char *fqdn, uint32_t *ip) { *ip = ia.s_addr; freeaddrinfo(result); - - return 0; + goto _err; } #else struct addrinfo hints = {0}; @@ -292,7 +295,7 @@ int32_t taosGetIpv4FromFqdn(const char *fqdn, uint32_t *ip) { struct in_addr ia = si->sin_addr; *ip = ia.s_addr; freeaddrinfo(result); - return 0; + goto _err; } else { #ifdef EAI_SYSTEM if (ret == EAI_SYSTEM) { @@ -305,9 +308,16 @@ int32_t taosGetIpv4FromFqdn(const char *fqdn, uint32_t *ip) { #endif *ip = 0xFFFFFFFF; - return TSDB_CODE_RPC_FQDN_ERROR; + code = TSDB_CODE_RPC_FQDN_ERROR; + goto _err; } #endif +_err: + cost = taosGetTimestampMs() - st; + if (cost >= limitMs) { + uWarn("get ip from fqdn:%s, cost:%" PRId64 "ms", fqdn, cost); + } + return code; } int32_t taosGetFqdn(char *fqdn) { From 34f1f23ed39ebcaf8a23e6e0cc88b9f8dbfd175c Mon Sep 17 00:00:00 2001 From: wangjiaming0909 <604227650@qq.com> Date: Fri, 6 Dec 2024 16:37:53 +0800 Subject: [PATCH 41/62] fix tests --- source/libs/nodes/src/nodesUtilFuncs.c | 5 ++--- source/libs/scheduler/src/schTask.c | 6 +++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/source/libs/nodes/src/nodesUtilFuncs.c b/source/libs/nodes/src/nodesUtilFuncs.c index 04b0d56a63..1d5dfa19da 100644 --- a/source/libs/nodes/src/nodesUtilFuncs.c +++ b/source/libs/nodes/src/nodesUtilFuncs.c @@ -2952,8 +2952,7 @@ int32_t nodesValueNodeToVariant(const SValueNode* pNode, SVariant* pVal) { case TSDB_DATA_TYPE_GEOMETRY: pVal->pz = taosMemoryMalloc(pVal->nLen + 1); if (pVal->pz) { - memcpy(pVal->pz, pNode->datum.p, pVal->nLen); - pVal->pz[pVal->nLen] = 0; + memcpy(pVal->pz, pNode->datum.p, varDataTLen(pNode->datum.p)); } else { code = terrno; } @@ -2962,7 +2961,7 @@ int32_t nodesValueNodeToVariant(const SValueNode* pNode, SVariant* pVal) { pVal->nLen = getJsonValueLen(pNode->datum.p); pVal->pz = taosMemoryMalloc(pVal->nLen); if (pVal->pz) { - memcpy(pVal->pz, pNode->datum.p, pVal->nLen); + memcpy(pVal->pz, pNode->datum.p, varDataTLen(pNode->datum.p)); } else { code = terrno; } diff --git a/source/libs/scheduler/src/schTask.c b/source/libs/scheduler/src/schTask.c index 9be0e3fc40..37249b5418 100644 --- a/source/libs/scheduler/src/schTask.c +++ b/source/libs/scheduler/src/schTask.c @@ -1129,7 +1129,11 @@ int32_t schLaunchRemoteTask(SSchJob *pJob, SSchTask *pTask) { int32_t schLaunchLocalTask(SSchJob *pJob, SSchTask *pTask) { // SCH_ERR_JRET(schSetTaskCandidateAddrs(pJob, pTask)); if (NULL == schMgmt.queryMgmt) { - SCH_ERR_RET(qWorkerInit(NODE_TYPE_CLIENT, CLIENT_HANDLE, (void **)&schMgmt.queryMgmt, NULL)); + void* p = NULL; + SCH_ERR_RET(qWorkerInit(NODE_TYPE_CLIENT, CLIENT_HANDLE, &p, NULL)); + if (atomic_val_compare_exchange_ptr(&schMgmt.queryMgmt, NULL, p)) { + qWorkerDestroy(&p); + } } SArray *explainRes = NULL; From 1f36e0a821cd74370939bbde711cec1c16c58c81 Mon Sep 17 00:00:00 2001 From: wangjiaming0909 <604227650@qq.com> Date: Fri, 6 Dec 2024 18:06:26 +0800 Subject: [PATCH 42/62] fix tests --- source/libs/nodes/src/nodesUtilFuncs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/libs/nodes/src/nodesUtilFuncs.c b/source/libs/nodes/src/nodesUtilFuncs.c index 1d5dfa19da..518f8a52d3 100644 --- a/source/libs/nodes/src/nodesUtilFuncs.c +++ b/source/libs/nodes/src/nodesUtilFuncs.c @@ -2950,7 +2950,7 @@ int32_t nodesValueNodeToVariant(const SValueNode* pNode, SVariant* pVal) { case TSDB_DATA_TYPE_VARCHAR: case TSDB_DATA_TYPE_VARBINARY: case TSDB_DATA_TYPE_GEOMETRY: - pVal->pz = taosMemoryMalloc(pVal->nLen + 1); + pVal->pz = taosMemoryCalloc(1, pVal->nLen + 1); if (pVal->pz) { memcpy(pVal->pz, pNode->datum.p, varDataTLen(pNode->datum.p)); } else { @@ -2959,9 +2959,9 @@ int32_t nodesValueNodeToVariant(const SValueNode* pNode, SVariant* pVal) { break; case TSDB_DATA_TYPE_JSON: pVal->nLen = getJsonValueLen(pNode->datum.p); - pVal->pz = taosMemoryMalloc(pVal->nLen); + pVal->pz = taosMemoryCalloc(1, pVal->nLen); if (pVal->pz) { - memcpy(pVal->pz, pNode->datum.p, varDataTLen(pNode->datum.p)); + memcpy(pVal->pz, pNode->datum.p, pVal->nLen); } else { code = terrno; } From 1d700079d44ff1d83b583ead05de361840cae2d8 Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Fri, 6 Dec 2024 18:56:49 +0800 Subject: [PATCH 43/62] refactor: 1) add update task nodeep trans for every involved streams. 2) do some internal refactor for conflict check. --- source/dnode/mnode/impl/src/mndStream.c | 11 ++-- source/dnode/mnode/impl/src/mndStreamTrans.c | 55 +++++++++++--------- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/source/dnode/mnode/impl/src/mndStream.c b/source/dnode/mnode/impl/src/mndStream.c index 5d41e1506c..0a107518df 100644 --- a/source/dnode/mnode/impl/src/mndStream.c +++ b/source/dnode/mnode/impl/src/mndStream.c @@ -1931,11 +1931,6 @@ static int32_t mndProcessVgroupChange(SMnode *pMnode, SVgroupChangeInfo *pChange sdbCancelFetch(pSdb, pIter); return terrno = code; } - - code = mndStreamRegisterTrans(pTrans, MND_STREAM_TASK_UPDATE_NAME, pStream->uid); - if (code) { - mError("failed to register trans, transId:%d, and continue", pTrans->id); - } } if (!includeAllNodes) { @@ -1951,6 +1946,12 @@ static int32_t mndProcessVgroupChange(SMnode *pMnode, SVgroupChangeInfo *pChange mDebug("stream:0x%" PRIx64 " %s involved node changed, create update trans, transId:%d", pStream->uid, pStream->name, pTrans->id); + // NOTE: for each stream, we register one trans entry for task update + code = mndStreamRegisterTrans(pTrans, MND_STREAM_TASK_UPDATE_NAME, pStream->uid); + if (code) { + mError("failed to register trans, transId:%d, and continue", pTrans->id); + } + code = mndStreamSetUpdateEpsetAction(pMnode, pStream, pChangeInfo, pTrans); // todo: not continue, drop all and retry again diff --git a/source/dnode/mnode/impl/src/mndStreamTrans.c b/source/dnode/mnode/impl/src/mndStreamTrans.c index 905a73ad48..a1f87f4d72 100644 --- a/source/dnode/mnode/impl/src/mndStreamTrans.c +++ b/source/dnode/mnode/impl/src/mndStreamTrans.c @@ -35,7 +35,12 @@ int32_t mndStreamClearFinishedTrans(SMnode *pMnode, int32_t *pNumOfActiveChkpt) size_t keyLen = 0; void *pIter = NULL; SArray *pList = taosArrayInit(4, sizeof(SKeyInfo)); - int32_t num = 0; + int32_t numOfChkpt = 0; + int32_t numOfTaskUpdate = 0; + + if (pNumOfActiveChkpt != NULL) { + *pNumOfActiveChkpt = 0; + } if (pList == NULL) { return terrno; @@ -50,15 +55,15 @@ int32_t mndStreamClearFinishedTrans(SMnode *pMnode, int32_t *pNumOfActiveChkpt) void *pKey = taosHashGetKey(pEntry, &keyLen); // key is the name of src/dst db name SKeyInfo info = {.pKey = pKey, .keyLen = keyLen}; - mDebug("transId:%d %s startTs:%" PRId64 " cleared since finished", pEntry->transId, pEntry->name, - pEntry->startTime); + mDebug("transId:%d stream:0x%" PRIx64 " %s startTs:%" PRId64 " cleared since finished", pEntry->transId, + pEntry->streamId, pEntry->name, pEntry->startTime); void* p = taosArrayPush(pList, &info); if (p == NULL) { return terrno; } } else { if (strcmp(pEntry->name, MND_STREAM_CHECKPOINT_NAME) == 0) { - num++; + numOfChkpt++; } mndReleaseTrans(pMnode, pTrans); } @@ -78,48 +83,34 @@ int32_t mndStreamClearFinishedTrans(SMnode *pMnode, int32_t *pNumOfActiveChkpt) } } - mDebug("clear %d finished stream-trans, remained:%d, active checkpoint trans:%d", size, - taosHashGetSize(execInfo.transMgmt.pDBTrans), num); + mDebug("clear %d finished stream-trans, active trans:%d, active checkpoint trans:%d, update trans:%d", size, + taosHashGetSize(execInfo.transMgmt.pDBTrans), numOfChkpt, numOfTaskUpdate); taosArrayDestroy(pList); if (pNumOfActiveChkpt != NULL) { - *pNumOfActiveChkpt = num; + *pNumOfActiveChkpt = numOfChkpt; } return 0; } -// * Transactions of different streams are not related. Here only check the conflict of transaction for a given stream. -// For a given stream: -// 1. checkpoint trans is conflict with any other trans except for the drop and reset trans. -// 2. create/drop/reset/update trans are conflict with any other trans. -int32_t mndStreamTransConflictCheck(SMnode *pMnode, int64_t streamId, const char *pTransName, bool lock) { - if (lock) { - streamMutexLock(&execInfo.lock); - } - +static int32_t doStreamTransConflictCheck(SMnode *pMnode, int64_t streamId, const char *pTransName) { int32_t num = taosHashGetSize(execInfo.transMgmt.pDBTrans); if (num <= 0) { - if (lock) { - streamMutexUnlock(&execInfo.lock); - } return 0; } + // if any task updates exist, any other stream trans are not allowed to be created int32_t code = mndStreamClearFinishedTrans(pMnode, NULL); if (code) { - mError("failed to clear finish trans, code:%s", tstrerror(code)); + mError("failed to clear finish trans, code:%s, and continue", tstrerror(code)); } SStreamTransInfo *pEntry = taosHashGet(execInfo.transMgmt.pDBTrans, &streamId, sizeof(streamId)); if (pEntry != NULL) { SStreamTransInfo tInfo = *pEntry; - if (lock) { - streamMutexUnlock(&execInfo.lock); - } - if (strcmp(tInfo.name, MND_STREAM_CHECKPOINT_NAME) == 0) { if ((strcmp(pTransName, MND_STREAM_DROP_NAME) != 0) && (strcmp(pTransName, MND_STREAM_TASK_RESET_NAME) != 0) && (strcmp(pTransName, MND_STREAM_RESTART_NAME) != 0)) { @@ -141,11 +132,25 @@ int32_t mndStreamTransConflictCheck(SMnode *pMnode, int64_t streamId, const char mDebug("stream:0x%" PRIx64 " no conflict trans existed, continue create trans", streamId); } + return TSDB_CODE_SUCCESS; +} + +// * Transactions of different streams are not related. Here only check the conflict of transaction for a given stream. +// For a given stream: +// 1. checkpoint trans is conflict with any other trans except for the drop and reset trans. +// 2. create/drop/reset/update trans are conflict with any other trans. +int32_t mndStreamTransConflictCheck(SMnode *pMnode, int64_t streamId, const char *pTransName, bool lock) { + if (lock) { + streamMutexLock(&execInfo.lock); + } + + int32_t code = doStreamTransConflictCheck(pMnode, streamId, pTransName); + if (lock) { streamMutexUnlock(&execInfo.lock); } - return 0; + return code; } int32_t mndStreamGetRelTrans(SMnode *pMnode, int64_t streamId) { From 85c7d513c5bb555ba128240651ea75b152992477 Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Fri, 6 Dec 2024 19:17:35 +0800 Subject: [PATCH 44/62] refactor(stream): remove unused variables. --- source/dnode/mnode/impl/src/mndStreamTrans.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/dnode/mnode/impl/src/mndStreamTrans.c b/source/dnode/mnode/impl/src/mndStreamTrans.c index a1f87f4d72..da55a14d74 100644 --- a/source/dnode/mnode/impl/src/mndStreamTrans.c +++ b/source/dnode/mnode/impl/src/mndStreamTrans.c @@ -36,7 +36,6 @@ int32_t mndStreamClearFinishedTrans(SMnode *pMnode, int32_t *pNumOfActiveChkpt) void *pIter = NULL; SArray *pList = taosArrayInit(4, sizeof(SKeyInfo)); int32_t numOfChkpt = 0; - int32_t numOfTaskUpdate = 0; if (pNumOfActiveChkpt != NULL) { *pNumOfActiveChkpt = 0; @@ -84,7 +83,7 @@ int32_t mndStreamClearFinishedTrans(SMnode *pMnode, int32_t *pNumOfActiveChkpt) } mDebug("clear %d finished stream-trans, active trans:%d, active checkpoint trans:%d, update trans:%d", size, - taosHashGetSize(execInfo.transMgmt.pDBTrans), numOfChkpt, numOfTaskUpdate); + taosHashGetSize(execInfo.transMgmt.pDBTrans), numOfChkpt); taosArrayDestroy(pList); From 06f91b64e69012dfbc38548b9551409c06d6797c Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Sat, 7 Dec 2024 11:51:42 +0800 Subject: [PATCH 45/62] fix(stream): fix syntax error. --- source/dnode/mnode/impl/src/mndStreamTrans.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/dnode/mnode/impl/src/mndStreamTrans.c b/source/dnode/mnode/impl/src/mndStreamTrans.c index da55a14d74..a1e104aeca 100644 --- a/source/dnode/mnode/impl/src/mndStreamTrans.c +++ b/source/dnode/mnode/impl/src/mndStreamTrans.c @@ -82,7 +82,7 @@ int32_t mndStreamClearFinishedTrans(SMnode *pMnode, int32_t *pNumOfActiveChkpt) } } - mDebug("clear %d finished stream-trans, active trans:%d, active checkpoint trans:%d, update trans:%d", size, + mDebug("clear %d finished stream-trans, active trans:%d, active checkpoint trans:%d", size, taosHashGetSize(execInfo.transMgmt.pDBTrans), numOfChkpt); taosArrayDestroy(pList); From cea647daf6905b12cab2e2ee606a0de8b315c6ba Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Sat, 7 Dec 2024 12:21:28 +0800 Subject: [PATCH 46/62] refactor: limit the number of items in inputq to be 5120 --- source/libs/stream/inc/streamInt.h | 2 +- source/libs/stream/src/streamSched.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/source/libs/stream/inc/streamInt.h b/source/libs/stream/inc/streamInt.h index 863bc76c79..8f9e4a311c 100644 --- a/source/libs/stream/inc/streamInt.h +++ b/source/libs/stream/inc/streamInt.h @@ -37,7 +37,7 @@ extern "C" { #define META_HB_CHECK_INTERVAL 200 #define META_HB_SEND_IDLE_COUNTER 25 // send hb every 5 sec #define STREAM_TASK_KEY_LEN ((sizeof(int64_t)) << 1) -#define STREAM_TASK_QUEUE_CAPACITY 20480 +#define STREAM_TASK_QUEUE_CAPACITY 5120 #define STREAM_TASK_QUEUE_CAPACITY_IN_SIZE (30) // clang-format off diff --git a/source/libs/stream/src/streamSched.c b/source/libs/stream/src/streamSched.c index bf402234ba..0436ae7ee4 100644 --- a/source/libs/stream/src/streamSched.c +++ b/source/libs/stream/src/streamSched.c @@ -225,7 +225,8 @@ static int32_t doCreateForceWindowTrigger(SStreamTask* pTask, int32_t* pNextTrig } pTask->status.latestForceWindow = w; - if (w.ekey + pTask->info.watermark + pTask->info.interval.interval > now) { + if ((w.ekey + pTask->info.watermark + pTask->info.interval.interval > now) || + streamQueueIsFull(pTask->inputq.queue)) { int64_t prev = convertTimePrecision(*pNextTrigger, precision, TSDB_TIME_PRECISION_MILLI); *pNextTrigger = w.ekey + pTask->info.watermark + pTask->info.interval.interval - now; From b715df1ac45fd49c2069ae10ca3234b54f0362f9 Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Sun, 8 Dec 2024 00:20:28 +0800 Subject: [PATCH 47/62] fix(stream): adjust schedule interval. --- source/libs/stream/src/streamSched.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/source/libs/stream/src/streamSched.c b/source/libs/stream/src/streamSched.c index 0436ae7ee4..1d0c882003 100644 --- a/source/libs/stream/src/streamSched.c +++ b/source/libs/stream/src/streamSched.c @@ -192,6 +192,7 @@ static int32_t doCreateForceWindowTrigger(SStreamTask* pTask, int32_t* pNextTrig const char* id = pTask->id.idStr; int8_t precision = pTask->info.interval.precision; SStreamTrigger* pTrigger = NULL; + bool isFull = false; while (1) { code = streamCreateForcewindowTrigger(&pTrigger, pTask->info.delaySchedParam, &pTask->info.interval, @@ -225,13 +226,15 @@ static int32_t doCreateForceWindowTrigger(SStreamTask* pTask, int32_t* pNextTrig } pTask->status.latestForceWindow = w; - if ((w.ekey + pTask->info.watermark + pTask->info.interval.interval > now) || - streamQueueIsFull(pTask->inputq.queue)) { + isFull = streamQueueIsFull(pTask->inputq.queue); + + if ((w.ekey + pTask->info.watermark + pTask->info.interval.interval > now) || isFull) { int64_t prev = convertTimePrecision(*pNextTrigger, precision, TSDB_TIME_PRECISION_MILLI); + if (!isFull) { + *pNextTrigger = w.ekey + pTask->info.watermark + pTask->info.interval.interval - now; + } - *pNextTrigger = w.ekey + pTask->info.watermark + pTask->info.interval.interval - now; *pNextTrigger = convertTimePrecision(*pNextTrigger, precision, TSDB_TIME_PRECISION_MILLI); - pTask->chkInfo.nextProcessVer = w.ekey + pTask->info.interval.interval; stDebug("s-task:%s generate %d time window(s), trigger delay adjust from %" PRId64 " to %d, set ver:%" PRId64, id, num, prev, *pNextTrigger, pTask->chkInfo.nextProcessVer); From 3e9b303b0b26d50d11c26a5263c6243955576a82 Mon Sep 17 00:00:00 2001 From: wangmm0220 Date: Mon, 9 Dec 2024 09:30:29 +0800 Subject: [PATCH 48/62] fix:[TD-33057] memory leak --- source/client/src/clientRawBlockWrite.c | 211 +++++++++++++----------- 1 file changed, 113 insertions(+), 98 deletions(-) diff --git a/source/client/src/clientRawBlockWrite.c b/source/client/src/clientRawBlockWrite.c index 3a23d38375..987bed1cf5 100644 --- a/source/client/src/clientRawBlockWrite.c +++ b/source/client/src/clientRawBlockWrite.c @@ -52,6 +52,22 @@ #define TMQ_META_VERSION "1.0" +static bool tmqAddJsonObjectItem(cJSON *object, const char *string, cJSON *item){ + bool ret = cJSON_AddItemToObject(object, string, item); + if (!ret){ + cJSON_Delete(item); + } + return ret; +} +static bool tmqAddJsonArrayItem(cJSON *array, cJSON *item){ + bool ret = cJSON_AddItemToArray(array, item); + if (!ret){ + cJSON_Delete(item); + } + return ret; +} + + static int32_t tmqWriteBatchMetaDataImpl(TAOS* taos, void* meta, int32_t metaLen); static tb_uid_t processSuid(tb_uid_t suid, char* db) { return suid + MurmurHash3_32(db, strlen(db)); } static void buildCreateTableJson(SSchemaWrapper* schemaRow, SSchemaWrapper* schemaTag, char* name, int64_t id, int8_t t, @@ -68,13 +84,13 @@ static void buildCreateTableJson(SSchemaWrapper* schemaRow, SSchemaWrapper* sche cJSON* type = cJSON_CreateString("create"); RAW_NULL_CHECK(type); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "type", type)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "type", type)); cJSON* tableType = cJSON_CreateString(t == TSDB_NORMAL_TABLE ? "normal" : "super"); RAW_NULL_CHECK(tableType); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "tableType", tableType)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tableType", tableType)); cJSON* tableName = cJSON_CreateString(name); RAW_NULL_CHECK(tableName); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "tableName", tableName)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tableName", tableName)); cJSON* columns = cJSON_CreateArray(); RAW_NULL_CHECK(columns); @@ -84,25 +100,25 @@ static void buildCreateTableJson(SSchemaWrapper* schemaRow, SSchemaWrapper* sche SSchema* s = schemaRow->pSchema + i; cJSON* cname = cJSON_CreateString(s->name); RAW_NULL_CHECK(cname); - RAW_FALSE_CHECK(cJSON_AddItemToObject(column, "name", cname)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(column, "name", cname)); cJSON* ctype = cJSON_CreateNumber(s->type); RAW_NULL_CHECK(ctype); - RAW_FALSE_CHECK(cJSON_AddItemToObject(column, "type", ctype)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(column, "type", ctype)); if (s->type == TSDB_DATA_TYPE_BINARY || s->type == TSDB_DATA_TYPE_VARBINARY || s->type == TSDB_DATA_TYPE_GEOMETRY) { int32_t length = s->bytes - VARSTR_HEADER_SIZE; cJSON* cbytes = cJSON_CreateNumber(length); RAW_NULL_CHECK(cbytes); - RAW_FALSE_CHECK(cJSON_AddItemToObject(column, "length", cbytes)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(column, "length", cbytes)); } else if (s->type == TSDB_DATA_TYPE_NCHAR) { int32_t length = (s->bytes - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE; cJSON* cbytes = cJSON_CreateNumber(length); RAW_NULL_CHECK(cbytes); - RAW_FALSE_CHECK(cJSON_AddItemToObject(column, "length", cbytes)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(column, "length", cbytes)); } cJSON* isPk = cJSON_CreateBool(s->flags & COL_IS_KEY); RAW_NULL_CHECK(isPk); - RAW_FALSE_CHECK(cJSON_AddItemToObject(column, "isPrimarykey", isPk)); - RAW_FALSE_CHECK(cJSON_AddItemToArray(columns, column)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(column, "isPrimarykey", isPk)); + RAW_FALSE_CHECK(tmqAddJsonArrayItem(columns, column)); if (pColCmprRow == NULL) { continue; @@ -124,17 +140,17 @@ static void buildCreateTableJson(SSchemaWrapper* schemaRow, SSchemaWrapper* sche cJSON* encodeJson = cJSON_CreateString(encode); RAW_NULL_CHECK(encodeJson); - RAW_FALSE_CHECK(cJSON_AddItemToObject(column, "encode", encodeJson)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(column, "encode", encodeJson)); cJSON* compressJson = cJSON_CreateString(compress); RAW_NULL_CHECK(compressJson); - RAW_FALSE_CHECK(cJSON_AddItemToObject(column, "compress", compressJson)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(column, "compress", compressJson)); cJSON* levelJson = cJSON_CreateString(level); RAW_NULL_CHECK(levelJson); - RAW_FALSE_CHECK(cJSON_AddItemToObject(column, "level", levelJson)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(column, "level", levelJson)); } - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "columns", columns)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "columns", columns)); cJSON* tags = cJSON_CreateArray(); RAW_NULL_CHECK(tags); @@ -144,24 +160,24 @@ static void buildCreateTableJson(SSchemaWrapper* schemaRow, SSchemaWrapper* sche SSchema* s = schemaTag->pSchema + i; cJSON* tname = cJSON_CreateString(s->name); RAW_NULL_CHECK(tname); - RAW_FALSE_CHECK(cJSON_AddItemToObject(tag, "name", tname)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(tag, "name", tname)); cJSON* ttype = cJSON_CreateNumber(s->type); RAW_NULL_CHECK(ttype); - RAW_FALSE_CHECK(cJSON_AddItemToObject(tag, "type", ttype)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(tag, "type", ttype)); if (s->type == TSDB_DATA_TYPE_BINARY || s->type == TSDB_DATA_TYPE_VARBINARY || s->type == TSDB_DATA_TYPE_GEOMETRY) { int32_t length = s->bytes - VARSTR_HEADER_SIZE; cJSON* cbytes = cJSON_CreateNumber(length); RAW_NULL_CHECK(cbytes); - RAW_FALSE_CHECK(cJSON_AddItemToObject(tag, "length", cbytes)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(tag, "length", cbytes)); } else if (s->type == TSDB_DATA_TYPE_NCHAR) { int32_t length = (s->bytes - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE; cJSON* cbytes = cJSON_CreateNumber(length); RAW_NULL_CHECK(cbytes); - RAW_FALSE_CHECK(cJSON_AddItemToObject(tag, "length", cbytes)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(tag, "length", cbytes)); } - RAW_FALSE_CHECK(cJSON_AddItemToArray(tags, tag)); + RAW_FALSE_CHECK(tmqAddJsonArrayItem(tags, tag)); } - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "tags", tags)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tags", tags)); end: *pJson = json; @@ -175,7 +191,7 @@ static int32_t setCompressOption(cJSON* json, uint32_t para) { RAW_NULL_CHECK(encodeStr); cJSON* encodeJson = cJSON_CreateString(encodeStr); RAW_NULL_CHECK(encodeJson); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "encode", encodeJson)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "encode", encodeJson)); return code; } uint8_t compress = COMPRESS_L2_TYPE_U32(para); @@ -184,7 +200,7 @@ static int32_t setCompressOption(cJSON* json, uint32_t para) { RAW_NULL_CHECK(compressStr); cJSON* compressJson = cJSON_CreateString(compressStr); RAW_NULL_CHECK(compressJson); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "compress", compressJson)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "compress", compressJson)); return code; } uint8_t level = COMPRESS_L2_TYPE_LEVEL_U32(para); @@ -193,7 +209,7 @@ static int32_t setCompressOption(cJSON* json, uint32_t para) { RAW_NULL_CHECK(levelStr); cJSON* levelJson = cJSON_CreateString(levelStr); RAW_NULL_CHECK(levelJson); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "level", levelJson)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "level", levelJson)); return code; } @@ -214,19 +230,19 @@ static void buildAlterSTableJson(void* alterData, int32_t alterDataLen, cJSON** RAW_NULL_CHECK(json); cJSON* type = cJSON_CreateString("alter"); RAW_NULL_CHECK(type); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "type", type)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "type", type)); SName name = {0}; RAW_RETURN_CHECK(tNameFromString(&name, req.name, T_NAME_ACCT | T_NAME_DB | T_NAME_TABLE)); cJSON* tableType = cJSON_CreateString("super"); RAW_NULL_CHECK(tableType); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "tableType", tableType)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tableType", tableType)); cJSON* tableName = cJSON_CreateString(name.tname); RAW_NULL_CHECK(tableName); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "tableName", tableName)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tableName", tableName)); cJSON* alterType = cJSON_CreateNumber(req.alterType); RAW_NULL_CHECK(alterType); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "alterType", alterType)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "alterType", alterType)); switch (req.alterType) { case TSDB_ALTER_TABLE_ADD_TAG: case TSDB_ALTER_TABLE_ADD_COLUMN: { @@ -234,22 +250,22 @@ static void buildAlterSTableJson(void* alterData, int32_t alterDataLen, cJSON** RAW_NULL_CHECK(field); cJSON* colName = cJSON_CreateString(field->name); RAW_NULL_CHECK(colName); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colName", colName)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colName", colName)); cJSON* colType = cJSON_CreateNumber(field->type); RAW_NULL_CHECK(colType); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colType", colType)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colType", colType)); if (field->type == TSDB_DATA_TYPE_BINARY || field->type == TSDB_DATA_TYPE_VARBINARY || field->type == TSDB_DATA_TYPE_GEOMETRY) { int32_t length = field->bytes - VARSTR_HEADER_SIZE; cJSON* cbytes = cJSON_CreateNumber(length); RAW_NULL_CHECK(cbytes); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colLength", cbytes)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colLength", cbytes)); } else if (field->type == TSDB_DATA_TYPE_NCHAR) { int32_t length = (field->bytes - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE; cJSON* cbytes = cJSON_CreateNumber(length); RAW_NULL_CHECK(cbytes); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colLength", cbytes)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colLength", cbytes)); } break; } @@ -258,22 +274,22 @@ static void buildAlterSTableJson(void* alterData, int32_t alterDataLen, cJSON** RAW_NULL_CHECK(field); cJSON* colName = cJSON_CreateString(field->name); RAW_NULL_CHECK(colName); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colName", colName)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colName", colName)); cJSON* colType = cJSON_CreateNumber(field->type); RAW_NULL_CHECK(colType); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colType", colType)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colType", colType)); if (field->type == TSDB_DATA_TYPE_BINARY || field->type == TSDB_DATA_TYPE_VARBINARY || field->type == TSDB_DATA_TYPE_GEOMETRY) { int32_t length = field->bytes - VARSTR_HEADER_SIZE; cJSON* cbytes = cJSON_CreateNumber(length); RAW_NULL_CHECK(cbytes); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colLength", cbytes)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colLength", cbytes)); } else if (field->type == TSDB_DATA_TYPE_NCHAR) { int32_t length = (field->bytes - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE; cJSON* cbytes = cJSON_CreateNumber(length); RAW_NULL_CHECK(cbytes); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colLength", cbytes)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colLength", cbytes)); } RAW_RETURN_CHECK(setCompressOption(json, field->compress)); break; @@ -284,7 +300,7 @@ static void buildAlterSTableJson(void* alterData, int32_t alterDataLen, cJSON** RAW_NULL_CHECK(field); cJSON* colName = cJSON_CreateString(field->name); RAW_NULL_CHECK(colName); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colName", colName)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colName", colName)); break; } case TSDB_ALTER_TABLE_UPDATE_TAG_BYTES: @@ -293,21 +309,21 @@ static void buildAlterSTableJson(void* alterData, int32_t alterDataLen, cJSON** RAW_NULL_CHECK(field); cJSON* colName = cJSON_CreateString(field->name); RAW_NULL_CHECK(colName); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colName", colName)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colName", colName)); cJSON* colType = cJSON_CreateNumber(field->type); RAW_NULL_CHECK(colType); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colType", colType)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colType", colType)); if (field->type == TSDB_DATA_TYPE_BINARY || field->type == TSDB_DATA_TYPE_VARBINARY || field->type == TSDB_DATA_TYPE_GEOMETRY) { int32_t length = field->bytes - VARSTR_HEADER_SIZE; cJSON* cbytes = cJSON_CreateNumber(length); RAW_NULL_CHECK(cbytes); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colLength", cbytes)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colLength", cbytes)); } else if (field->type == TSDB_DATA_TYPE_NCHAR) { int32_t length = (field->bytes - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE; cJSON* cbytes = cJSON_CreateNumber(length); RAW_NULL_CHECK(cbytes); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colLength", cbytes)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colLength", cbytes)); } break; } @@ -319,10 +335,10 @@ static void buildAlterSTableJson(void* alterData, int32_t alterDataLen, cJSON** RAW_NULL_CHECK(newField); cJSON* colName = cJSON_CreateString(oldField->name); RAW_NULL_CHECK(colName); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colName", colName)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colName", colName)); cJSON* colNewName = cJSON_CreateString(newField->name); RAW_NULL_CHECK(colNewName); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colNewName", colNewName)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colNewName", colNewName)); break; } case TSDB_ALTER_TABLE_UPDATE_COLUMN_COMPRESS: { @@ -330,7 +346,7 @@ static void buildAlterSTableJson(void* alterData, int32_t alterDataLen, cJSON** RAW_NULL_CHECK(field); cJSON* colName = cJSON_CreateString(field->name); RAW_NULL_CHECK(colName); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colName", colName)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colName", colName)); RAW_RETURN_CHECK(setCompressOption(json, field->bytes)); break; } @@ -392,21 +408,20 @@ static void buildChildElement(cJSON* json, SVCreateTbReq* pCreateReq) { uint8_t tagNum = pCreateReq->ctb.tagNum; int32_t code = 0; cJSON* tags = NULL; + SArray* pTagVals = NULL; cJSON* tableName = cJSON_CreateString(name); RAW_NULL_CHECK(tableName); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "tableName", tableName)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tableName", tableName)); cJSON* using = cJSON_CreateString(sname); RAW_NULL_CHECK(using); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "using", using)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "using", using)); cJSON* tagNumJson = cJSON_CreateNumber(tagNum); RAW_NULL_CHECK(tagNumJson); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "tagNum", tagNumJson)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tagNum", tagNumJson)); tags = cJSON_CreateArray(); RAW_NULL_CHECK(tags); - SArray* pTagVals = NULL; RAW_RETURN_CHECK(tTagToValArray(pTag, &pTagVals)); - if (tTagIsJson(pTag)) { STag* p = (STag*)pTag; if (p->nTag == 0) { @@ -427,14 +442,14 @@ static void buildChildElement(cJSON* json, SVCreateTbReq* pCreateReq) { RAW_NULL_CHECK(ptname); cJSON* tname = cJSON_CreateString(ptname); RAW_NULL_CHECK(tname); - RAW_FALSE_CHECK(cJSON_AddItemToObject(tag, "name", tname)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(tag, "name", tname)); cJSON* ttype = cJSON_CreateNumber(TSDB_DATA_TYPE_JSON); RAW_NULL_CHECK(ttype); - RAW_FALSE_CHECK(cJSON_AddItemToObject(tag, "type", ttype)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(tag, "type", ttype)); cJSON* tvalue = cJSON_CreateString(pJson); RAW_NULL_CHECK(tvalue); - RAW_FALSE_CHECK(cJSON_AddItemToObject(tag, "value", tvalue)); - RAW_FALSE_CHECK(cJSON_AddItemToArray(tags, tag)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(tag, "value", tvalue)); + RAW_FALSE_CHECK(tmqAddJsonArrayItem(tags, tag)); taosMemoryFree(pJson); goto end; } @@ -448,10 +463,10 @@ static void buildChildElement(cJSON* json, SVCreateTbReq* pCreateReq) { RAW_NULL_CHECK(ptname); cJSON* tname = cJSON_CreateString(ptname); RAW_NULL_CHECK(tname); - RAW_FALSE_CHECK(cJSON_AddItemToObject(tag, "name", tname)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(tag, "name", tname)); cJSON* ttype = cJSON_CreateNumber(pTagVal->type); RAW_NULL_CHECK(ttype); - RAW_FALSE_CHECK(cJSON_AddItemToObject(tag, "type", ttype)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(tag, "type", ttype)); cJSON* tvalue = NULL; if (IS_VAR_DATA_TYPE(pTagVal->type)) { @@ -481,12 +496,12 @@ static void buildChildElement(cJSON* json, SVCreateTbReq* pCreateReq) { RAW_NULL_CHECK(tvalue); } - RAW_FALSE_CHECK(cJSON_AddItemToObject(tag, "value", tvalue)); - RAW_FALSE_CHECK(cJSON_AddItemToArray(tags, tag)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(tag, "value", tvalue)); + RAW_FALSE_CHECK(tmqAddJsonArrayItem(tags, tag)); } + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tags", tags)); end: - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "tags", tags)); taosArrayDestroy(pTagVals); } @@ -497,11 +512,11 @@ static void buildCreateCTableJson(SVCreateTbReq* pCreateReq, int32_t nReqs, cJSO RAW_NULL_CHECK(json); cJSON* type = cJSON_CreateString("create"); RAW_NULL_CHECK(type); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "type", type)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "type", type)); cJSON* tableType = cJSON_CreateString("child"); RAW_NULL_CHECK(tableType); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "tableType", tableType)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tableType", tableType)); buildChildElement(json, pCreateReq); cJSON* createList = cJSON_CreateArray(); @@ -510,9 +525,9 @@ static void buildCreateCTableJson(SVCreateTbReq* pCreateReq, int32_t nReqs, cJSO cJSON* create = cJSON_CreateObject(); RAW_NULL_CHECK(create); buildChildElement(create, pCreateReq + i); - RAW_FALSE_CHECK(cJSON_AddItemToArray(createList, create)); + RAW_FALSE_CHECK(tmqAddJsonArrayItem(createList, create)); } - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "createList", createList)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "createList", createList)); end: *pJson = json; @@ -619,62 +634,62 @@ static void processAlterTable(SMqMetaRsp* metaRsp, cJSON** pJson) { RAW_NULL_CHECK(json); cJSON* type = cJSON_CreateString("alter"); RAW_NULL_CHECK(type); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "type", type)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "type", type)); cJSON* tableType = cJSON_CreateString(vAlterTbReq.action == TSDB_ALTER_TABLE_UPDATE_TAG_VAL || vAlterTbReq.action == TSDB_ALTER_TABLE_UPDATE_MULTI_TAG_VAL ? "child" : "normal"); RAW_NULL_CHECK(tableType); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "tableType", tableType)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tableType", tableType)); cJSON* tableName = cJSON_CreateString(vAlterTbReq.tbName); RAW_NULL_CHECK(tableName); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "tableName", tableName)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tableName", tableName)); cJSON* alterType = cJSON_CreateNumber(vAlterTbReq.action); RAW_NULL_CHECK(alterType); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "alterType", alterType)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "alterType", alterType)); switch (vAlterTbReq.action) { case TSDB_ALTER_TABLE_ADD_COLUMN: { cJSON* colName = cJSON_CreateString(vAlterTbReq.colName); RAW_NULL_CHECK(colName); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colName", colName)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colName", colName)); cJSON* colType = cJSON_CreateNumber(vAlterTbReq.type); RAW_NULL_CHECK(colType); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colType", colType)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colType", colType)); if (vAlterTbReq.type == TSDB_DATA_TYPE_BINARY || vAlterTbReq.type == TSDB_DATA_TYPE_VARBINARY || vAlterTbReq.type == TSDB_DATA_TYPE_GEOMETRY) { int32_t length = vAlterTbReq.bytes - VARSTR_HEADER_SIZE; cJSON* cbytes = cJSON_CreateNumber(length); RAW_NULL_CHECK(cbytes); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colLength", cbytes)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colLength", cbytes)); } else if (vAlterTbReq.type == TSDB_DATA_TYPE_NCHAR) { int32_t length = (vAlterTbReq.bytes - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE; cJSON* cbytes = cJSON_CreateNumber(length); RAW_NULL_CHECK(cbytes); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colLength", cbytes)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colLength", cbytes)); } break; } case TSDB_ALTER_TABLE_ADD_COLUMN_WITH_COMPRESS_OPTION: { cJSON* colName = cJSON_CreateString(vAlterTbReq.colName); RAW_NULL_CHECK(colName); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colName", colName)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colName", colName)); cJSON* colType = cJSON_CreateNumber(vAlterTbReq.type); RAW_NULL_CHECK(colType); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colType", colType)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colType", colType)); if (vAlterTbReq.type == TSDB_DATA_TYPE_BINARY || vAlterTbReq.type == TSDB_DATA_TYPE_VARBINARY || vAlterTbReq.type == TSDB_DATA_TYPE_GEOMETRY) { int32_t length = vAlterTbReq.bytes - VARSTR_HEADER_SIZE; cJSON* cbytes = cJSON_CreateNumber(length); RAW_NULL_CHECK(cbytes); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colLength", cbytes)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colLength", cbytes)); } else if (vAlterTbReq.type == TSDB_DATA_TYPE_NCHAR) { int32_t length = (vAlterTbReq.bytes - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE; cJSON* cbytes = cJSON_CreateNumber(length); RAW_NULL_CHECK(cbytes); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colLength", cbytes)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colLength", cbytes)); } RAW_RETURN_CHECK(setCompressOption(json, vAlterTbReq.compress)); break; @@ -682,43 +697,43 @@ static void processAlterTable(SMqMetaRsp* metaRsp, cJSON** pJson) { case TSDB_ALTER_TABLE_DROP_COLUMN: { cJSON* colName = cJSON_CreateString(vAlterTbReq.colName); RAW_NULL_CHECK(colName); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colName", colName)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colName", colName)); break; } case TSDB_ALTER_TABLE_UPDATE_COLUMN_BYTES: { cJSON* colName = cJSON_CreateString(vAlterTbReq.colName); RAW_NULL_CHECK(colName); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colName", colName)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colName", colName)); cJSON* colType = cJSON_CreateNumber(vAlterTbReq.colModType); RAW_NULL_CHECK(colType); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colType", colType)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colType", colType)); if (vAlterTbReq.colModType == TSDB_DATA_TYPE_BINARY || vAlterTbReq.colModType == TSDB_DATA_TYPE_VARBINARY || vAlterTbReq.colModType == TSDB_DATA_TYPE_GEOMETRY) { int32_t length = vAlterTbReq.colModBytes - VARSTR_HEADER_SIZE; cJSON* cbytes = cJSON_CreateNumber(length); RAW_NULL_CHECK(cbytes); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colLength", cbytes)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colLength", cbytes)); } else if (vAlterTbReq.colModType == TSDB_DATA_TYPE_NCHAR) { int32_t length = (vAlterTbReq.colModBytes - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE; cJSON* cbytes = cJSON_CreateNumber(length); RAW_NULL_CHECK(cbytes); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colLength", cbytes)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colLength", cbytes)); } break; } case TSDB_ALTER_TABLE_UPDATE_COLUMN_NAME: { cJSON* colName = cJSON_CreateString(vAlterTbReq.colName); RAW_NULL_CHECK(colName); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colName", colName)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colName", colName)); cJSON* colNewName = cJSON_CreateString(vAlterTbReq.colNewName); RAW_NULL_CHECK(colNewName); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colNewName", colNewName)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colNewName", colNewName)); break; } case TSDB_ALTER_TABLE_UPDATE_TAG_VAL: { cJSON* tagName = cJSON_CreateString(vAlterTbReq.tagName); RAW_NULL_CHECK(tagName); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colName", tagName)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colName", tagName)); bool isNull = vAlterTbReq.isNull; if (vAlterTbReq.tagType == TSDB_DATA_TYPE_JSON) { @@ -757,12 +772,12 @@ static void processAlterTable(SMqMetaRsp* metaRsp, cJSON** pJson) { cJSON* colValue = cJSON_CreateString(buf); taosMemoryFree(buf); RAW_NULL_CHECK(colValue); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colValue", colValue)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colValue", colValue)); } cJSON* isNullCJson = cJSON_CreateBool(isNull); RAW_NULL_CHECK(isNullCJson); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colValueNull", isNullCJson)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colValueNull", isNullCJson)); break; } case TSDB_ALTER_TABLE_UPDATE_MULTI_TAG_VAL: { @@ -781,7 +796,7 @@ static void processAlterTable(SMqMetaRsp* metaRsp, cJSON** pJson) { SMultiTagUpateVal* pTagVal = taosArrayGet(vAlterTbReq.pMultiTag, i); cJSON* tagName = cJSON_CreateString(pTagVal->tagName); RAW_NULL_CHECK(tagName); - RAW_FALSE_CHECK(cJSON_AddItemToObject(member, "colName", tagName)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(member, "colName", tagName)); if (pTagVal->tagType == TSDB_DATA_TYPE_JSON) { uError("processAlterTable isJson false"); @@ -806,21 +821,21 @@ static void processAlterTable(SMqMetaRsp* metaRsp, cJSON** pJson) { cJSON* colValue = cJSON_CreateString(buf); taosMemoryFree(buf); RAW_NULL_CHECK(colValue); - RAW_FALSE_CHECK(cJSON_AddItemToObject(member, "colValue", colValue)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(member, "colValue", colValue)); } cJSON* isNullCJson = cJSON_CreateBool(isNull); RAW_NULL_CHECK(isNullCJson); - RAW_FALSE_CHECK(cJSON_AddItemToObject(member, "colValueNull", isNullCJson)); - RAW_FALSE_CHECK(cJSON_AddItemToArray(tags, member)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(member, "colValueNull", isNullCJson)); + RAW_FALSE_CHECK(tmqAddJsonArrayItem(tags, member)); } - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "tags", tags)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tags", tags)); break; } case TSDB_ALTER_TABLE_UPDATE_COLUMN_COMPRESS: { cJSON* colName = cJSON_CreateString(vAlterTbReq.colName); RAW_NULL_CHECK(colName); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "colName", colName)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "colName", colName)); RAW_RETURN_CHECK(setCompressOption(json, vAlterTbReq.compress)); break; } @@ -858,13 +873,13 @@ static void processDropSTable(SMqMetaRsp* metaRsp, cJSON** pJson) { RAW_NULL_CHECK(json); cJSON* type = cJSON_CreateString("drop"); RAW_NULL_CHECK(type); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "type", type)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "type", type)); cJSON* tableType = cJSON_CreateString("super"); RAW_NULL_CHECK(tableType); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "tableType", tableType)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tableType", tableType)); cJSON* tableName = cJSON_CreateString(req.name); RAW_NULL_CHECK(tableName); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "tableName", tableName)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tableName", tableName)); end: uDebug("processDropSTable return"); @@ -897,10 +912,10 @@ static void processDeleteTable(SMqMetaRsp* metaRsp, cJSON** pJson) { RAW_NULL_CHECK(json); cJSON* type = cJSON_CreateString("delete"); RAW_NULL_CHECK(type); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "type", type)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "type", type)); cJSON* sqlJson = cJSON_CreateString(sql); RAW_NULL_CHECK(sqlJson); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "sql", sqlJson)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "sql", sqlJson)); end: uDebug("processDeleteTable return"); @@ -928,16 +943,16 @@ static void processDropTable(SMqMetaRsp* metaRsp, cJSON** pJson) { RAW_NULL_CHECK(json); cJSON* type = cJSON_CreateString("drop"); RAW_NULL_CHECK(type); - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "type", type)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "type", type)); cJSON* tableNameList = cJSON_CreateArray(); RAW_NULL_CHECK(tableNameList); for (int32_t iReq = 0; iReq < req.nReqs; iReq++) { SVDropTbReq* pDropTbReq = req.pReqs + iReq; cJSON* tableName = cJSON_CreateString(pDropTbReq->name); RAW_NULL_CHECK(tableName); - RAW_FALSE_CHECK(cJSON_AddItemToArray(tableNameList, tableName)); + RAW_FALSE_CHECK(tmqAddJsonArrayItem(tableNameList, tableName)); } - RAW_FALSE_CHECK(cJSON_AddItemToObject(json, "tableNameList", tableNameList)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tableNameList", tableNameList)); end: uDebug("processDropTable return"); @@ -2198,10 +2213,10 @@ static void processBatchMetaToJson(SMqBatchMetaRsp* pMsgRsp, char** string) { cJSON* pItem = NULL; processSimpleMeta(&metaRsp, &pItem); tDeleteMqMetaRsp(&metaRsp); - RAW_FALSE_CHECK(cJSON_AddItemToArray(pMetaArr, pItem)); + RAW_FALSE_CHECK(tmqAddJsonArrayItem(pMetaArr, pItem)); } - RAW_FALSE_CHECK(cJSON_AddItemToObject(pJson, "metas", pMetaArr)); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(pJson, "metas", pMetaArr)); tDeleteMqBatchMetaRsp(&rsp); char* fullStr = cJSON_PrintUnformatted(pJson); cJSON_Delete(pJson); From a7a25b93fdad23a1996cffae7c55700d2fe9d998 Mon Sep 17 00:00:00 2001 From: dmchen Date: Tue, 3 Dec 2024 09:53:46 +0800 Subject: [PATCH 49/62] fix/exit-fail-retry-when-follower --- source/dnode/mnode/impl/src/mndTrans.c | 74 +++++++++++++++----------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/source/dnode/mnode/impl/src/mndTrans.c b/source/dnode/mnode/impl/src/mndTrans.c index 4268d73746..0a1d0770dd 100644 --- a/source/dnode/mnode/impl/src/mndTrans.c +++ b/source/dnode/mnode/impl/src/mndTrans.c @@ -52,10 +52,17 @@ static bool mndTransPerformCommitStage(SMnode *pMnode, STrans *pTrans, bool t static bool mndTransPerformRollbackStage(SMnode *pMnode, STrans *pTrans, bool topHalf); static bool mndTransPerformFinishStage(SMnode *pMnode, STrans *pTrans, bool topHalf); -static bool mndCannotExecuteTransAction(SMnode *pMnode, bool topHalf) { - return (!pMnode->deploy && !mndIsLeader(pMnode)) || !topHalf; +static inline bool mndTransIsInSyncContext(bool topHalf) { return !topHalf; } + +static bool mndCannotExecuteTrans(SMnode *pMnode, bool topHalf) { + bool isLeader = mndIsLeader(pMnode); + bool ret = (!pMnode->deploy && !isLeader) || mndTransIsInSyncContext(topHalf); + if (ret) mDebug("cannot execute trans action, deploy:%d, isLeader:%d, topHalf:%d", pMnode->deploy, isLeader, topHalf); + return ret; } +static inline char *mndStrExecutionContext(bool topHalf) { return topHalf ? "transContext" : "syncContext"; } + static void mndTransSendRpcRsp(SMnode *pMnode, STrans *pTrans); static int32_t mndProcessTransTimer(SRpcMsg *pReq); static int32_t mndProcessTtl(SRpcMsg *pReq); @@ -1339,7 +1346,7 @@ static int32_t mndTransWriteSingleLog(SMnode *pMnode, STrans *pTrans, STransActi // execute in trans context static int32_t mndTransSendSingleMsg(SMnode *pMnode, STrans *pTrans, STransAction *pAction, bool topHalf) { if (pAction->msgSent) return 0; - if (mndCannotExecuteTransAction(pMnode, topHalf)) { + if (mndCannotExecuteTrans(pMnode, topHalf)) { TAOS_RETURN(TSDB_CODE_MND_TRANS_CTX_SWITCH); } @@ -1485,8 +1492,8 @@ static int32_t mndTransExecuteActions(SMnode *pMnode, STrans *pTrans, SArray *pA static int32_t mndTransExecuteRedoActions(SMnode *pMnode, STrans *pTrans, bool topHalf) { int32_t code = mndTransExecuteActions(pMnode, pTrans, pTrans->redoActions, topHalf); if (code != 0 && code != TSDB_CODE_ACTION_IN_PROGRESS && code != TSDB_CODE_MND_TRANS_CTX_SWITCH) { - mError("trans:%d, failed to execute redoActions since:%s, code:0x%x, topHalf(TransContext):%d", pTrans->id, - terrstr(), terrno, topHalf); + mError("trans:%d, failed to execute redoActions since:%s, code:0x%x, in %s", pTrans->id, terrstr(), terrno, + mndStrExecutionContext(topHalf)); } return code; } @@ -1494,8 +1501,8 @@ static int32_t mndTransExecuteRedoActions(SMnode *pMnode, STrans *pTrans, bool t static int32_t mndTransExecuteUndoActions(SMnode *pMnode, STrans *pTrans, bool topHalf) { int32_t code = mndTransExecuteActions(pMnode, pTrans, pTrans->undoActions, topHalf); if (code != 0 && code != TSDB_CODE_ACTION_IN_PROGRESS && code != TSDB_CODE_MND_TRANS_CTX_SWITCH) { - mError("trans:%d, failed to execute undoActions since %s. topHalf(TransContext):%d", pTrans->id, terrstr(), - topHalf); + mError("trans:%d, failed to execute undoActions since %s. in %s", pTrans->id, terrstr(), + mndStrExecutionContext(topHalf)); } return code; } @@ -1503,8 +1510,8 @@ static int32_t mndTransExecuteUndoActions(SMnode *pMnode, STrans *pTrans, bool t static int32_t mndTransExecuteCommitActions(SMnode *pMnode, STrans *pTrans, bool topHalf) { int32_t code = mndTransExecuteActions(pMnode, pTrans, pTrans->commitActions, topHalf); if (code != 0 && code != TSDB_CODE_ACTION_IN_PROGRESS && code != TSDB_CODE_MND_TRANS_CTX_SWITCH) { - mError("trans:%d, failed to execute commitActions since %s. topHalf(TransContext):%d", pTrans->id, terrstr(), - topHalf); + mError("trans:%d, failed to execute commitActions since %s. in %s", pTrans->id, terrstr(), + mndStrExecutionContext(topHalf)); } return code; } @@ -1524,7 +1531,7 @@ static int32_t mndTransExecuteActionsSerial(SMnode *pMnode, STrans *pTrans, SArr for (int32_t action = pTrans->actionPos; action < numOfActions; ++action) { STransAction *pAction = taosArrayGet(pActions, action); - mInfo("trans:%d, current action:%d, stage:%s, actionType(0:log,1:msg):%d", pTrans->id, pTrans->actionPos, + mInfo("trans:%d, current action:%d, stage:%s, actionType(1:msg,2:log):%d", pTrans->id, pTrans->actionPos, mndTransStr(pAction->stage), pAction->actionType); code = mndTransExecSingleAction(pMnode, pTrans, pAction, topHalf); @@ -1555,11 +1562,11 @@ static int32_t mndTransExecuteActionsSerial(SMnode *pMnode, STrans *pTrans, SArr } mndSetTransLastAction(pTrans, pAction); - if (mndCannotExecuteTransAction(pMnode, topHalf)) { + if (mndCannotExecuteTrans(pMnode, topHalf)) { pTrans->lastErrorNo = code; pTrans->code = code; - mInfo("trans:%d, %s:%d, topHalf(TransContext):%d, not execute next action, code:%s", pTrans->id, - mndTransStr(pAction->stage), action, topHalf, tstrerror(code)); + mInfo("trans:%d, %s:%d, cannot execute next action in %s, code:%s", pTrans->id, mndTransStr(pAction->stage), + action, mndStrExecutionContext(topHalf), tstrerror(code)); break; } @@ -1660,21 +1667,25 @@ static bool mndTransPerformRedoActionStage(SMnode *pMnode, STrans *pTrans, bool code = mndTransExecuteRedoActions(pMnode, pTrans, topHalf); } - if (mndCannotExecuteTransAction(pMnode, topHalf)) { + if (code != 0 && code != TSDB_CODE_MND_TRANS_CTX_SWITCH && mndTransIsInSyncContext(topHalf)) { pTrans->lastErrorNo = code; pTrans->code = code; - bool continueExec = true; - if (code != 0 && code != TSDB_CODE_MND_TRANS_CTX_SWITCH) { - taosMsleep(100); - continueExec = true; - } else { - continueExec = false; + mInfo( + "trans:%d, failed to execute, will retry redo action stage in 100 ms , in %s, " + "continueExec:%d, code:%s", + pTrans->id, mndStrExecutionContext(topHalf), continueExec, tstrerror(code)); + taosMsleep(100); + return true; + } else { + if (mndCannotExecuteTrans(pMnode, topHalf)) { + mInfo("trans:%d, cannot continue to execute redo action stage in %s, continueExec:%d, code:%s", pTrans->id, + mndStrExecutionContext(topHalf), continueExec, tstrerror(code)); + return false; } - mInfo("trans:%d, cannot execute redo action stage, topHalf(TransContext):%d, continueExec:%d, code:%s", pTrans->id, - topHalf, continueExec, tstrerror(code)); - - return continueExec; } + + // if (mndCannotExecuteTrans(pMnode, topHalf)) return false; + terrno = code; if (code == 0) { @@ -1716,9 +1727,9 @@ static bool mndTransPerformRedoActionStage(SMnode *pMnode, STrans *pTrans, bool return continueExec; } -// in trans context +// execute in trans context static bool mndTransPerformCommitStage(SMnode *pMnode, STrans *pTrans, bool topHalf) { - if (mndCannotExecuteTransAction(pMnode, topHalf)) return false; + if (mndCannotExecuteTrans(pMnode, topHalf)) return false; bool continueExec = true; int32_t code = mndTransCommit(pMnode, pTrans); @@ -1772,7 +1783,7 @@ static bool mndTransPerformUndoActionStage(SMnode *pMnode, STrans *pTrans, bool code = mndTransExecuteUndoActions(pMnode, pTrans, topHalf); } - if (mndCannotExecuteTransAction(pMnode, topHalf)) return false; + if (mndCannotExecuteTrans(pMnode, topHalf)) return false; terrno = code; if (code == 0) { @@ -1793,7 +1804,7 @@ static bool mndTransPerformUndoActionStage(SMnode *pMnode, STrans *pTrans, bool // in trans context static bool mndTransPerformRollbackStage(SMnode *pMnode, STrans *pTrans, bool topHalf) { - if (mndCannotExecuteTransAction(pMnode, topHalf)) return false; + if (mndCannotExecuteTrans(pMnode, topHalf)) return false; bool continueExec = true; int32_t code = mndTransRollback(pMnode, pTrans); @@ -1810,8 +1821,9 @@ static bool mndTransPerformRollbackStage(SMnode *pMnode, STrans *pTrans, bool to return continueExec; } +// excute in trans context static bool mndTransPerformPreFinishStage(SMnode *pMnode, STrans *pTrans, bool topHalf) { - if (mndCannotExecuteTransAction(pMnode, topHalf)) return false; + if (mndCannotExecuteTrans(pMnode, topHalf)) return false; bool continueExec = true; int32_t code = mndTransPreFinish(pMnode, pTrans); @@ -1854,8 +1866,8 @@ void mndTransExecuteImp(SMnode *pMnode, STrans *pTrans, bool topHalf) { bool continueExec = true; while (continueExec) { - mInfo("trans:%d, continue to execute, stage:%s createTime:%" PRId64 " topHalf(TransContext):%d", pTrans->id, - mndTransStr(pTrans->stage), pTrans->createdTime, topHalf); + mInfo("trans:%d, continue to execute stage:%s in %s, createTime:%" PRId64 "", pTrans->id, + mndTransStr(pTrans->stage), mndStrExecutionContext(topHalf), pTrans->createdTime); pTrans->lastExecTime = taosGetTimestampMs(); switch (pTrans->stage) { case TRN_STAGE_PREPARE: From 41140195803a24a50ce5f82c15e5d9148bc1038d Mon Sep 17 00:00:00 2001 From: dmchen Date: Tue, 3 Dec 2024 09:58:14 +0800 Subject: [PATCH 50/62] fix/exit-fail-retry-when-follower --- source/dnode/mnode/impl/src/mndTrans.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/source/dnode/mnode/impl/src/mndTrans.c b/source/dnode/mnode/impl/src/mndTrans.c index 0a1d0770dd..ae5da415a2 100644 --- a/source/dnode/mnode/impl/src/mndTrans.c +++ b/source/dnode/mnode/impl/src/mndTrans.c @@ -1683,9 +1683,6 @@ static bool mndTransPerformRedoActionStage(SMnode *pMnode, STrans *pTrans, bool return false; } } - - // if (mndCannotExecuteTrans(pMnode, topHalf)) return false; - terrno = code; if (code == 0) { From 5028191796b7dfe298fb23a661d8c00f23973e32 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Mon, 9 Dec 2024 07:56:30 +0000 Subject: [PATCH 51/62] enh: add test cases for osAtomic and osDir --- include/os/osAtomic.h | 20 +- source/os/src/osAtomic.c | 37 ++- source/os/src/osDir.c | 66 ++--- source/os/test/CMakeLists.txt | 7 + source/os/test/osAtomicTests.cpp | 479 ++++++++++++++++++++++++++----- source/os/test/osDirTests.cpp | 448 +++++++++++++++++++++++++++++ 6 files changed, 923 insertions(+), 134 deletions(-) create mode 100644 source/os/test/osDirTests.cpp diff --git a/include/os/osAtomic.h b/include/os/osAtomic.h index 97bb6f53ba..d595c687b7 100644 --- a/include/os/osAtomic.h +++ b/include/os/osAtomic.h @@ -48,13 +48,13 @@ void atomic_store_8(int8_t volatile *ptr, int8_t val); void atomic_store_16(int16_t volatile *ptr, int16_t val); void atomic_store_32(int32_t volatile *ptr, int32_t val); void atomic_store_64(int64_t volatile *ptr, int64_t val); -double atomic_store_double(double volatile *ptr, double val); +void atomic_store_double(double volatile *ptr, double val); void atomic_store_ptr(void *ptr, void *val); int8_t atomic_exchange_8(int8_t volatile *ptr, int8_t val); int16_t atomic_exchange_16(int16_t volatile *ptr, int16_t val); int32_t atomic_exchange_32(int32_t volatile *ptr, int32_t val); int64_t atomic_exchange_64(int64_t volatile *ptr, int64_t val); -double atomic_exchange_double(double volatile *ptr, int64_t val); +double atomic_exchange_double(double volatile *ptr, double val); void *atomic_exchange_ptr(void *ptr, void *val); int8_t atomic_val_compare_exchange_8(int8_t volatile *ptr, int8_t oldval, int8_t newval); int16_t atomic_val_compare_exchange_16(int16_t volatile *ptr, int16_t oldval, int16_t newval); @@ -71,7 +71,7 @@ int16_t atomic_fetch_add_16(int16_t volatile *ptr, int16_t val); int32_t atomic_fetch_add_32(int32_t volatile *ptr, int32_t val); int64_t atomic_fetch_add_64(int64_t volatile *ptr, int64_t val); double atomic_fetch_add_double(double volatile *ptr, double val); -void *atomic_fetch_add_ptr(void *ptr, void *val); +void *atomic_fetch_add_ptr(void *ptr, int64_t val); int8_t atomic_sub_fetch_8(int8_t volatile *ptr, int8_t val); int16_t atomic_sub_fetch_16(int16_t volatile *ptr, int16_t val); int32_t atomic_sub_fetch_32(int32_t volatile *ptr, int32_t val); @@ -82,37 +82,37 @@ int16_t atomic_fetch_sub_16(int16_t volatile *ptr, int16_t val); int32_t atomic_fetch_sub_32(int32_t volatile *ptr, int32_t val); int64_t atomic_fetch_sub_64(int64_t volatile *ptr, int64_t val); double atomic_fetch_sub_double(double volatile *ptr, double val); -void *atomic_fetch_sub_ptr(void *ptr, void *val); +void *atomic_fetch_sub_ptr(void *ptr, int64_t val); int8_t atomic_and_fetch_8(int8_t volatile *ptr, int8_t val); int16_t atomic_and_fetch_16(int16_t volatile *ptr, int16_t val); int32_t atomic_and_fetch_32(int32_t volatile *ptr, int32_t val); int64_t atomic_and_fetch_64(int64_t volatile *ptr, int64_t val); -void *atomic_and_fetch_ptr(void *ptr, void *val); +void *atomic_and_fetch_ptr(void *ptr, int64_t val); int8_t atomic_fetch_and_8(int8_t volatile *ptr, int8_t val); int16_t atomic_fetch_and_16(int16_t volatile *ptr, int16_t val); int32_t atomic_fetch_and_32(int32_t volatile *ptr, int32_t val); int64_t atomic_fetch_and_64(int64_t volatile *ptr, int64_t val); -void *atomic_fetch_and_ptr(void *ptr, void *val); +void *atomic_fetch_and_ptr(void *ptr, int64_t val); int8_t atomic_or_fetch_8(int8_t volatile *ptr, int8_t val); int16_t atomic_or_fetch_16(int16_t volatile *ptr, int16_t val); int32_t atomic_or_fetch_32(int32_t volatile *ptr, int32_t val); int64_t atomic_or_fetch_64(int64_t volatile *ptr, int64_t val); -void *atomic_or_fetch_ptr(void *ptr, void *val); +void *atomic_or_fetch_ptr(void *ptr, int64_t val); int8_t atomic_fetch_or_8(int8_t volatile *ptr, int8_t val); int16_t atomic_fetch_or_16(int16_t volatile *ptr, int16_t val); int32_t atomic_fetch_or_32(int32_t volatile *ptr, int32_t val); int64_t atomic_fetch_or_64(int64_t volatile *ptr, int64_t val); -void *atomic_fetch_or_ptr(void *ptr, void *val); +void *atomic_fetch_or_ptr(void *ptr, int64_t val); int8_t atomic_xor_fetch_8(int8_t volatile *ptr, int8_t val); int16_t atomic_xor_fetch_16(int16_t volatile *ptr, int16_t val); int32_t atomic_xor_fetch_32(int32_t volatile *ptr, int32_t val); int64_t atomic_xor_fetch_64(int64_t volatile *ptr, int64_t val); -void *atomic_xor_fetch_ptr(void *ptr, void *val); +void *atomic_xor_fetch_ptr(void *ptr, int64_t val); int8_t atomic_fetch_xor_8(int8_t volatile *ptr, int8_t val); int16_t atomic_fetch_xor_16(int16_t volatile *ptr, int16_t val); int32_t atomic_fetch_xor_32(int32_t volatile *ptr, int32_t val); int64_t atomic_fetch_xor_64(int64_t volatile *ptr, int64_t val); -void *atomic_fetch_xor_ptr(void *ptr, void *val); +void *atomic_fetch_xor_ptr(void *ptr, int64_t val); #ifdef _MSC_VER #define tmemory_barrier(order) MemoryBarrier() diff --git a/source/os/src/osAtomic.c b/source/os/src/osAtomic.c index c891ee4579..5da2307cb3 100644 --- a/source/os/src/osAtomic.c +++ b/source/os/src/osAtomic.c @@ -19,7 +19,6 @@ typedef union { volatile int64_t i; volatile double d; - //double d; } double_number; #ifdef WINDOWS @@ -345,7 +344,7 @@ void atomic_store_64(int64_t volatile* ptr, int64_t val) { #endif } -double atomic_store_double(double volatile *ptr, double val){ +void atomic_store_double(double volatile* ptr, double val) { for (;;) { double_number old_num = {0}; old_num.d = *ptr; // current old value @@ -354,9 +353,9 @@ double atomic_store_double(double volatile *ptr, double val){ new_num.d = val; double_number ret_num = {0}; - ret_num.i = atomic_val_compare_exchange_64((volatile int64_t *)ptr, old_num.i, new_num.i); + ret_num.i = atomic_val_compare_exchange_64((volatile int64_t*)ptr, old_num.i, new_num.i); - if (ret_num.i == old_num.i) return ret_num.d; + if (ret_num.i == old_num.i) return; } } @@ -414,16 +413,16 @@ int64_t atomic_exchange_64(int64_t volatile* ptr, int64_t val) { #endif } -double atomic_exchange_double(double volatile *ptr, int64_t val){ +double atomic_exchange_double(double volatile* ptr, double val) { for (;;) { double_number old_num = {0}; old_num.d = *ptr; // current old value double_number new_num = {0}; - int64_t iNew = val; + new_num.d = val; double_number ret_num = {0}; - ret_num.i = atomic_val_compare_exchange_64((volatile int64_t *)ptr, old_num.i, new_num.i); + ret_num.i = atomic_val_compare_exchange_64((volatile int64_t*)ptr, old_num.i, new_num.i); if (ret_num.i == old_num.i) { return ret_num.d; @@ -589,7 +588,7 @@ int64_t atomic_fetch_add_64(int64_t volatile* ptr, int64_t val) { #endif } -double atomic_fetch_add_double(double volatile *ptr, double val){ +double atomic_fetch_add_double(double volatile* ptr, double val) { for (;;) { double_number old_num = {0}; old_num.d = *ptr; // current old value @@ -598,13 +597,13 @@ double atomic_fetch_add_double(double volatile *ptr, double val){ new_num.d = old_num.d + val; double_number ret_num = {0}; - ret_num.i = atomic_val_compare_exchange_64((volatile int64_t *)ptr, old_num.i, new_num.i); + ret_num.i = atomic_val_compare_exchange_64((volatile int64_t*)ptr, old_num.i, new_num.i); if (ret_num.i == old_num.i) return ret_num.d; } } -void* atomic_fetch_add_ptr(void* ptr, void* val) { +void* atomic_fetch_add_ptr(void* ptr, int64_t val) { #ifdef WINDOWS return _InterlockedExchangePointer((void* volatile*)(ptr), (void*)(val)); #elif defined(_TD_NINGSI_60) @@ -710,7 +709,7 @@ int64_t atomic_fetch_sub_64(int64_t volatile* ptr, int64_t val) { #endif } -double atomic_fetch_sub_double(double volatile *ptr, double val){ +double atomic_fetch_sub_double(double volatile* ptr, double val) { for (;;) { double_number old_num = {0}; old_num.d = *ptr; // current old value @@ -719,13 +718,13 @@ double atomic_fetch_sub_double(double volatile *ptr, double val){ new_num.d = old_num.d - val; double_number ret_num = {0}; - ret_num.i = atomic_val_compare_exchange_64((volatile int64_t *)ptr, old_num.i, new_num.i); + ret_num.i = atomic_val_compare_exchange_64((volatile int64_t*)ptr, old_num.i, new_num.i); if (ret_num.i == old_num.i) return ret_num.d; } } -void* atomic_fetch_sub_ptr(void* ptr, void* val) { +void* atomic_fetch_sub_ptr(void* ptr, int64_t val) { #ifdef WINDOWS return interlocked_fetch_sub_ptr(ptr, val); #elif defined(_TD_NINGSI_60) @@ -777,7 +776,7 @@ int64_t atomic_and_fetch_64(int64_t volatile* ptr, int64_t val) { #endif } -void* atomic_and_fetch_ptr(void* ptr, void* val) { +void* atomic_and_fetch_ptr(void* ptr, int64_t val) { #ifdef WINDOWS return interlocked_and_fetch_ptr((void* volatile*)(ptr), (void*)(val)); #elif defined(_TD_NINGSI_60) @@ -829,7 +828,7 @@ int64_t atomic_fetch_and_64(int64_t volatile* ptr, int64_t val) { #endif } -void* atomic_fetch_and_ptr(void* ptr, void* val) { +void* atomic_fetch_and_ptr(void* ptr, int64_t val) { #ifdef WINDOWS return interlocked_fetch_and_ptr((void* volatile*)(ptr), (void*)(val)); #elif defined(_TD_NINGSI_60) @@ -881,7 +880,7 @@ int64_t atomic_or_fetch_64(int64_t volatile* ptr, int64_t val) { #endif } -void* atomic_or_fetch_ptr(void* ptr, void* val) { +void* atomic_or_fetch_ptr(void* ptr, int64_t val) { #ifdef WINDOWS return interlocked_or_fetch_ptr((void* volatile*)(ptr), (void*)(val)); #elif defined(_TD_NINGSI_60) @@ -933,7 +932,7 @@ int64_t atomic_fetch_or_64(int64_t volatile* ptr, int64_t val) { #endif } -void* atomic_fetch_or_ptr(void* ptr, void* val) { +void* atomic_fetch_or_ptr(void* ptr, int64_t val) { #ifdef WINDOWS return interlocked_fetch_or_ptr((void* volatile*)(ptr), (void*)(val)); #elif defined(_TD_NINGSI_60) @@ -985,7 +984,7 @@ int64_t atomic_xor_fetch_64(int64_t volatile* ptr, int64_t val) { #endif } -void* atomic_xor_fetch_ptr(void* ptr, void* val) { +void* atomic_xor_fetch_ptr(void* ptr, int64_t val) { #ifdef WINDOWS return interlocked_xor_fetch_ptr((void* volatile*)(ptr), (void*)(val)); #elif defined(_TD_NINGSI_60) @@ -1037,7 +1036,7 @@ int64_t atomic_fetch_xor_64(int64_t volatile* ptr, int64_t val) { #endif } -void* atomic_fetch_xor_ptr(void* ptr, void* val) { +void* atomic_fetch_xor_ptr(void* ptr, int64_t val) { #ifdef WINDOWS return interlocked_fetch_xor_ptr((void* volatile*)(ptr), (void*)(val)); #elif defined(_TD_NINGSI_60) diff --git a/source/os/src/osDir.c b/source/os/src/osDir.c index 25245d2df9..189ccb8a8d 100644 --- a/source/os/src/osDir.c +++ b/source/os/src/osDir.c @@ -39,7 +39,7 @@ enum { WRDE_SYNTAX /* Shell syntax error. */ }; -int wordexp(char *words, wordexp_t *pwordexp, int flags) { +int32_t wordexp(char *words, wordexp_t *pwordexp, int32_t flags) { pwordexp->we_offs = 0; pwordexp->we_wordc = 1; pwordexp->we_wordv[0] = pwordexp->wordPos; @@ -197,14 +197,10 @@ int32_t taosMulMkDir(const char *dirname) { } } - if (code < 0 && errno == EEXIST) { - return 0; - } - - return code; + return 0; } -int32_t taosMulModeMkDir(const char *dirname, int mode, bool checkAccess) { +int32_t taosMulModeMkDir(const char *dirname, int32_t mode, bool checkAccess) { if (dirname == NULL || strlen(dirname) >= TDDIRMAXLEN) { terrno = TSDB_CODE_INVALID_PARA; return terrno; @@ -326,7 +322,7 @@ void taosRemoveOldFiles(const char *dirname, int32_t keepDays) { int32_t days = (int32_t)(TABS(sec - fileSec) / 86400 + 1); if (days > keepDays) { TAOS_UNUSED(taosRemoveFile(filename)); - uInfo("file:%s is removed, days:%d keepDays:%d, sed:%" PRId64, filename, days, keepDays, fileSec); + // printf("file:%s is removed, days:%d keepDays:%d, sed:%" PRId64, filename, days, keepDays, fileSec); } else { // printf("file:%s won't be removed, days:%d keepDays:%d", filename, days, keepDays); } @@ -340,10 +336,13 @@ void taosRemoveOldFiles(const char *dirname, int32_t keepDays) { int32_t taosExpandDir(const char *dirname, char *outname, int32_t maxlen) { OS_PARAM_CHECK(dirname); OS_PARAM_CHECK(outname); - wordexp_t full_path; + outname[0] = 0; + + wordexp_t full_path = {0}; int32_t code = wordexp(dirname, &full_path, 0); switch (code) { case 0: + tstrncpy(outname, full_path.we_wordv[0], maxlen); break; case WRDE_NOSPACE: wordfree(&full_path); @@ -352,18 +351,13 @@ int32_t taosExpandDir(const char *dirname, char *outname, int32_t maxlen) { return terrno = TSDB_CODE_INVALID_PARA; } - if (full_path.we_wordv != NULL && full_path.we_wordv[0] != NULL) { - tstrncpy(outname, full_path.we_wordv[0], maxlen); - } - wordfree(&full_path); - return 0; } int32_t taosRealPath(char *dirname, char *realPath, int32_t maxlen) { OS_PARAM_CHECK(dirname); - OS_PARAM_CHECK(realPath); + char tmp[PATH_MAX] = {0}; #ifdef WINDOWS if (_fullpath(tmp, dirname, maxlen) != NULL) { @@ -377,12 +371,14 @@ int32_t taosRealPath(char *dirname, char *realPath, int32_t maxlen) { tstrncpy(realPath, tmp, maxlen); } return 0; + } else { + terrno = TSDB_CODE_OUT_OF_MEMORY; + return terrno; } + } else { + terrno = TAOS_SYSTEM_ERROR(errno); + return terrno; } - - terrno = TAOS_SYSTEM_ERROR(errno); - - return terrno; } bool taosIsDir(const char *dirname) { @@ -454,7 +450,7 @@ TdDirPtr taosOpenDir(const char *dirname) { } #ifdef WINDOWS - char szFind[MAX_PATH]; //这是要找的 + char szFind[MAX_PATH]; // 这是要找的 HANDLE hFind; TdDirPtr pDir = taosMemoryMalloc(sizeof(TdDir)); @@ -462,7 +458,7 @@ TdDirPtr taosOpenDir(const char *dirname) { return NULL; } - snprintf(szFind, sizeof(szFind), "%s%s", dirname, "\\*.*"); //利用通配符找这个目录下的所以文件,包括目录 + snprintf(szFind, sizeof(szFind), "%s%s", dirname, "\\*.*"); // 利用通配符找这个目录下的所以文件,包括目录 pDir->hFind = FindFirstFile(szFind, &(pDir->dirEntry.findFileData)); if (INVALID_HANDLE_VALUE == pDir->hFind) { @@ -585,14 +581,14 @@ void taosGetCwd(char *buf, int32_t len) { #endif } -int taosGetDirSize(const char *path, int64_t *size) { - int32_t code; +int32_t taosGetDirSize(const char *path, int64_t *size) { + int32_t code = 0; + char fullPath[PATH_MAX + 100] = {0}; + TdDirPtr pDir = taosOpenDir(path); if (pDir == NULL) { return code = terrno; } - int32_t nBytes = 0; - char fullPath[1024] = {0}; int64_t totalSize = 0; TdDirEntryPtr de = NULL; @@ -601,31 +597,23 @@ int taosGetDirSize(const char *path, int64_t *size) { if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { continue; } - nBytes = snprintf(fullPath, sizeof(fullPath), "%s%s%s", path, TD_DIRSEP, name); - if (nBytes <= 0 || nBytes >= sizeof(fullPath)) { - TAOS_UNUSED(taosCloseDir(&pDir)); - return TSDB_CODE_OUT_OF_RANGE; - } + (void)snprintf(fullPath, sizeof(fullPath), "%s%s%s", path, TD_DIRSEP, name); int64_t subSize = 0; if (taosIsDir(fullPath)) { code = taosGetDirSize(fullPath, &subSize); - if (code != 0) { - TAOS_UNUSED(taosCloseDir(&pDir)); - return code; - } } else { code = taosStatFile(fullPath, &subSize, NULL, NULL); - if (code != 0) { - TAOS_UNUSED(taosCloseDir(&pDir)); - return code; - } } + + if (code != 0) goto _OVER; + totalSize += subSize; fullPath[0] = 0; } +_OVER: *size = totalSize; TAOS_UNUSED(taosCloseDir(&pDir)); - return 0; + return code; } diff --git a/source/os/test/CMakeLists.txt b/source/os/test/CMakeLists.txt index cc7110517f..81fb0ecb26 100644 --- a/source/os/test/CMakeLists.txt +++ b/source/os/test/CMakeLists.txt @@ -78,6 +78,13 @@ add_test( COMMAND osAtomicTests ) +add_executable(osDirTests "osDirTests.cpp") +target_link_libraries(osDirTests os util gtest_main) +add_test( + NAME osDirTests + COMMAND osDirTests +) + add_executable(osSemaphoreTests "osSemaphoreTests.cpp") target_link_libraries(osSemaphoreTests os util gtest_main) add_test( diff --git a/source/os/test/osAtomicTests.cpp b/source/os/test/osAtomicTests.cpp index eebc1574c3..170ba1cc7d 100644 --- a/source/os/test/osAtomicTests.cpp +++ b/source/os/test/osAtomicTests.cpp @@ -29,87 +29,434 @@ #include "os.h" #include "tlog.h" -TEST(osAtomicTests, Exchange16) { - int16_t value = 123; - int16_t new_value = 456; - int16_t result = atomic_exchange_16(&value, new_value); - EXPECT_EQ(result, 123); - EXPECT_EQ(value, 456); +TEST(osAtomicTests, atomic_load) { + int8_t result8 = 0, value8 = 8; + int16_t result16 = 0, value16 = 16; + int32_t result32 = 0, value32 = 32; + int64_t result64 = 0, value64 = 64; + void* resultp = &result64; + void* valuep = &value64; + + result8 = atomic_load_8(&value8); + result16 = atomic_load_16(&value16); + result32 = atomic_load_32(&value32); + result64 = atomic_load_64(&value64); + resultp = atomic_load_ptr(&valuep); + + EXPECT_EQ(result8, 8); + EXPECT_EQ(result16, 16); + EXPECT_EQ(result32, 32); + EXPECT_EQ(result64, 64); + EXPECT_EQ(resultp, &value64); + EXPECT_EQ(value8, 8); + EXPECT_EQ(value16, 16); + EXPECT_EQ(value32, 32); + EXPECT_EQ(value64, 64); + EXPECT_EQ(valuep, &value64); } -TEST(osAtomicTests, Exchange32) { - int32_t value = 123; - int32_t new_value = 456; - int32_t result = atomic_exchange_32(&value, new_value); - EXPECT_EQ(result, 123); - EXPECT_EQ(value, 456); +TEST(osAtomicTests, atomic_store) { + int8_t result8 = 0, value8 = 8; + int16_t result16 = 0, value16 = 16; + int32_t result32 = 0, value32 = 32; + int64_t result64 = 0, value64 = 64; + double resultd = 0, valued = 64; + void* resultp = &result64; + void* valuep = &value64; + + atomic_store_8(&result8, value8); + atomic_store_16(&result16, value16); + atomic_store_32(&result32, value32); + atomic_store_64(&result64, value64); + atomic_store_double(&resultd, valued); + atomic_store_ptr(&resultp, valuep); + + EXPECT_EQ(result8, 8); + EXPECT_EQ(result16, 16); + EXPECT_EQ(result32, 32); + EXPECT_EQ(result64, 64); + EXPECT_DOUBLE_EQ(resultd, 64); + EXPECT_EQ(resultp, &value64); } -TEST(osAtomicTests, Exchange64) { - int64_t value = 123; - int64_t new_value = 456; - int64_t result = atomic_exchange_64(&value, new_value); - EXPECT_EQ(result, 123); - EXPECT_EQ(value, 456); +TEST(osAtomicTests, atomic_exchange) { + int8_t result8 = 0, value8 = 8, newval8 = 18; + int16_t result16 = 0, value16 = 16, newval16 = 116; + int32_t result32 = 0, value32 = 32, newval32 = 132; + int64_t result64 = 0, value64 = 64, newval64 = 164; + double resultd = 0, valued = 64, newvald = 164; + void* valuep = &value64; + void* newvalp = &newval64; + void* resultp = &result64; + + result8 = atomic_exchange_8(&value8, newval8); + result16 = atomic_exchange_16(&value16, newval16); + result32 = atomic_exchange_32(&value32, newval32); + result64 = atomic_exchange_64(&value64, newval64); + resultd = atomic_exchange_double(&valued, newvald); + resultp = atomic_exchange_ptr(&valuep, newvalp); + + EXPECT_EQ(value8, 18); + EXPECT_EQ(value16, 116); + EXPECT_EQ(value32, 132); + EXPECT_EQ(value64, 164); + EXPECT_DOUBLE_EQ(valued, 164); + EXPECT_EQ(valuep, &newval64); + + EXPECT_EQ(result8, 8); + EXPECT_EQ(result16, 16); + EXPECT_EQ(result32, 32); + EXPECT_EQ(result64, 64); + EXPECT_DOUBLE_EQ(resultd, 64); + EXPECT_EQ(resultp, &value64); } -TEST(osAtomicTests, ExchangePtr) { - int value1 = 123; - int value2 = 456; - int* ptr = &value1; - int* result = (int*)atomic_exchange_ptr(&ptr, &value2); - EXPECT_EQ(result, &value1); - EXPECT_EQ(*ptr, 456); +TEST(osAtomicTests, atomic_val_compare_exchange) { + int8_t result8 = 0, value8 = 8, oldval8 = 8, newval8 = 18; + int16_t result16 = 0, value16 = 16, oldval16 = 16, newval16 = 116; + int32_t result32 = 0, value32 = 32, oldval32 = 32, newval32 = 132; + int64_t result64 = 0, value64 = 64, oldval64 = 64, newval64 = 164; + void* resultp = NULL; + void* valuep = &value64; + void* oldvalp = &value64; + void* newvalp = &newval64; + + result8 = atomic_val_compare_exchange_8(&value8, oldval8, newval8); + result16 = atomic_val_compare_exchange_16(&value16, oldval16, newval16); + result32 = atomic_val_compare_exchange_32(&value32, oldval32, newval32); + result64 = atomic_val_compare_exchange_64(&value64, oldval64, newval64); + resultp = atomic_val_compare_exchange_ptr(&valuep, oldvalp, newvalp); + + EXPECT_EQ(result8, 8); + EXPECT_EQ(value8, 18); + EXPECT_EQ(result16, 16); + EXPECT_EQ(value16, 116); + EXPECT_EQ(result32, 32); + EXPECT_EQ(value32, 132); + EXPECT_EQ(result64, 64); + EXPECT_EQ(value64, 164); + EXPECT_EQ(resultp, &value64); + EXPECT_EQ(valuep, &newval64); + + oldval8 = 9; + oldval16 = 99; + oldval32 = 999; + oldval64 = 9999; + oldvalp = NULL; + + result8 = atomic_val_compare_exchange_8(&value8, oldval8, newval8); + result16 = atomic_val_compare_exchange_16(&value16, oldval16, newval16); + result32 = atomic_val_compare_exchange_32(&value32, oldval32, newval32); + result64 = atomic_val_compare_exchange_64(&value64, oldval64, newval64); + resultp = atomic_val_compare_exchange_ptr(&valuep, oldvalp, newvalp); + + EXPECT_EQ(result8, 18); + EXPECT_EQ(value8, 18); + EXPECT_EQ(result16, 116); + EXPECT_EQ(value16, 116); + EXPECT_EQ(result32, 132); + EXPECT_EQ(value32, 132); + EXPECT_EQ(result64, 164); + EXPECT_EQ(value64, 164); + EXPECT_EQ(resultp, &newval64); + EXPECT_EQ(valuep, &newval64); } -TEST(osAtomicTests, ValCompareExchange8) { - int8_t value = 12; - int8_t oldval = 12; - int8_t newval = 45; - int8_t result = atomic_val_compare_exchange_8(&value, oldval, newval); - EXPECT_EQ(result, 12); - EXPECT_EQ(value, 45); +TEST(osAtomicTests, atomic_add_fetch) { + int8_t result8 = 0, value8 = 8; + int16_t result16 = 0, value16 = 16; + int32_t result32 = 0, value32 = 32; + int64_t result64 = 0, value64 = 64; - oldval = 78; - result = atomic_val_compare_exchange_8(&value, oldval, newval); - EXPECT_EQ(result, 45); - EXPECT_EQ(value, 45); + int64_t valuex = 128; + int64_t* valuep = &valuex; + int64_t resultx = 0; + + result8 = atomic_add_fetch_8(&value8, 10); + result16 = atomic_add_fetch_16(&value16, 10); + result32 = atomic_add_fetch_32(&value32, 10); + result64 = atomic_add_fetch_64(&value64, 10); + resultx = (int64_t)atomic_add_fetch_ptr(valuep, 10); + + EXPECT_EQ(result8, 18); + EXPECT_EQ(value8, 18); + EXPECT_EQ(result16, 26); + EXPECT_EQ(value16, 26); + EXPECT_EQ(result32, 42); + EXPECT_EQ(value32, 42); + EXPECT_EQ(result64, 74); + EXPECT_EQ(value64, 74); + EXPECT_EQ(resultx, 138); + EXPECT_EQ(*valuep, 138); + EXPECT_EQ(valuex, 138); } -TEST(osAtomicTests, ValCompareExchange16) { - int16_t value = 123; - int16_t oldval = 123; - int16_t newval = 456; - int16_t result = atomic_val_compare_exchange_16(&value, oldval, newval); - EXPECT_EQ(result, 123); - EXPECT_EQ(value, 456); +TEST(osAtomicTests, atomic_fetch_add) { + int8_t result8 = 0, value8 = 8; + int16_t result16 = 0, value16 = 16; + int32_t result32 = 0, value32 = 32; + int64_t result64 = 0, value64 = 64; + double resultd = 0, valued = 64; - oldval = 789; - result = atomic_val_compare_exchange_16(&value, oldval, newval); - EXPECT_EQ(result, 456); - EXPECT_EQ(value, 456); + int64_t valuex = 128; + int64_t* valuep = &valuex; + int64_t resultx = 0; + + result8 = atomic_fetch_add_8(&value8, 10); + result16 = atomic_fetch_add_16(&value16, 10); + result32 = atomic_fetch_add_32(&value32, 10); + result64 = atomic_fetch_add_64(&value64, 10); + resultd = atomic_fetch_add_double(&valued, 10); + resultx = (int64_t)atomic_fetch_add_ptr(valuep, 10); + + EXPECT_EQ(result8, 8); + EXPECT_EQ(value8, 18); + EXPECT_EQ(result16, 16); + EXPECT_EQ(value16, 26); + EXPECT_EQ(result32, 32); + EXPECT_EQ(value32, 42); + EXPECT_EQ(result64, 64); + EXPECT_EQ(value64, 74); + EXPECT_DOUBLE_EQ(resultd, 64); + EXPECT_DOUBLE_EQ(valued, 74); + EXPECT_EQ(resultx, 128); + EXPECT_EQ(*valuep, 138); + EXPECT_EQ(valuex, 138); } -TEST(osAtomicTests, TestAtomicExchange8) { - volatile int8_t value = 42; - int8_t new_value = 100; - int8_t old_value = atomic_exchange_8(&value, new_value); - EXPECT_EQ(old_value, 42); - EXPECT_EQ(value, new_value); +TEST(osAtomicTests, atomic_sub_fetch) { + int8_t result8 = 0, value8 = 8; + int16_t result16 = 0, value16 = 16; + int32_t result32 = 0, value32 = 32; + int64_t result64 = 0, value64 = 64; + + int64_t valuex = 128; + int64_t* valuep = &valuex; + int64_t resultx = 0; + + result8 = atomic_sub_fetch_8(&value8, 10); + result16 = atomic_sub_fetch_16(&value16, 10); + result32 = atomic_sub_fetch_32(&value32, 10); + result64 = atomic_sub_fetch_64(&value64, 10); + resultx = (int64_t)atomic_sub_fetch_ptr(valuep, 10); + + EXPECT_EQ(result8, -2); + EXPECT_EQ(value8, -2); + EXPECT_EQ(result16, 6); + EXPECT_EQ(value16, 6); + EXPECT_EQ(result32, 22); + EXPECT_EQ(value32, 22); + EXPECT_EQ(result64, 54); + EXPECT_EQ(value64, 54); + EXPECT_EQ(resultx, 118); + EXPECT_EQ(*valuep, 118); + EXPECT_EQ(valuex, 118); } -TEST(osAtomicTests, TestAtomicAddFetch16) { - volatile int16_t value = 42; - int16_t increment = 10; - int16_t new_value = atomic_add_fetch_16(&value, increment); - EXPECT_EQ(new_value, 52); - EXPECT_EQ(value, 52); +TEST(osAtomicTests, atomic_fetch_sub) { + int8_t result8 = 0, value8 = 8; + int16_t result16 = 0, value16 = 16; + int32_t result32 = 0, value32 = 32; + int64_t result64 = 0, value64 = 64; + double resultd = 0, valued = 64; + + int64_t valuex = 128; + int64_t* valuep = &valuex; + int64_t resultx = 0; + + result8 = atomic_fetch_sub_8(&value8, 10); + result16 = atomic_fetch_sub_16(&value16, 10); + result32 = atomic_fetch_sub_32(&value32, 10); + result64 = atomic_fetch_sub_64(&value64, 10); + resultd = atomic_fetch_sub_double(&valued, 10); + resultx = (int64_t)atomic_fetch_sub_ptr(valuep, 10); + + EXPECT_EQ(result8, 8); + EXPECT_EQ(value8, -2); + EXPECT_EQ(result16, 16); + EXPECT_EQ(value16, 6); + EXPECT_EQ(result32, 32); + EXPECT_EQ(value32, 22); + EXPECT_EQ(result64, 64); + EXPECT_EQ(value64, 54); + EXPECT_DOUBLE_EQ(resultd, 64); + EXPECT_DOUBLE_EQ(valued, 54); + EXPECT_EQ(resultx, 128); + EXPECT_EQ(*valuep, 118); + EXPECT_EQ(valuex, 118); } -//TEST(osAtomicTests, AddFetchPtr) { -// uintptr_t val = 0; -// uintptr_t* ptr = &val; -// uintptr_t ret = atomic_add_fetch_ptr(ptr, 10); -// EXPECT_EQ(ret, 10); -// EXPECT_EQ(val, 10); -//} +TEST(osAtomicTests, atomic_and_fetch) { + int8_t result8 = 0, value8 = 3; + int16_t result16 = 0, value16 = 3; + int32_t result32 = 0, value32 = 3; + int64_t result64 = 0, value64 = 3; + + int64_t valuex = 3; + int64_t* valuep = &valuex; + int64_t resultx = 0; + + result8 = atomic_and_fetch_8(&value8, 5); + result16 = atomic_and_fetch_16(&value16, 5); + result32 = atomic_and_fetch_32(&value32, 5); + result64 = atomic_and_fetch_64(&value64, 5); + resultx = (int64_t)atomic_and_fetch_ptr(valuep, 5); + + EXPECT_EQ(result8, 1); + EXPECT_EQ(value8, 1); + EXPECT_EQ(result16, 1); + EXPECT_EQ(value16, 1); + EXPECT_EQ(result32, 1); + EXPECT_EQ(value32, 1); + EXPECT_EQ(result64, 1); + EXPECT_EQ(value64, 1); + EXPECT_EQ(resultx, 1); + EXPECT_EQ(*valuep, 1); + EXPECT_EQ(valuex, 1); +} + +TEST(osAtomicTests, atomic_fetch_and) { + int8_t result8 = 0, value8 = 3; + int16_t result16 = 0, value16 = 3; + int32_t result32 = 0, value32 = 3; + int64_t result64 = 0, value64 = 3; + + int64_t valuex = 3; + int64_t* valuep = &valuex; + int64_t resultx = 0; + + result8 = atomic_fetch_and_8(&value8, 5); + result16 = atomic_fetch_and_16(&value16, 5); + result32 = atomic_fetch_and_32(&value32, 5); + result64 = atomic_fetch_and_64(&value64, 5); + resultx = (int64_t)atomic_fetch_and_ptr(valuep, 5); + + EXPECT_EQ(result8, 3); + EXPECT_EQ(value8, 1); + EXPECT_EQ(result16, 3); + EXPECT_EQ(value16, 1); + EXPECT_EQ(result32, 3); + EXPECT_EQ(value32, 1); + EXPECT_EQ(result64, 3); + EXPECT_EQ(value64, 1); + EXPECT_EQ(resultx, 3); + EXPECT_EQ(*valuep, 1); + EXPECT_EQ(valuex, 1); +} + +TEST(osAtomicTests, atomic_or_fetch) { + int8_t result8 = 0, value8 = 3; + int16_t result16 = 0, value16 = 3; + int32_t result32 = 0, value32 = 3; + int64_t result64 = 0, value64 = 3; + + int64_t valuex = 3; + int64_t* valuep = &valuex; + int64_t resultx = 0; + + result8 = atomic_or_fetch_8(&value8, 5); + result16 = atomic_or_fetch_16(&value16, 5); + result32 = atomic_or_fetch_32(&value32, 5); + result64 = atomic_or_fetch_64(&value64, 5); + resultx = (int64_t)atomic_or_fetch_ptr(valuep, 5); + + EXPECT_EQ(result8, 7); + EXPECT_EQ(value8, 7); + EXPECT_EQ(result16, 7); + EXPECT_EQ(value16, 7); + EXPECT_EQ(result32, 7); + EXPECT_EQ(value32, 7); + EXPECT_EQ(result64, 7); + EXPECT_EQ(value64, 7); + EXPECT_EQ(resultx, 7); + EXPECT_EQ(*valuep, 7); + EXPECT_EQ(valuex, 7); +} + +TEST(osAtomicTests, atomic_fetch_or) { + int8_t result8 = 0, value8 = 3; + int16_t result16 = 0, value16 = 3; + int32_t result32 = 0, value32 = 3; + int64_t result64 = 0, value64 = 3; + + int64_t valuex = 3; + int64_t* valuep = &valuex; + int64_t resultx = 0; + + result8 = atomic_fetch_or_8(&value8, 5); + result16 = atomic_fetch_or_16(&value16, 5); + result32 = atomic_fetch_or_32(&value32, 5); + result64 = atomic_fetch_or_64(&value64, 5); + resultx = (int64_t)atomic_fetch_or_ptr(valuep, 5); + + EXPECT_EQ(result8, 3); + EXPECT_EQ(value8, 7); + EXPECT_EQ(result16, 3); + EXPECT_EQ(value16, 7); + EXPECT_EQ(result32, 3); + EXPECT_EQ(value32, 7); + EXPECT_EQ(result64, 3); + EXPECT_EQ(value64, 7); + EXPECT_EQ(resultx, 3); + EXPECT_EQ(*valuep, 7); + EXPECT_EQ(valuex, 7); +} + + +TEST(osAtomicTests, atomic_xor_fetch) { + int8_t result8 = 0, value8 = 3; + int16_t result16 = 0, value16 = 3; + int32_t result32 = 0, value32 = 3; + int64_t result64 = 0, value64 = 3; + + int64_t valuex = 3; + int64_t* valuep = &valuex; + int64_t resultx = 0; + + result8 = atomic_xor_fetch_8(&value8, 5); + result16 = atomic_xor_fetch_16(&value16, 5); + result32 = atomic_xor_fetch_32(&value32, 5); + result64 = atomic_xor_fetch_64(&value64, 5); + resultx = (int64_t)atomic_xor_fetch_ptr(valuep, 5); + + EXPECT_EQ(result8, 6); + EXPECT_EQ(value8, 6); + EXPECT_EQ(result16, 6); + EXPECT_EQ(value16, 6); + EXPECT_EQ(result32, 6); + EXPECT_EQ(value32, 6); + EXPECT_EQ(result64, 6); + EXPECT_EQ(value64, 6); + EXPECT_EQ(resultx, 6); + EXPECT_EQ(*valuep, 6); + EXPECT_EQ(valuex, 6); +} + +TEST(osAtomicTests, atomic_fetch_xor) { + int8_t result8 = 0, value8 = 3; + int16_t result16 = 0, value16 = 3; + int32_t result32 = 0, value32 = 3; + int64_t result64 = 0, value64 = 3; + + int64_t valuex = 3; + int64_t* valuep = &valuex; + int64_t resultx = 0; + + result8 = atomic_fetch_xor_8(&value8, 5); + result16 = atomic_fetch_xor_16(&value16, 5); + result32 = atomic_fetch_xor_32(&value32, 5); + result64 = atomic_fetch_xor_64(&value64, 5); + resultx = (int64_t)atomic_fetch_xor_ptr(valuep, 5); + + EXPECT_EQ(result8, 3); + EXPECT_EQ(value8, 6); + EXPECT_EQ(result16, 3); + EXPECT_EQ(value16, 6); + EXPECT_EQ(result32, 3); + EXPECT_EQ(value32, 6); + EXPECT_EQ(result64, 3); + EXPECT_EQ(value64, 6); + EXPECT_EQ(resultx, 3); + EXPECT_EQ(*valuep, 6); + EXPECT_EQ(valuex, 6); +} \ No newline at end of file diff --git a/source/os/test/osDirTests.cpp b/source/os/test/osDirTests.cpp new file mode 100644 index 0000000000..eaf4781955 --- /dev/null +++ b/source/os/test/osDirTests.cpp @@ -0,0 +1,448 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic ignored "-Wformat" +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" +#pragma GCC diagnostic ignored "-Wpointer-arith" + +#include "os.h" +#include "tlog.h" + +TEST(osDirTests, taosRemoveDir) { + int32_t ret = 0; + + const char* testDir = "/tmp/tdengine-test-dir"; + if (taosDirExist(testDir)) { + taosRemoveDir(testDir); + } + + taosRemoveDir(testDir); + + ret = taosMkDir(testDir); + EXPECT_EQ(ret, 0); + + const char* testFile = "/tmp/tdengine-test-dir/test-file"; + TdFilePtr testFilePtr = taosCreateFile(testFile, TD_FILE_CREATE); + EXPECT_NE(testFilePtr, nullptr); + ret = taosCloseFile(&testFilePtr); + EXPECT_EQ(ret, 0); + + const char* testDir2 = "/tmp/tdengine-test-dir/test-dir2"; + ret = taosMkDir(testDir2); + EXPECT_EQ(ret, 0); + + const char* testFile2 = "/tmp/tdengine-test-dir/test-dir2/test-file2"; + TdFilePtr testFilePtr2 = taosCreateFile(testFile2, TD_FILE_CREATE); + EXPECT_NE(testFilePtr2, nullptr); + ret = taosCloseFile(&testFilePtr2); + EXPECT_EQ(ret, 0); + + taosRemoveDir(testDir); + + bool exist = taosDirExist(testDir); + EXPECT_EQ(exist, false); + + taosRemoveDir("/tmp/tdengine-test-dir"); +} + +TEST(osDirTests, taosDirExist) { + const char* dir1 = NULL; + bool exist = taosDirExist(dir1); + EXPECT_EQ(exist, false); + + char dir2[2048] = {0}; + for (int32_t i = 0; i < 2047; ++i) { + dir2[i] = 1; + } + exist = taosDirExist(dir2); + EXPECT_EQ(exist, false); + + taosRemoveDir("/tmp/tdengine-test-dir"); +} + +TEST(osDirTests, taosMulMkDir) { + int32_t ret = 0; + + const char* dir1 = NULL; + ret = taosMulMkDir(dir1); + EXPECT_EQ(ret, -1); + + char dir2[2048] = {0}; + for (int32_t i = 0; i < 2047; ++i) { + dir2[i] = '1'; + } + ret = taosMulMkDir(dir2); + EXPECT_EQ(ret, -1); + + const char* dir3 = "/tmp/tdengine-test-dir/1/2/3/4"; + taosRemoveDir(dir3); + ret = taosMulMkDir(dir3); + EXPECT_EQ(ret, 0); + taosRemoveDir(dir3); + + const char* dir4 = "./tdengine-test-dir/1/2/3/4"; + taosRemoveDir(dir4); + ret = taosMulMkDir(dir4); + EXPECT_EQ(ret, 0); + taosRemoveDir(dir4); + + const char* dir5 = "tdengine-test-dir/1/2/3/4"; + taosRemoveDir(dir5); + ret = taosMulMkDir(dir5); + EXPECT_EQ(ret, 0); + ret = taosMulMkDir(dir5); + EXPECT_EQ(ret, 0); + taosRemoveDir(dir5); + + const char* testFile = "/tmp/tdengine-test-dir/test-file"; + TdFilePtr testFilePtr = taosCreateFile(testFile, TD_FILE_CREATE); + EXPECT_NE(testFilePtr, nullptr); + ret = taosCloseFile(&testFilePtr); + EXPECT_EQ(ret, 0); + char dir6[2048] = {0}; + strcpy(dir6, "/tmp/tdengine-test-dir/test-file/1/2/3/4"); + ret = taosMulMkDir(dir6); + EXPECT_NE(ret, 0); + + taosRemoveDir("/tmp/tdengine-test-dir"); +} + +TEST(osDirTests, taosMulModeMkDir) { + int32_t ret = 0; + + const char* dir1 = NULL; + ret = taosMulModeMkDir(dir1, 777, true); + EXPECT_NE(ret, 0); + + char dir2[2048] = {0}; + for (int32_t i = 0; i < 2047; ++i) { + dir2[i] = '1'; + } + ret = taosMulModeMkDir(dir2, 777, true); + EXPECT_NE(ret, 0); + + const char* dir3 = "/tmp/tdengine-test-dir/1/2/3/4"; + taosRemoveDir(dir3); + ret = taosMulMkDir(dir3); + EXPECT_EQ(ret, 0); + ret = taosMulModeMkDir(dir3, 777, true); + EXPECT_EQ(ret, 0); + ret = taosMulModeMkDir(dir3, 777, false); + EXPECT_EQ(ret, 0); + ret = taosMulModeMkDir(dir3, 999, true); + EXPECT_EQ(ret, 0); + ret = taosMulModeMkDir(dir3, 999, false); + EXPECT_EQ(ret, 0); + taosRemoveDir(dir3); + + const char* dir4 = "./tdengine-test-dir/1/2/3/4"; + taosRemoveDir(dir4); + ret = taosMulModeMkDir(dir4, 777, true); + EXPECT_EQ(ret, 0); + ret = taosMulModeMkDir(dir4, 777, false); + EXPECT_EQ(ret, 0); + taosRemoveDir(dir4); + + const char* dir5 = "tdengine-test-dir/1/2/3/4"; + taosRemoveDir(dir5); + ret = taosMulModeMkDir(dir5, 777, true); + EXPECT_EQ(ret, 0); + ret = taosMulModeMkDir(dir5, 777, false); + EXPECT_EQ(ret, 0); + ret = taosMulModeMkDir(dir5, 777, true); + EXPECT_EQ(ret, 0); + ret = taosMulModeMkDir(dir5, 777, false); + EXPECT_EQ(ret, 0); + taosRemoveDir(dir5); + + const char* testFile = "/tmp/tdengine-test-dir/test-file"; + TdFilePtr testFilePtr = taosCreateFile(testFile, TD_FILE_CREATE); + EXPECT_NE(testFilePtr, nullptr); + ret = taosCloseFile(&testFilePtr); + EXPECT_EQ(ret, 0); + char dir6[2048] = {0}; + strcpy(dir6, "/tmp/tdengine-test-dir/test-file/1/2/3/4"); + ret = taosMulModeMkDir(dir6, 777, true); + EXPECT_NE(ret, 0); + + const char* dir7 = "tdengine-test-dir/1/2/3/5"; + taosRemoveDir(dir7); + ret = taosMulModeMkDir(dir7, 999, true); + EXPECT_EQ(ret, 0); + ret = taosMulModeMkDir(dir7, 999, false); + EXPECT_EQ(ret, 0); + + taosRemoveDir("/tmp/tdengine-test-dir"); +} + +TEST(osDirTests, taosRemoveOldFiles) { + int32_t ret = 0; + const char* testDir = "/tmp/tdengine-test-dir"; + if (taosDirExist(testDir)) { + taosRemoveDir(testDir); + } + taosRemoveDir(testDir); + ret = taosMkDir(testDir); + EXPECT_EQ(ret, 0); + + const char* testFile = "/tmp/tdengine-test-dir/test-file"; + TdFilePtr testFilePtr = taosCreateFile(testFile, TD_FILE_CREATE); + EXPECT_NE(testFilePtr, nullptr); + ret = taosCloseFile(&testFilePtr); + EXPECT_EQ(ret, 0); + + taosRemoveOldFiles(testFile, 10); + + const char* testDir2 = "/tmp/tdengine-test-dir/test-dir2"; + ret = taosMkDir(testDir2); + EXPECT_EQ(ret, 0); + + const char* testFile3 = "/tmp/tdengine-test-dir/log.1433726073.gz"; + TdFilePtr testFilePtr3 = taosCreateFile(testFile3, TD_FILE_CREATE); + EXPECT_NE(testFilePtr3, nullptr); + ret = taosCloseFile(&testFilePtr3); + EXPECT_EQ(ret, 0); + + const char* testFile4 = "/tmp/tdengine-test-dir/log.80.gz"; + TdFilePtr testFilePtr4 = taosCreateFile(testFile4, TD_FILE_CREATE); + EXPECT_NE(testFilePtr4, nullptr); + ret = taosCloseFile(&testFilePtr4); + EXPECT_EQ(ret, 0); + + char testFile5[1024]; + snprintf(testFile5, 1024, "/tmp/tdengine-test-dir/log.%d.gz", taosGetTimestampSec()); + TdFilePtr testFilePtr5 = taosCreateFile(testFile5, TD_FILE_CREATE); + EXPECT_NE(testFilePtr5, nullptr); + ret = taosCloseFile(&testFilePtr5); + EXPECT_EQ(ret, 0); + + const char* testFile6 = "/tmp/tdengine-test-dir/log.1433726073.gz"; + TdFilePtr testFilePtr6 = taosCreateFile(testFile6, TD_FILE_CREATE); + EXPECT_NE(testFilePtr6, nullptr); + ret = taosCloseFile(&testFilePtr6); + EXPECT_EQ(ret, 0); + + taosRemoveOldFiles(testDir, 10); + + bool exist = taosDirExist(testDir); + EXPECT_EQ(exist, true); + + taosRemoveDir("/tmp/tdengine-test-dir"); +} + +TEST(osDirTests, taosExpandDir) { + int32_t ret = 0; + const char* testDir = "/tmp/tdengine-test-dir"; + ret = taosMkDir(testDir); + EXPECT_EQ(ret, 0); + + char fullpath[1024] = {0}; + ret = taosExpandDir(testDir, NULL, 1024); + EXPECT_NE(ret, 0); + ret = taosExpandDir(NULL, fullpath, 1024); + EXPECT_NE(ret, 0); + ret = taosExpandDir(testDir, fullpath, 1024); + EXPECT_EQ(ret, 0); + + ret = taosExpandDir("/x123", fullpath, 1024); + EXPECT_EQ(ret, 0); + + char dir2[2048] = {0}; + for (int32_t i = 0; i < 2047; ++i) { + dir2[i] = '1'; + } + ret = taosExpandDir(dir2, fullpath, 1024); + EXPECT_EQ(ret, 0); + + taosRemoveDir("/tmp/tdengine-test-dir"); +} + +TEST(osDirTests, taosRealPath) { + int32_t ret = 0; + char testDir[1024] = "/tmp/tdengine-test-dir"; + ret = taosMkDir(testDir); + EXPECT_EQ(ret, 0); + + char fullpath[PATH_MAX * 2] = {0}; + + ret = taosRealPath(testDir, NULL, PATH_MAX * 2); + EXPECT_EQ(ret, 0); + + ret = taosRealPath(NULL, fullpath, PATH_MAX * 2); + EXPECT_NE(ret, 0); + + ret = taosRealPath(testDir, fullpath, PATH_MAX * 2); + EXPECT_EQ(ret, 0); + + ret = taosRealPath(testDir, fullpath, 12); + EXPECT_NE(ret, 0); + + ret = taosRealPath("/c/d", fullpath, 1024); + EXPECT_NE(ret, 0); + + taosRemoveDir("/tmp/tdengine-test-dir"); +} + +TEST(osDirTests, taosIsDir) { + bool ret = taosIsDir("/c/d"); + EXPECT_EQ(ret, false); +} + +TEST(osDirTests, taosDirName) { + char* ret = taosDirName(NULL); + EXPECT_EQ(ret, nullptr); + + char name1[24] = "xyz"; + ret = taosDirName(name1); + EXPECT_NE(ret, nullptr); + EXPECT_EQ(name1[0], 0); + + char name2[24] = "/root/xyz"; + ret = taosDirName(name2); + EXPECT_NE(ret, nullptr); + EXPECT_STREQ(ret, "/root"); +} + +TEST(osDirTests, taosDirEntryBaseName) { + char* ret = taosDirEntryBaseName(NULL); + EXPECT_EQ(ret, nullptr); + + char name1[12] = "/"; + ret = taosDirEntryBaseName(name1); + EXPECT_STREQ(ret, "/"); + + char name2[12] = "/root/"; + ret = taosDirEntryBaseName(name2); + EXPECT_STREQ(ret, "root"); + + char name3[12] = "/root"; + ret = taosDirEntryBaseName(name3); + EXPECT_STREQ(ret, "root"); + + char name4[12] = "root"; + ret = taosDirEntryBaseName(name4); + EXPECT_STREQ(ret, "root"); +} + +TEST(osDirTests, taosOpenDir) { + TdDirPtr ret = taosOpenDir(NULL); + EXPECT_EQ(ret, nullptr); +} + +TEST(osDirTests, taosReadDir) { + TdDirEntryPtr rddir = taosReadDir(NULL); + EXPECT_EQ(rddir, nullptr); + + int32_t ret = 0; + const char* testDir = "/tmp/tdengine-test-dir"; + ret = taosMkDir(testDir); + EXPECT_EQ(ret, 0); + + const char* testFile = "/tmp/tdengine-test-dir/test-file"; + TdFilePtr testFilePtr = taosCreateFile(testFile, TD_FILE_CREATE); + EXPECT_NE(testFilePtr, nullptr); + ret = taosCloseFile(&testFilePtr); + EXPECT_EQ(ret, 0); + + TdDirPtr dir = taosOpenDir(testFile); + EXPECT_EQ(dir, nullptr); + + const char* testDir2 = "/tmp/tdengine-test-dir/test-dir2"; + ret = taosMkDir(testDir2); + EXPECT_EQ(ret, 0); + + const char* testFile2 = "/tmp/tdengine-test-dir/test-dir2/test-file2"; + TdFilePtr testFilePtr2 = taosCreateFile(testFile2, TD_FILE_CREATE); + EXPECT_NE(testFilePtr2, nullptr); + ret = taosCloseFile(&testFilePtr2); + EXPECT_EQ(ret, 0); + + dir = taosOpenDir(testFile); + EXPECT_EQ(dir, nullptr); + + rddir = taosReadDir(dir); + EXPECT_EQ(rddir, nullptr); + + dir = taosOpenDir(testDir); + EXPECT_NE(dir, nullptr); + + rddir = taosReadDir(dir); + EXPECT_NE(rddir, nullptr); + + bool entry = taosDirEntryIsDir(NULL); + EXPECT_EQ(entry, false); + + char* entryname = taosGetDirEntryName(NULL); + EXPECT_EQ(entryname, nullptr); + + entryname = taosGetDirEntryName(rddir); + EXPECT_NE(entryname, nullptr); + + int32_t code = taosCloseDir(NULL); + EXPECT_NE(code, 0); + + code = taosCloseDir(&dir); + EXPECT_EQ(code, 0); + + taosRemoveDir("/tmp/tdengine-test-dir"); +} + + +TEST(osDirTests, taosGetDirSize) { + TdDirEntryPtr rddir = taosReadDir(NULL); + EXPECT_EQ(rddir, nullptr); + + int32_t ret = 0; + const char* testDir = "/tmp/tdengine-test-dir"; + ret = taosMkDir(testDir); + EXPECT_EQ(ret, 0); + + const char* testFile = "/tmp/tdengine-test-dir/test-file"; + TdFilePtr testFilePtr = taosCreateFile(testFile, TD_FILE_CREATE); + EXPECT_NE(testFilePtr, nullptr); + ret = taosCloseFile(&testFilePtr); + EXPECT_EQ(ret, 0); + + TdDirPtr dir = taosOpenDir(testFile); + EXPECT_EQ(dir, nullptr); + + const char* testDir2 = "/tmp/tdengine-test-dir/test-dir2"; + ret = taosMkDir(testDir2); + EXPECT_EQ(ret, 0); + + const char* testFile2 = "/tmp/tdengine-test-dir/test-dir2/test-file2"; + TdFilePtr testFilePtr2 = taosCreateFile(testFile2, TD_FILE_CREATE); + EXPECT_NE(testFilePtr2, nullptr); + ret = taosCloseFile(&testFilePtr2); + EXPECT_EQ(ret, 0); + + int64_t size = -1; + ret = taosGetDirSize(testFile, &size); + EXPECT_NE(ret, 0); + + ret = taosGetDirSize(testDir, &size); + EXPECT_EQ(ret, 0); + + taosRemoveDir("/tmp/tdengine-test-dir"); +} From 68558b0116b713235611795b9c3e4c928da7acda Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Mon, 9 Dec 2024 08:16:14 +0000 Subject: [PATCH 52/62] enh: simple changes --- source/os/src/osDir.c | 17 ++++++----------- source/os/test/osDirTests.cpp | 3 +++ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/source/os/src/osDir.c b/source/os/src/osDir.c index 189ccb8a8d..0485c8f6c4 100644 --- a/source/os/src/osDir.c +++ b/source/os/src/osDir.c @@ -340,19 +340,14 @@ int32_t taosExpandDir(const char *dirname, char *outname, int32_t maxlen) { wordexp_t full_path = {0}; int32_t code = wordexp(dirname, &full_path, 0); - switch (code) { - case 0: - tstrncpy(outname, full_path.we_wordv[0], maxlen); - break; - case WRDE_NOSPACE: - wordfree(&full_path); - // FALL THROUGH - default: - return terrno = TSDB_CODE_INVALID_PARA; + if (code == 0 && full_path.we_wordv[0] != NULL) { + tstrncpy(outname, full_path.we_wordv[0], maxlen); + wordfree(&full_path); + return 0; } wordfree(&full_path); - return 0; + return terrno = TSDB_CODE_INVALID_PARA; } int32_t taosRealPath(char *dirname, char *realPath, int32_t maxlen) { @@ -607,7 +602,7 @@ int32_t taosGetDirSize(const char *path, int64_t *size) { } if (code != 0) goto _OVER; - + totalSize += subSize; fullPath[0] = 0; } diff --git a/source/os/test/osDirTests.cpp b/source/os/test/osDirTests.cpp index eaf4781955..e6d64d61a2 100644 --- a/source/os/test/osDirTests.cpp +++ b/source/os/test/osDirTests.cpp @@ -268,6 +268,9 @@ TEST(osDirTests, taosExpandDir) { ret = taosExpandDir("/x123", fullpath, 1024); EXPECT_EQ(ret, 0); + ret = taosExpandDir("", fullpath, 1024); + EXPECT_NE(ret, 0); + char dir2[2048] = {0}; for (int32_t i = 0; i < 2047; ++i) { dir2[i] = '1'; From befaee12a5889b930ca622144f131d5ad5473c90 Mon Sep 17 00:00:00 2001 From: Alex Duan <417921451@qq.com> Date: Mon, 9 Dec 2024 16:57:04 +0800 Subject: [PATCH 53/62] case: test passed ok --- tests/parallel_test/cases.task | 1 + .../eco-system/manager/schema_change.py | 46 ++++++++++++++++--- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/tests/parallel_test/cases.task b/tests/parallel_test/cases.task index a635ae680a..47a6b418f6 100644 --- a/tests/parallel_test/cases.task +++ b/tests/parallel_test/cases.task @@ -1082,6 +1082,7 @@ ,,n,system-test,python3 ./test.py -f 5-taos-tools/taosbenchmark/insertMix.py -N 3 ,,n,system-test,python3 ./test.py -f 5-taos-tools/taosbenchmark/stt.py -N 3 ,,n,system-test,python3 ./test.py -f eco-system/meta/database/keep_time_offset.py +,,y,system-test,./pytest.sh python3 ./test.py -f eco-system/manager/schema_change.py -N 3 -M 3 #tsim test ,,y,script,./test.sh -f tsim/query/timeline.sim diff --git a/tests/system-test/eco-system/manager/schema_change.py b/tests/system-test/eco-system/manager/schema_change.py index 400d2b100b..8eef773d48 100644 --- a/tests/system-test/eco-system/manager/schema_change.py +++ b/tests/system-test/eco-system/manager/schema_change.py @@ -133,8 +133,17 @@ class TDTestCase: if len(tags) < 10: return - sel_cols = random.sample(columns, random.randint(2,int(len(columns)/10))) - sel_tags = random.sample(tags, random.randint(1,int(len(tags)/10))) + # cmax + cmax = int(len(columns)/10) + if cmax <=2 : + cmax = 3 + sel_cols = random.sample(columns, random.randint(2, cmax)) + + # tmax + tmax = int(len(tags)/10) + if tmax <=1 : + tmax = 2 + sel_tags = random.sample(tags, random.randint(1, tmax)) field_cols = ",".join(sel_cols) field_tags = ",".join(sel_tags) @@ -217,18 +226,43 @@ class TDTestCase: #time.sleep(0.3) + # create db and stb + def create(self, db, stb, cols, tags): + # create db + sql = f"create database {db} ;" + tdSql.execute(sql) + + # switch db + tdSql.execute(f"use {db};") + + # cols + sql1 = "" + for k, v in cols.items(): + sql1 += f",{k} {v}" + # tags + sql2 = "" + for k, v in tags.items(): + if sql2 == "": + sql2 = f"{k} {v}" + else: + sql2 += f",{k} {v}" + + # create stb + sql = f"create table {db}.{stb}(ts timestamp {sql1}) tags({sql2})" + tdSql.execute(sql) + # run def run(self): # seed random.seed(int(time.time())) self.dbname = "schema_change" - # switch db - tdSql.execute(f"use {self.dbname};") + # create db + self.create(self.dbname, "meters", self.column_dict, self.tag_dict) + # change meters - self.change_schema(1000000) - + self.change_schema(1000) def stop(self): From a2317486878a898c48f33b16c60c2a2460e63d66 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Mon, 9 Dec 2024 09:06:24 +0000 Subject: [PATCH 54/62] enh: minor changes --- source/os/src/osDir.c | 18 +++++++++++++----- source/os/test/osDirTests.cpp | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/source/os/src/osDir.c b/source/os/src/osDir.c index 0485c8f6c4..410f9da623 100644 --- a/source/os/src/osDir.c +++ b/source/os/src/osDir.c @@ -336,18 +336,26 @@ void taosRemoveOldFiles(const char *dirname, int32_t keepDays) { int32_t taosExpandDir(const char *dirname, char *outname, int32_t maxlen) { OS_PARAM_CHECK(dirname); OS_PARAM_CHECK(outname); - outname[0] = 0; + if (dirname[0] == 0) return 0; wordexp_t full_path = {0}; int32_t code = wordexp(dirname, &full_path, 0); - if (code == 0 && full_path.we_wordv[0] != NULL) { + switch (code) { + case 0: + break; + case WRDE_NOSPACE: + wordfree(&full_path); + // FALL THROUGH + default: + return terrno = TSDB_CODE_INVALID_PARA; + } + + if (full_path.we_wordv != NULL && full_path.we_wordv[0] != NULL) { tstrncpy(outname, full_path.we_wordv[0], maxlen); - wordfree(&full_path); - return 0; } wordfree(&full_path); - return terrno = TSDB_CODE_INVALID_PARA; + return 0; } int32_t taosRealPath(char *dirname, char *realPath, int32_t maxlen) { diff --git a/source/os/test/osDirTests.cpp b/source/os/test/osDirTests.cpp index e6d64d61a2..1d649addd2 100644 --- a/source/os/test/osDirTests.cpp +++ b/source/os/test/osDirTests.cpp @@ -269,7 +269,7 @@ TEST(osDirTests, taosExpandDir) { EXPECT_EQ(ret, 0); ret = taosExpandDir("", fullpath, 1024); - EXPECT_NE(ret, 0); + EXPECT_EQ(ret, 0); char dir2[2048] = {0}; for (int32_t i = 0; i < 2047; ++i) { From 325dcac84b36453a9722cafdc88ec24630f198c3 Mon Sep 17 00:00:00 2001 From: wangmm0220 Date: Mon, 9 Dec 2024 17:23:02 +0800 Subject: [PATCH 55/62] fix:[TD-33057] memory leak --- source/client/src/clientRawBlockWrite.c | 53 ++++++++++++------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/source/client/src/clientRawBlockWrite.c b/source/client/src/clientRawBlockWrite.c index 987bed1cf5..9ce2f726a5 100644 --- a/source/client/src/clientRawBlockWrite.c +++ b/source/client/src/clientRawBlockWrite.c @@ -94,9 +94,12 @@ static void buildCreateTableJson(SSchemaWrapper* schemaRow, SSchemaWrapper* sche cJSON* columns = cJSON_CreateArray(); RAW_NULL_CHECK(columns); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "columns", columns)); + for (int i = 0; i < schemaRow->nCols; i++) { cJSON* column = cJSON_CreateObject(); RAW_NULL_CHECK(column); + RAW_FALSE_CHECK(tmqAddJsonArrayItem(columns, column)); SSchema* s = schemaRow->pSchema + i; cJSON* cname = cJSON_CreateString(s->name); RAW_NULL_CHECK(cname); @@ -118,7 +121,6 @@ static void buildCreateTableJson(SSchemaWrapper* schemaRow, SSchemaWrapper* sche cJSON* isPk = cJSON_CreateBool(s->flags & COL_IS_KEY); RAW_NULL_CHECK(isPk); RAW_FALSE_CHECK(tmqAddJsonObjectItem(column, "isPrimarykey", isPk)); - RAW_FALSE_CHECK(tmqAddJsonArrayItem(columns, column)); if (pColCmprRow == NULL) { continue; @@ -150,13 +152,15 @@ static void buildCreateTableJson(SSchemaWrapper* schemaRow, SSchemaWrapper* sche RAW_NULL_CHECK(levelJson); RAW_FALSE_CHECK(tmqAddJsonObjectItem(column, "level", levelJson)); } - RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "columns", columns)); cJSON* tags = cJSON_CreateArray(); RAW_NULL_CHECK(tags); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tags", tags)); + for (int i = 0; schemaTag && i < schemaTag->nCols; i++) { cJSON* tag = cJSON_CreateObject(); RAW_NULL_CHECK(tag); + RAW_FALSE_CHECK(tmqAddJsonArrayItem(tags, tag)); SSchema* s = schemaTag->pSchema + i; cJSON* tname = cJSON_CreateString(s->name); RAW_NULL_CHECK(tname); @@ -175,9 +179,7 @@ static void buildCreateTableJson(SSchemaWrapper* schemaRow, SSchemaWrapper* sche RAW_NULL_CHECK(cbytes); RAW_FALSE_CHECK(tmqAddJsonObjectItem(tag, "length", cbytes)); } - RAW_FALSE_CHECK(tmqAddJsonArrayItem(tags, tag)); } - RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tags", tags)); end: *pJson = json; @@ -407,8 +409,9 @@ static void buildChildElement(cJSON* json, SVCreateTbReq* pCreateReq) { int64_t id = pCreateReq->uid; uint8_t tagNum = pCreateReq->ctb.tagNum; int32_t code = 0; - cJSON* tags = NULL; SArray* pTagVals = NULL; + char* pJson = NULL; + cJSON* tableName = cJSON_CreateString(name); RAW_NULL_CHECK(tableName); RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tableName", tableName)); @@ -419,8 +422,9 @@ static void buildChildElement(cJSON* json, SVCreateTbReq* pCreateReq) { RAW_NULL_CHECK(tagNumJson); RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tagNum", tagNumJson)); - tags = cJSON_CreateArray(); + cJSON* tags = cJSON_CreateArray(); RAW_NULL_CHECK(tags); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tags", tags)); RAW_RETURN_CHECK(tTagToValArray(pTag, &pTagVals)); if (tTagIsJson(pTag)) { STag* p = (STag*)pTag; @@ -428,14 +432,11 @@ static void buildChildElement(cJSON* json, SVCreateTbReq* pCreateReq) { uError("p->nTag == 0"); goto end; } - char* pJson = NULL; parseTagDatatoJson(pTag, &pJson); - if (pJson == NULL) { - uError("parseTagDatatoJson failed, pJson == NULL"); - goto end; - } + RAW_NULL_CHECK(pJson); cJSON* tag = cJSON_CreateObject(); RAW_NULL_CHECK(tag); + RAW_FALSE_CHECK(tmqAddJsonArrayItem(tags, tag)); STagVal* pTagVal = taosArrayGet(pTagVals, 0); RAW_NULL_CHECK(pTagVal); char* ptname = taosArrayGet(tagName, 0); @@ -449,8 +450,6 @@ static void buildChildElement(cJSON* json, SVCreateTbReq* pCreateReq) { cJSON* tvalue = cJSON_CreateString(pJson); RAW_NULL_CHECK(tvalue); RAW_FALSE_CHECK(tmqAddJsonObjectItem(tag, "value", tvalue)); - RAW_FALSE_CHECK(tmqAddJsonArrayItem(tags, tag)); - taosMemoryFree(pJson); goto end; } @@ -459,6 +458,7 @@ static void buildChildElement(cJSON* json, SVCreateTbReq* pCreateReq) { RAW_NULL_CHECK(pTagVal); cJSON* tag = cJSON_CreateObject(); RAW_NULL_CHECK(tag); + RAW_FALSE_CHECK(tmqAddJsonArrayItem(tags, tag)); char* ptname = taosArrayGet(tagName, i); RAW_NULL_CHECK(ptname); cJSON* tname = cJSON_CreateString(ptname); @@ -470,25 +470,22 @@ static void buildChildElement(cJSON* json, SVCreateTbReq* pCreateReq) { cJSON* tvalue = NULL; if (IS_VAR_DATA_TYPE(pTagVal->type)) { - char* buf = NULL; int64_t bufSize = 0; if (pTagVal->type == TSDB_DATA_TYPE_VARBINARY) { bufSize = pTagVal->nData * 2 + 2 + 3; } else { bufSize = pTagVal->nData + 3; } - buf = taosMemoryCalloc(bufSize, 1); - + char* buf = taosMemoryCalloc(bufSize, 1); RAW_NULL_CHECK(buf); - if (!buf) goto end; if (dataConverToStr(buf, bufSize, pTagVal->type, pTagVal->pData, pTagVal->nData, NULL) != TSDB_CODE_SUCCESS) { taosMemoryFree(buf); goto end; } tvalue = cJSON_CreateString(buf); - RAW_NULL_CHECK(tvalue); taosMemoryFree(buf); + RAW_NULL_CHECK(tvalue); } else { double val = 0; GET_TYPED_DATA(val, double, pTagVal->type, &pTagVal->i64); @@ -497,11 +494,10 @@ static void buildChildElement(cJSON* json, SVCreateTbReq* pCreateReq) { } RAW_FALSE_CHECK(tmqAddJsonObjectItem(tag, "value", tvalue)); - RAW_FALSE_CHECK(tmqAddJsonArrayItem(tags, tag)); } - RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tags", tags)); end: + taosMemoryFree(pJson); taosArrayDestroy(pTagVals); } @@ -521,13 +517,14 @@ static void buildCreateCTableJson(SVCreateTbReq* pCreateReq, int32_t nReqs, cJSO buildChildElement(json, pCreateReq); cJSON* createList = cJSON_CreateArray(); RAW_NULL_CHECK(createList); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "createList", createList)); + for (int i = 0; nReqs > 1 && i < nReqs; i++) { cJSON* create = cJSON_CreateObject(); RAW_NULL_CHECK(create); buildChildElement(create, pCreateReq + i); RAW_FALSE_CHECK(tmqAddJsonArrayItem(createList, create)); } - RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "createList", createList)); end: *pJson = json; @@ -789,9 +786,12 @@ static void processAlterTable(SMqMetaRsp* metaRsp, cJSON** pJson) { cJSON* tags = cJSON_CreateArray(); RAW_NULL_CHECK(tags); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tags", tags)); + for (int32_t i = 0; i < nTags; i++) { cJSON* member = cJSON_CreateObject(); RAW_NULL_CHECK(member); + RAW_FALSE_CHECK(tmqAddJsonArrayItem(tags, member)); SMultiTagUpateVal* pTagVal = taosArrayGet(vAlterTbReq.pMultiTag, i); cJSON* tagName = cJSON_CreateString(pTagVal->tagName); @@ -804,14 +804,13 @@ static void processAlterTable(SMqMetaRsp* metaRsp, cJSON** pJson) { } bool isNull = pTagVal->isNull; if (!isNull) { - char* buf = NULL; int64_t bufSize = 0; if (pTagVal->tagType == TSDB_DATA_TYPE_VARBINARY) { bufSize = pTagVal->nTagVal * 2 + 2 + 3; } else { bufSize = pTagVal->nTagVal + 3; } - buf = taosMemoryCalloc(bufSize, 1); + char* buf = taosMemoryCalloc(bufSize, 1); RAW_NULL_CHECK(buf); if (dataConverToStr(buf, bufSize, pTagVal->tagType, pTagVal->pTagVal, pTagVal->nTagVal, NULL) != TSDB_CODE_SUCCESS) { @@ -826,9 +825,7 @@ static void processAlterTable(SMqMetaRsp* metaRsp, cJSON** pJson) { cJSON* isNullCJson = cJSON_CreateBool(isNull); RAW_NULL_CHECK(isNullCJson); RAW_FALSE_CHECK(tmqAddJsonObjectItem(member, "colValueNull", isNullCJson)); - RAW_FALSE_CHECK(tmqAddJsonArrayItem(tags, member)); } - RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tags", tags)); break; } @@ -946,13 +943,14 @@ static void processDropTable(SMqMetaRsp* metaRsp, cJSON** pJson) { RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "type", type)); cJSON* tableNameList = cJSON_CreateArray(); RAW_NULL_CHECK(tableNameList); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tableNameList", tableNameList)); + for (int32_t iReq = 0; iReq < req.nReqs; iReq++) { SVDropTbReq* pDropTbReq = req.pReqs + iReq; cJSON* tableName = cJSON_CreateString(pDropTbReq->name); RAW_NULL_CHECK(tableName); RAW_FALSE_CHECK(tmqAddJsonArrayItem(tableNameList, tableName)); } - RAW_FALSE_CHECK(tmqAddJsonObjectItem(json, "tableNameList", tableNameList)); end: uDebug("processDropTable return"); @@ -2198,6 +2196,8 @@ static void processBatchMetaToJson(SMqBatchMetaRsp* pMsgRsp, char** string) { RAW_FALSE_CHECK(cJSON_AddStringToObject(pJson, "tmq_meta_version", TMQ_META_VERSION)); cJSON* pMetaArr = cJSON_CreateArray(); RAW_NULL_CHECK(pMetaArr); + RAW_FALSE_CHECK(tmqAddJsonObjectItem(pJson, "metas", pMetaArr)); + int32_t num = taosArrayGetSize(rsp.batchMetaReq); for (int32_t i = 0; i < num; i++) { int32_t* len = taosArrayGet(rsp.batchMetaLen, i); @@ -2216,7 +2216,6 @@ static void processBatchMetaToJson(SMqBatchMetaRsp* pMsgRsp, char** string) { RAW_FALSE_CHECK(tmqAddJsonArrayItem(pMetaArr, pItem)); } - RAW_FALSE_CHECK(tmqAddJsonObjectItem(pJson, "metas", pMetaArr)); tDeleteMqBatchMetaRsp(&rsp); char* fullStr = cJSON_PrintUnformatted(pJson); cJSON_Delete(pJson); From d29e87d5727a7e1c228323cc659aab29d42a9209 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Mon, 9 Dec 2024 09:41:42 +0000 Subject: [PATCH 56/62] enh: add unitest for osEnv.c --- .gitignore | 1 + source/os/test/CMakeLists.txt | 7 +++ source/os/test/osDirTests.cpp | 15 +++++- source/os/test/osEnvTests.cpp | 93 +++++++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 source/os/test/osEnvTests.cpp diff --git a/.gitignore b/.gitignore index 8f461f2b02..4e47039628 100644 --- a/.gitignore +++ b/.gitignore @@ -162,3 +162,4 @@ geos_c.h source/libs/parser/src/sql.c include/common/ttokenauto.h !packaging/smokeTest/pytest_require.txt +tdengine-test-dir diff --git a/source/os/test/CMakeLists.txt b/source/os/test/CMakeLists.txt index 81fb0ecb26..f0607fa612 100644 --- a/source/os/test/CMakeLists.txt +++ b/source/os/test/CMakeLists.txt @@ -85,6 +85,13 @@ add_test( COMMAND osDirTests ) +add_executable(osEnvTests "osEnvTests.cpp") +target_link_libraries(osEnvTests os util gtest_main) +add_test( + NAME osEnvTests + COMMAND osEnvTests +) + add_executable(osSemaphoreTests "osSemaphoreTests.cpp") target_link_libraries(osSemaphoreTests os util gtest_main) add_test( diff --git a/source/os/test/osDirTests.cpp b/source/os/test/osDirTests.cpp index 1d649addd2..53cd550e36 100644 --- a/source/os/test/osDirTests.cpp +++ b/source/os/test/osDirTests.cpp @@ -411,7 +411,6 @@ TEST(osDirTests, taosReadDir) { taosRemoveDir("/tmp/tdengine-test-dir"); } - TEST(osDirTests, taosGetDirSize) { TdDirEntryPtr rddir = taosReadDir(NULL); EXPECT_EQ(rddir, nullptr); @@ -448,4 +447,18 @@ TEST(osDirTests, taosGetDirSize) { EXPECT_EQ(ret, 0); taosRemoveDir("/tmp/tdengine-test-dir"); + + taosRemoveDir("./tdengine-test-dir/1/2/3/5"); + taosRemoveDir("./tdengine-test-dir/1/2/3/4"); + taosRemoveDir("./tdengine-test-dir/1/2/3"); + taosRemoveDir("./tdengine-test-dir/1/2"); + taosRemoveDir("./tdengine-test-dir/1"); + taosRemoveDir("./tdengine-test-dir/"); + taosRemoveDir("tdengine-test-dir/1/2/3/5"); + taosRemoveDir("tdengine-test-dir/1/2/3/4"); + taosRemoveDir("tdengine-test-dir/1/2/3"); + taosRemoveDir("tdengine-test-dir/1/2"); + taosRemoveDir("tdengine-test-dir/1"); + taosRemoveDir("tdengine-test-dir/"); + taosRemoveDir("tdengine-test-dir/"); } diff --git a/source/os/test/osEnvTests.cpp b/source/os/test/osEnvTests.cpp new file mode 100644 index 0000000000..d5b3cac8a6 --- /dev/null +++ b/source/os/test/osEnvTests.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic ignored "-Wformat" +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" +#pragma GCC diagnostic ignored "-Wpointer-arith" + +#include "os.h" +#include "tlog.h" + +TEST(osEnvTests, osDefaultInit) { + int32_t ret = 0; + + strcpy(tsTimezoneStr, ""); + strcpy(tsTempDir, ""); + tsNumOfCores = 0; + ret = osDefaultInit(); + EXPECT_EQ(ret, 0); + + strcpy(tsTempDir, "/tmp"); + ret = osDefaultInit(); + EXPECT_EQ(ret, 0); + + osCleanup(); +} + +TEST(osEnvTests, osUpdate) { + int32_t ret = 0; + + strcpy(tsLogDir, ""); + strcpy(tsDataDir, ""); + strcpy(tsTempDir, ""); + + ret = osUpdate(); + EXPECT_EQ(ret, 0); +} + +TEST(osEnvTests, osSufficient) { + bool ret = 0; + + tsLogSpace.size.avail = 10000; + tsDataSpace.size.avail = 10000; + tsTempSpace.size.avail = 10000; + tsLogSpace.reserved = 2000; + tsDataSpace.reserved = 2000; + tsDataSpace.reserved = 2000; + + ret = osLogSpaceAvailable(); + EXPECT_EQ(ret, true); + + ret = osTempSpaceAvailable(); + EXPECT_EQ(ret, true); + + ret = osDataSpaceAvailable(); + EXPECT_EQ(ret, true); + + ret = osLogSpaceSufficient(); + EXPECT_EQ(ret, true); + + ret = osDataSpaceSufficient(); + EXPECT_EQ(ret, true); + + ret = osTempSpaceSufficient(); + EXPECT_EQ(ret, true); + + osSetSystemLocale(NULL, NULL); + osSetSystemLocale(NULL, NULL); + osSetSystemLocale("1", "2"); + + osSetProcPath(1, NULL); + osSetProcPath(0, (char **)&ret); +} \ No newline at end of file From 89f7e42bee285b415017ee17a4e7fe5d0ec19f62 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Mon, 9 Dec 2024 09:51:49 +0000 Subject: [PATCH 57/62] enh: minor changes --- source/os/test/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/os/test/CMakeLists.txt b/source/os/test/CMakeLists.txt index f0607fa612..98b3b18616 100644 --- a/source/os/test/CMakeLists.txt +++ b/source/os/test/CMakeLists.txt @@ -78,6 +78,8 @@ add_test( COMMAND osAtomicTests ) +if(TD_LINUX) + add_executable(osDirTests "osDirTests.cpp") target_link_libraries(osDirTests os util gtest_main) add_test( @@ -92,6 +94,8 @@ add_test( COMMAND osEnvTests ) +endif() + add_executable(osSemaphoreTests "osSemaphoreTests.cpp") target_link_libraries(osSemaphoreTests os util gtest_main) add_test( From 3d83b74b2601f620c980d0c1fb8ae032af7a9664 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Mon, 9 Dec 2024 10:31:46 +0000 Subject: [PATCH 58/62] enh: minor changes --- source/os/test/osDirTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/os/test/osDirTests.cpp b/source/os/test/osDirTests.cpp index 53cd550e36..1dba7299be 100644 --- a/source/os/test/osDirTests.cpp +++ b/source/os/test/osDirTests.cpp @@ -283,7 +283,7 @@ TEST(osDirTests, taosExpandDir) { TEST(osDirTests, taosRealPath) { int32_t ret = 0; - char testDir[1024] = "/tmp/tdengine-test-dir"; + char testDir[PATH_MAX * 2] = "/tmp/tdengine-test-dir"; ret = taosMkDir(testDir); EXPECT_EQ(ret, 0); From 9b554aec8315dbfe31e1edc1696251143a3b96a2 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Mon, 9 Dec 2024 19:10:29 +0800 Subject: [PATCH 59/62] doc: default compress algorith --- docs/en/14-reference/03-taos-sql/31-compress.md | 16 +++++++++------- docs/zh/14-reference/03-taos-sql/32-compress.md | 16 +++++++++------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/docs/en/14-reference/03-taos-sql/31-compress.md b/docs/en/14-reference/03-taos-sql/31-compress.md index 39abfe69bd..2ac269a2e9 100644 --- a/docs/en/14-reference/03-taos-sql/31-compress.md +++ b/docs/en/14-reference/03-taos-sql/31-compress.md @@ -28,13 +28,15 @@ In this article, it specifically refers to the level within the secondary compre - Default compression algorithm list and applicable range for each data type -| Data Type | Optional Encoding Algorithm | Default Encoding Algorithm | Optional Compression Algorithm|Default Compression Algorithm| Default Compression Level| -| :-----------:|:----------:|:-------:|:-------:|:----------:|:----:| -| tinyint/untinyint/smallint/usmallint/int/uint | simple8b| simple8b | lz4/zlib/zstd/xz| lz4 | medium| -| bigint/ubigint/timestamp | simple8b/delta-i | delta-i |lz4/zlib/zstd/xz | lz4| medium| -|float/double | delta-d|delta-d |lz4/zlib/zstd/xz/tsz|lz4| medium| -|binary/nchar| disabled| disabled|lz4/zlib/zstd/xz| lz4| medium| -|bool| bit-packing| bit-packing| lz4/zlib/zstd/xz| lz4| medium| +| Data Type |Available Encoding Algorithms | Default Encoding Algorithm | Available Compression Algorithms | Default Compression Algorithm | Default Compression Level | +|:------------------------------------:|:----------------:|:-----------:|:--------------------:|:----:|:------:| +| int/uint | simple8b | simple8b | lz4/zlib/zstd/xz | lz4 | medium | +| tinyint/untinyint/smallint/usmallint | simple8b | simple8b | lz4/zlib/zstd/xz | zlib | medium | +| bigint/ubigint/timestamp | simple8b/delta-i | delta-i | lz4/zlib/zstd/xz | lz4 | medium | +| float/double | delta-d | delta-d | lz4/zlib/zstd/xz/tsz | lz4 | medium | +| binary/nchar | disabled | disabled | lz4/zlib/zstd/xz | zstd | medium | +| bool | bit-packing | bit-packing | lz4/zlib/zstd/xz | zstd | medium | + ## SQL diff --git a/docs/zh/14-reference/03-taos-sql/32-compress.md b/docs/zh/14-reference/03-taos-sql/32-compress.md index 0f2b260832..2ef6e9e06a 100644 --- a/docs/zh/14-reference/03-taos-sql/32-compress.md +++ b/docs/zh/14-reference/03-taos-sql/32-compress.md @@ -29,13 +29,15 @@ description: 可配置压缩算法 - 各个数据类型的默认压缩算法列表和适用范围 -| 数据类型 | 可选编码算法 | 编码算法默认值 | 可选压缩算法|压缩算法默认值| 压缩等级默认值| -| :-----------:|:----------:|:-------:|:-------:|:----------:|:----:| -| tinyint/untinyint/smallint/usmallint/int/uint | simple8b| simple8b | lz4/zlib/zstd/xz| lz4 | medium| -| bigint/ubigint/timestamp | simple8b/delta-i | delta-i |lz4/zlib/zstd/xz | lz4| medium| -|float/double | delta-d|delta-d |lz4/zlib/zstd/xz/tsz|lz4| medium| -|binary/nchar| disabled| disabled|lz4/zlib/zstd/xz| lz4| medium| -|bool| bit-packing| bit-packing| lz4/zlib/zstd/xz| lz4| medium| +| 数据类型 | 可选编码算法 | 编码算法默认值 | 可选压缩算法 | 压缩算法默认值 |压缩等级默认值| +|:------------------------------------:|:----------------:|:-----------:|:--------------------:|:----:|:------:| +| int/uint | simple8b | simple8b | lz4/zlib/zstd/xz | lz4 | medium | +| tinyint/untinyint/smallint/usmallint | simple8b | simple8b | lz4/zlib/zstd/xz | zlib | medium | +| bigint/ubigint/timestamp | simple8b/delta-i | delta-i | lz4/zlib/zstd/xz | lz4 | medium | +| float/double | delta-d | delta-d | lz4/zlib/zstd/xz/tsz | lz4 | medium | +| binary/nchar | disabled | disabled | lz4/zlib/zstd/xz | zstd | medium | +| bool | bit-packing | bit-packing | lz4/zlib/zstd/xz | zstd | medium | + ## SQL 语法 From b8c32776c96fe6c0d149ddd2cac31ebfc77801fc Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Mon, 9 Dec 2024 19:12:11 +0800 Subject: [PATCH 60/62] doc: default compress algorithm --- docs/en/14-reference/03-taos-sql/32-compress.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/en/14-reference/03-taos-sql/32-compress.md b/docs/en/14-reference/03-taos-sql/32-compress.md index efe1959b1a..8bb2ae31e3 100644 --- a/docs/en/14-reference/03-taos-sql/32-compress.md +++ b/docs/en/14-reference/03-taos-sql/32-compress.md @@ -28,13 +28,14 @@ In this document, it specifically refers to the internal levels of the second-le - Default compression algorithms list and applicable range for each data type -| Data Type | Available Encoding Algorithms | Default Encoding Algorithm | Available Compression Algorithms|Default Compression Algorithm| Default Compression Level| -| :-----------:|:----------:|:-------:|:-------:|:----------:|:----:| -| tinyint/untinyint/smallint/usmallint/int/uint | simple8b| simple8b | lz4/zlib/zstd/xz| lz4 | medium| -| bigint/ubigint/timestamp | simple8b/delta-i | delta-i |lz4/zlib/zstd/xz | lz4| medium| -|float/double | delta-d|delta-d |lz4/zlib/zstd/xz/tsz|lz4| medium| -|binary/nchar| disabled| disabled|lz4/zlib/zstd/xz| lz4| medium| -|bool| bit-packing| bit-packing| lz4/zlib/zstd/xz| lz4| medium| +| Data Type |Available Encoding Algorithms | Default Encoding Algorithm | Available Compression Algorithms | Default Compression Algorithm | Default Compression Level | +|:------------------------------------:|:----------------:|:-----------:|:--------------------:|:----:|:------:| +| int/uint | simple8b | simple8b | lz4/zlib/zstd/xz | lz4 | medium | +| tinyint/untinyint/smallint/usmallint | simple8b | simple8b | lz4/zlib/zstd/xz | zlib | medium | +| bigint/ubigint/timestamp | simple8b/delta-i | delta-i | lz4/zlib/zstd/xz | lz4 | medium | +| float/double | delta-d | delta-d | lz4/zlib/zstd/xz/tsz | lz4 | medium | +| binary/nchar | disabled | disabled | lz4/zlib/zstd/xz | zstd | medium | +| bool | bit-packing | bit-packing | lz4/zlib/zstd/xz | zstd | medium | ## SQL Syntax From 6259dcc8bd9ccc8729efa68c3bcc4a8027d606d3 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Mon, 9 Dec 2024 11:58:22 +0000 Subject: [PATCH 61/62] enh: add heaptest --- source/os/test/CMakeLists.txt | 5 +++-- source/util/test/CMakeLists.txt | 7 +++++++ source/util/test/heapTest.cpp | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/source/os/test/CMakeLists.txt b/source/os/test/CMakeLists.txt index 98b3b18616..13fea463f7 100644 --- a/source/os/test/CMakeLists.txt +++ b/source/os/test/CMakeLists.txt @@ -71,6 +71,9 @@ add_test( COMMAND osTimeTests ) + +if(TD_LINUX) + add_executable(osAtomicTests "osAtomicTests.cpp") target_link_libraries(osAtomicTests os util gtest_main) add_test( @@ -78,8 +81,6 @@ add_test( COMMAND osAtomicTests ) -if(TD_LINUX) - add_executable(osDirTests "osDirTests.cpp") target_link_libraries(osDirTests os util gtest_main) add_test( diff --git a/source/util/test/CMakeLists.txt b/source/util/test/CMakeLists.txt index e801008970..55da8c0929 100644 --- a/source/util/test/CMakeLists.txt +++ b/source/util/test/CMakeLists.txt @@ -33,6 +33,13 @@ ENDIF() INCLUDE_DIRECTORIES(${TD_SOURCE_DIR}/src/util/inc) INCLUDE_DIRECTORIES(${TD_SOURCE_DIR}/include/common) +add_executable(heapTest "heapTest.cpp") +target_link_libraries(heapTest os util gtest_main) +add_test( + NAME heapTest + COMMAND heapTest +) + # arrayTest add_executable(arrayTest "arrayTest.cpp") target_link_libraries(arrayTest os util gtest_main) diff --git a/source/util/test/heapTest.cpp b/source/util/test/heapTest.cpp index 51eeb26ed3..fd61e5032b 100644 --- a/source/util/test/heapTest.cpp +++ b/source/util/test/heapTest.cpp @@ -20,7 +20,7 @@ int32_t heapCompare(const HeapNode* a, const HeapNode* b) { return 1; } -TEST(TD_UTIL_HEAP_TEST, heapTest) { +TEST(heapTest, heapTest) { Heap* heap = heapCreate(heapCompare); ASSERT_TRUE(heap != NULL); ASSERT_EQ(0, heapSize(heap)); From 4268099bdc154094000f6a1e27190723b1d9e77d Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Tue, 10 Dec 2024 01:31:50 +0000 Subject: [PATCH 62/62] fix: ci errors --- tests/system-test/2-query/union.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system-test/2-query/union.py b/tests/system-test/2-query/union.py index fc6dd4fb32..24ccac5d90 100644 --- a/tests/system-test/2-query/union.py +++ b/tests/system-test/2-query/union.py @@ -434,7 +434,7 @@ class TDTestCase: tdSql.checkRows(2) sql = "select db_name `TABLE_CAT`, '' `TABLE_SCHEM`, stable_name `TABLE_NAME`, 'TABLE' `TABLE_TYPE`, table_comment `REMARKS` from information_schema.ins_stables union all select db_name `TABLE_CAT`, '' `TABLE_SCHEM`, table_name `TABLE_NAME`, case when `type`='SYSTEM_TABLE' then 'TABLE' when `type`='NORMAL_TABLE' then 'TABLE' when `type`='CHILD_TABLE' then 'TABLE' else 'UNKNOWN' end `TABLE_TYPE`, table_comment `REMARKS` from information_schema.ins_tables union all select db_name `TABLE_CAT`, '' `TABLE_SCHEM`, view_name `TABLE_NAME`, 'VIEW' `TABLE_TYPE`, NULL `REMARKS` from information_schema.ins_views" tdSql.query(sql, queryTimes=1) - tdSql.checkRows(47) + tdSql.checkRows(48) def stop(self): tdSql.close()