diff --git a/include/common/tmsg.h b/include/common/tmsg.h index 9ec80293a838f9ee825dc77e97f31b12d621caf6..aaad7f5b52871ff98713a36d3235ece60bede6f9 100644 --- a/include/common/tmsg.h +++ b/include/common/tmsg.h @@ -328,6 +328,9 @@ typedef struct { int8_t alterType; int32_t numOfFields; SArray* pFields; + int32_t ttl; + int32_t commentLen; + char* comment; } SMAlterStbReq; int32_t tSerializeSMAlterStbReq(void* buf, int32_t bufLen, SMAlterStbReq* pReq); diff --git a/include/libs/nodes/nodes.h b/include/libs/nodes/nodes.h index 702dd50df55e6fa98d555a796b8570eaf1e04883..05c9da1a8acb6fdf22ea3e034368814bdc7a9978 100644 --- a/include/libs/nodes/nodes.h +++ b/include/libs/nodes/nodes.h @@ -179,6 +179,7 @@ typedef enum ENodeType { QUERY_NODE_KILL_CONNECTION_STMT, QUERY_NODE_KILL_QUERY_STMT, QUERY_NODE_KILL_TRANSACTION_STMT, + QUERY_NODE_QUERY, // logic plan node QUERY_NODE_LOGIC_PLAN_SCAN, diff --git a/include/libs/nodes/querynodes.h b/include/libs/nodes/querynodes.h index 0a835dae83fd636874206112dce950c0b0d48462..c0e2ec91e0610ba53512aa1a27f8840a881ded15 100644 --- a/include/libs/nodes/querynodes.h +++ b/include/libs/nodes/querynodes.h @@ -295,6 +295,37 @@ typedef struct SExplainStmt { SNode* pQuery; } SExplainStmt; +typedef struct SCmdMsgInfo { + int16_t msgType; + SEpSet epSet; + void* pMsg; + int32_t msgLen; + void* pExtension; // todo remove it soon +} SCmdMsgInfo; + +typedef enum EQueryExecMode { + QUERY_EXEC_MODE_LOCAL = 1, + QUERY_EXEC_MODE_RPC, + QUERY_EXEC_MODE_SCHEDULE, + QUERY_EXEC_MODE_EMPTY_RESULT +} EQueryExecMode; + +typedef struct SQuery { + ENodeType type; + EQueryExecMode execMode; + bool haveResultSet; + SNode* pRoot; + int32_t numOfResCols; + SSchema* pResSchema; + int8_t precision; + SCmdMsgInfo* pCmdMsg; + int32_t msgType; + SArray* pDbList; + SArray* pTableList; + bool showRewrite; + int32_t placeholderNum; +} SQuery; + void nodesWalkSelectStmt(SSelectStmt* pSelect, ESqlClause clause, FNodeWalker walker, void* pContext); void nodesRewriteSelectStmt(SSelectStmt* pSelect, ESqlClause clause, FNodeRewriter rewriter, void* pContext); diff --git a/include/libs/parser/parser.h b/include/libs/parser/parser.h index 998d45aee155b120eabb33468f98d48d01a4e16f..a8bcac1c424fa262345f6f627a7ac0940920b34c 100644 --- a/include/libs/parser/parser.h +++ b/include/libs/parser/parser.h @@ -48,36 +48,6 @@ typedef struct SParseContext { bool isSuperUser; } SParseContext; -typedef struct SCmdMsgInfo { - int16_t msgType; - SEpSet epSet; - void* pMsg; - int32_t msgLen; - void* pExtension; // todo remove it soon -} SCmdMsgInfo; - -typedef enum EQueryExecMode { - QUERY_EXEC_MODE_LOCAL = 1, - QUERY_EXEC_MODE_RPC, - QUERY_EXEC_MODE_SCHEDULE, - QUERY_EXEC_MODE_EMPTY_RESULT -} EQueryExecMode; - -typedef struct SQuery { - EQueryExecMode execMode; - bool haveResultSet; - SNode* pRoot; - int32_t numOfResCols; - SSchema* pResSchema; - int8_t precision; - SCmdMsgInfo* pCmdMsg; - int32_t msgType; - SArray* pDbList; - SArray* pTableList; - bool showRewrite; - int32_t placeholderNum; -} SQuery; - int32_t qParseQuerySql(SParseContext* pCxt, SQuery** pQuery); bool isInsertSql(const char* pStr, size_t length); @@ -103,9 +73,10 @@ void destroyBoundColumnInfo(void* pBoundInfo); int32_t qCreateSName(SName* pName, const char* pTableName, int32_t acctId, char* dbName, char* msgBuf, int32_t msgBufLen); -void* smlInitHandle(SQuery *pQuery); -void smlDestroyHandle(void *pHandle); -int32_t smlBindData(void *handle, SArray *tags, SArray *colsFormat, SArray *colsSchema, SArray *cols, bool format, STableMeta *pTableMeta, char *tableName, char *msgBuf, int16_t msgBufLen); +void* smlInitHandle(SQuery* pQuery); +void smlDestroyHandle(void* pHandle); +int32_t smlBindData(void* handle, SArray* tags, SArray* colsFormat, SArray* colsSchema, SArray* cols, bool format, + STableMeta* pTableMeta, char* tableName, char* msgBuf, int16_t msgBufLen); int32_t smlBuildOutput(void* handle, SHashObj* pVgHash); #ifdef __cplusplus diff --git a/include/util/taoserror.h b/include/util/taoserror.h index 6a57b8d53ea30a50613a3bc2885299d548c4da30..addc478673d312c18a60631e00100b771ae91c0b 100644 --- a/include/util/taoserror.h +++ b/include/util/taoserror.h @@ -632,6 +632,7 @@ int32_t* taosGetErrno(); #define TSDB_CODE_PAR_INVALID_VAR_COLUMN_LEN TAOS_DEF_ERROR_CODE(0, 0x2642) #define TSDB_CODE_PAR_INVALID_TAGS_NUM TAOS_DEF_ERROR_CODE(0, 0x2643) #define TSDB_CODE_PAR_PERMISSION_DENIED TAOS_DEF_ERROR_CODE(0, 0x2644) +#define TSDB_CODE_PAR_INVALID_STREAM_QUERY TAOS_DEF_ERROR_CODE(0, 0x2645) //planner #define TSDB_CODE_PLAN_INTERNAL_ERROR TAOS_DEF_ERROR_CODE(0, 0x2700) diff --git a/source/common/src/tmsg.c b/source/common/src/tmsg.c index 56bb93faa4090689e65d66610a566902207872e4..0853d48d67ac127bfc12f8fe1158d9bba404715a 100644 --- a/source/common/src/tmsg.c +++ b/source/common/src/tmsg.c @@ -607,6 +607,11 @@ int32_t tSerializeSMAlterStbReq(void *buf, int32_t bufLen, SMAlterStbReq *pReq) if (tEncodeI32(&encoder, pField->bytes) < 0) return -1; if (tEncodeCStr(&encoder, pField->name) < 0) return -1; } + if (tEncodeI32(&encoder, pReq->ttl) < 0) return -1; + if (tEncodeI32(&encoder, pReq->commentLen) < 0) return -1; + if (pReq->commentLen > 0) { + if (tEncodeCStr(&encoder, pReq->comment) < 0) return -1; + } tEndEncode(&encoder); int32_t tlen = encoder.pos; @@ -639,6 +644,14 @@ int32_t tDeserializeSMAlterStbReq(void *buf, int32_t bufLen, SMAlterStbReq *pReq } } + if (tDecodeI32(&decoder, &pReq->ttl) < 0) return -1; + if (tDecodeI32(&decoder, &pReq->commentLen) < 0) return -1; + if (pReq->commentLen > 0) { + pReq->comment = taosMemoryMalloc(pReq->commentLen); + if (pReq->comment == NULL) return -1; + if (tDecodeCStrTo(&decoder, pReq->comment) < 0) return -1; + } + tEndDecode(&decoder); tDecoderClear(&decoder); return 0; diff --git a/source/libs/function/src/builtins.c b/source/libs/function/src/builtins.c index b7bd0235816a1437eb268cec08d8d67a912e05f5..b88c3493b96cb42a302ffff21cc77a3f1ef09069 100644 --- a/source/libs/function/src/builtins.c +++ b/source/libs/function/src/builtins.c @@ -959,6 +959,16 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = { .sprocessFunc = NULL, .finalizeFunc = NULL }, + { + .name = "_c0", + .type = FUNCTION_TYPE_ROWTS, + .classification = FUNC_MGT_PSEUDO_COLUMN_FUNC, + .translateFunc = translateTimePseudoColumn, + .getEnvFunc = getTimePseudoFuncEnv, + .initFunc = NULL, + .sprocessFunc = NULL, + .finalizeFunc = NULL + }, { .name = "tbname", .type = FUNCTION_TYPE_TBNAME, diff --git a/source/libs/parser/src/parAstCreater.c b/source/libs/parser/src/parAstCreater.c index e8ac5620720b59ed85f0bec546ad2f9a948a0cbe..a9481593e08daba1599381b9e8e08b39bd03e74b 100644 --- a/source/libs/parser/src/parAstCreater.c +++ b/source/libs/parser/src/parAstCreater.c @@ -907,6 +907,13 @@ SNode* createDropSuperTableStmt(SAstCreateContext* pCxt, bool ignoreNotExists, S return (SNode*)pStmt; } +static SNode* createAlterTableStmtFinalize(SNode* pRealTable, SAlterTableStmt* pStmt) { + strcpy(pStmt->dbName, ((SRealTableNode*)pRealTable)->table.dbName); + strcpy(pStmt->tableName, ((SRealTableNode*)pRealTable)->table.tableName); + nodesDestroyNode(pRealTable); + return (SNode*)pStmt; +} + SNode* createAlterTableModifyOptions(SAstCreateContext* pCxt, SNode* pRealTable, SNode* pOptions) { if (NULL == pRealTable) { return NULL; @@ -915,7 +922,7 @@ SNode* createAlterTableModifyOptions(SAstCreateContext* pCxt, SNode* pRealTable, CHECK_OUT_OF_MEM(pStmt); pStmt->alterType = TSDB_ALTER_TABLE_UPDATE_OPTIONS; pStmt->pOptions = (STableOptions*)pOptions; - return (SNode*)pStmt; + return createAlterTableStmtFinalize(pRealTable, pStmt); } SNode* createAlterTableAddModifyCol(SAstCreateContext* pCxt, SNode* pRealTable, int8_t alterType, @@ -928,7 +935,7 @@ SNode* createAlterTableAddModifyCol(SAstCreateContext* pCxt, SNode* pRealTable, pStmt->alterType = alterType; strncpy(pStmt->colName, pColName->z, pColName->n); pStmt->dataType = dataType; - return (SNode*)pStmt; + return createAlterTableStmtFinalize(pRealTable, pStmt); } SNode* createAlterTableDropCol(SAstCreateContext* pCxt, SNode* pRealTable, int8_t alterType, const SToken* pColName) { @@ -939,7 +946,7 @@ SNode* createAlterTableDropCol(SAstCreateContext* pCxt, SNode* pRealTable, int8_ CHECK_OUT_OF_MEM(pStmt); pStmt->alterType = alterType; strncpy(pStmt->colName, pColName->z, pColName->n); - return (SNode*)pStmt; + return createAlterTableStmtFinalize(pRealTable, pStmt); } SNode* createAlterTableRenameCol(SAstCreateContext* pCxt, SNode* pRealTable, int8_t alterType, @@ -952,7 +959,7 @@ SNode* createAlterTableRenameCol(SAstCreateContext* pCxt, SNode* pRealTable, int pStmt->alterType = alterType; strncpy(pStmt->colName, pOldColName->z, pOldColName->n); strncpy(pStmt->newColName, pNewColName->z, pNewColName->n); - return (SNode*)pStmt; + return createAlterTableStmtFinalize(pRealTable, pStmt); } SNode* createAlterTableSetTag(SAstCreateContext* pCxt, SNode* pRealTable, const SToken* pTagName, SNode* pVal) { @@ -964,7 +971,7 @@ SNode* createAlterTableSetTag(SAstCreateContext* pCxt, SNode* pRealTable, const pStmt->alterType = TSDB_ALTER_TABLE_UPDATE_TAG_VAL; strncpy(pStmt->colName, pTagName->z, pTagName->n); pStmt->pVal = (SValueNode*)pVal; - return (SNode*)pStmt; + return createAlterTableStmtFinalize(pRealTable, pStmt); } SNode* createUseDatabaseStmt(SAstCreateContext* pCxt, SToken* pDbName) { diff --git a/source/libs/parser/src/parTokenizer.c b/source/libs/parser/src/parTokenizer.c index 01327c08efb4a7de9f811e68bbd2d96156b4f3f8..abc7ddb17f4b6ea4cd9a859637fe3886dffa21fc 100644 --- a/source/libs/parser/src/parTokenizer.c +++ b/source/libs/parser/src/parTokenizer.c @@ -214,6 +214,7 @@ static SKeyword keywordTable[] = { {"WINDOW_CLOSE", TK_WINDOW_CLOSE}, {"WITH", TK_WITH}, {"WRITE", TK_WRITE}, + {"_C0", TK_ROWTS}, {"_QENDTS", TK_QENDTS}, {"_QSTARTTS", TK_QSTARTTS}, {"_ROWTS", TK_ROWTS}, diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index d40da8a6298b82f578db71cc8fd4ffe43a0191bc..e6b0d186456ed0f3bbe2a9828fb4cbef1e22d445 100644 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -782,6 +782,7 @@ static EDealRes rewriteColToSelectValFunc(STranslateContext* pCxt, bool* pHasSel return DEAL_RES_ERROR; } strcpy(pFunc->functionName, "_select_value"); + strcpy(pFunc->node.aliasName, ((SExprNode*)*pNode)->aliasName); pCxt->errCode = nodesListMakeAppend(&pFunc->pParameterList, *pNode); if (TSDB_CODE_SUCCESS == pCxt->errCode) { translateFunction(pCxt, pFunc); @@ -2540,10 +2541,18 @@ static int32_t buildCreateStbReq(STranslateContext* pCxt, SCreateTableStmt* pStm pReq->igExists = pStmt->ignoreExists; pReq->xFilesFactor = pStmt->pOptions->filesFactor; pReq->delay = pStmt->pOptions->delay; + pReq->ttl = pStmt->pOptions->ttl; columnDefNodeToField(pStmt->pCols, &pReq->pColumns); columnDefNodeToField(pStmt->pTags, &pReq->pTags); pReq->numOfColumns = LIST_LENGTH(pStmt->pCols); pReq->numOfTags = LIST_LENGTH(pStmt->pTags); + if ('\0' != pStmt->pOptions->comment[0]) { + pReq->comment = strdup(pStmt->pOptions->comment); + if (NULL == pReq->comment) { + return TSDB_CODE_OUT_OF_MEMORY; + } + pReq->commentLen = strlen(pStmt->pOptions->comment) + 1; + } SName tableName; tNameExtractFullName(toName(pCxt->pParseCxt->acctId, pStmt->dbName, pStmt->tableName, &tableName), pReq->name); @@ -2602,6 +2611,18 @@ static int32_t translateDropSuperTable(STranslateContext* pCxt, SDropSuperTableS } static int32_t setAlterTableField(SAlterTableStmt* pStmt, SMAlterStbReq* pAlterReq) { + if (TSDB_ALTER_TABLE_UPDATE_OPTIONS == pStmt->alterType) { + pAlterReq->ttl = pStmt->pOptions->ttl; + if ('\0' != pStmt->pOptions->comment[0]) { + pAlterReq->comment = strdup(pStmt->pOptions->comment); + if (NULL == pAlterReq->comment) { + return TSDB_CODE_OUT_OF_MEMORY; + } + pAlterReq->commentLen = strlen(pStmt->pOptions->comment) + 1; + } + return TSDB_CODE_SUCCESS; + } + pAlterReq->pFields = taosArrayInit(2, sizeof(TAOS_FIELD)); if (NULL == pAlterReq->pFields) { return TSDB_CODE_OUT_OF_MEMORY; @@ -2614,7 +2635,7 @@ static int32_t setAlterTableField(SAlterTableStmt* pStmt, SMAlterStbReq* pAlterR case TSDB_ALTER_TABLE_DROP_COLUMN: case TSDB_ALTER_TABLE_UPDATE_COLUMN_BYTES: case TSDB_ALTER_TABLE_UPDATE_TAG_BYTES: { - TAOS_FIELD field = {.type = pStmt->dataType.type, .bytes = pStmt->dataType.bytes}; + TAOS_FIELD field = {.type = pStmt->dataType.type, .bytes = calcTypeBytes(pStmt->dataType)}; strcpy(field.name, pStmt->colName); taosArrayPush(pAlterReq->pFields, &field); break; @@ -2625,7 +2646,7 @@ static int32_t setAlterTableField(SAlterTableStmt* pStmt, SMAlterStbReq* pAlterR strcpy(oldField.name, pStmt->colName); taosArrayPush(pAlterReq->pFields, &oldField); TAOS_FIELD newField = {0}; - strcpy(oldField.name, pStmt->newColName); + strcpy(newField.name, pStmt->newColName); taosArrayPush(pAlterReq->pFields, &newField); break; } @@ -2642,7 +2663,7 @@ static int32_t translateAlterTable(STranslateContext* pCxt, SAlterTableStmt* pSt SName tableName; tNameExtractFullName(toName(pCxt->pParseCxt->acctId, pStmt->dbName, pStmt->tableName, &tableName), alterReq.name); alterReq.alterType = pStmt->alterType; - if (TSDB_ALTER_TABLE_UPDATE_OPTIONS == pStmt->alterType || TSDB_ALTER_TABLE_UPDATE_TAG_VAL == pStmt->alterType) { + if (TSDB_ALTER_TABLE_UPDATE_TAG_VAL == pStmt->alterType) { return TSDB_CODE_FAILED; } else { if (TSDB_CODE_SUCCESS != setAlterTableField(pStmt, &alterReq)) { @@ -2929,7 +2950,6 @@ static int32_t buildCreateTopicReq(STranslateContext* pCxt, SCreateTopicStmt* pS SName name; tNameSetDbName(&name, pCxt->pParseCxt->acctId, pStmt->topicName, strlen(pStmt->topicName)); tNameGetFullDbName(&name, pReq->name); - /*tNameExtractFullName(toName(pCxt->pParseCxt->acctId, pCxt->pParseCxt->db, pStmt->topicName, &name), pReq->name);*/ pReq->igExists = pStmt->ignoreExists; pReq->withTbName = pStmt->pOptions->withTable; pReq->withSchema = pStmt->pOptions->withSchema; @@ -2993,7 +3013,8 @@ static int32_t translateDropTopic(STranslateContext* pCxt, SDropTopicStmt* pStmt SMDropTopicReq dropReq = {0}; SName name; - tNameExtractFullName(toName(pCxt->pParseCxt->acctId, pCxt->pParseCxt->db, pStmt->topicName, &name), dropReq.name); + tNameSetDbName(&name, pCxt->pParseCxt->acctId, pStmt->topicName, strlen(pStmt->topicName)); + tNameGetFullDbName(&name, dropReq.name); dropReq.igNotExists = pStmt->ignoreNotExists; return buildCmdMsg(pCxt, TDMT_MND_DROP_TOPIC, (FSerializeFunc)tSerializeSMDropTopicReq, &dropReq); @@ -3033,28 +3054,48 @@ static int32_t translateKillTransaction(STranslateContext* pCxt, SKillStmt* pStm return buildCmdMsg(pCxt, TDMT_MND_KILL_TRANS, (FSerializeFunc)tSerializeSKillTransReq, &killReq); } -static int32_t translateCreateStream(STranslateContext* pCxt, SCreateStreamStmt* pStmt) { - SCMCreateStreamReq createReq = {0}; +static int32_t checkCreateStream(STranslateContext* pCxt, SCreateStreamStmt* pStmt) { + if (NULL == pStmt->pQuery) { + return TSDB_CODE_SUCCESS; + } - createReq.igExists = pStmt->ignoreExists; + if (QUERY_NODE_SELECT_STMT == nodeType(pStmt->pQuery)) { + SSelectStmt* pSelect = (SSelectStmt*)pStmt->pQuery; + if (QUERY_NODE_REAL_TABLE == nodeType(pSelect->pFromTable)) { + return TSDB_CODE_SUCCESS; + } + } + + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_STREAM_QUERY); +} + +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); + tNameGetFullDbName(&name, pDbFName); +} + +static int32_t buildCreateStreamReq(STranslateContext* pCxt, SCreateStreamStmt* pStmt, SCMCreateStreamReq* pReq) { + pReq->igExists = pStmt->ignoreExists; SName name; - tNameExtractFullName(toName(pCxt->pParseCxt->acctId, pCxt->pParseCxt->db, pStmt->streamName, &name), createReq.name); + tNameExtractFullName(toName(pCxt->pParseCxt->acctId, pCxt->pParseCxt->db, pStmt->streamName, &name), pReq->name); if ('\0' != pStmt->targetTabName[0]) { strcpy(name.dbname, pStmt->targetDbName); strcpy(name.tname, pStmt->targetTabName); - tNameExtractFullName(&name, createReq.targetStbFullName); + tNameExtractFullName(&name, pReq->targetStbFullName); } int32_t code = translateQuery(pCxt, pStmt->pQuery); if (TSDB_CODE_SUCCESS == code) { - code = nodesNodeToString(pStmt->pQuery, false, &createReq.ast, NULL); + getSourceDatabase(pStmt->pQuery, pCxt->pParseCxt->acctId, pReq->sourceDB); + code = nodesNodeToString(pStmt->pQuery, false, &pReq->ast, NULL); } if (TSDB_CODE_SUCCESS == code) { - createReq.sql = strdup(pCxt->pParseCxt->pSql); - if (NULL == createReq.sql) { + pReq->sql = strdup(pCxt->pParseCxt->pSql); + if (NULL == pReq->sql) { code = TSDB_CODE_OUT_OF_MEMORY; } } @@ -3064,11 +3105,20 @@ static int32_t translateCreateStream(STranslateContext* pCxt, SCreateStreamStmt* : TSDB_CODE_SUCCESS; } if (TSDB_CODE_SUCCESS == code) { - createReq.triggerType = pStmt->pOptions->triggerType; - createReq.watermark = - (NULL != pStmt->pOptions->pWatermark ? ((SValueNode*)pStmt->pOptions->pWatermark)->datum.i : 0); + pReq->triggerType = pStmt->pOptions->triggerType; + pReq->watermark = (NULL != pStmt->pOptions->pWatermark ? ((SValueNode*)pStmt->pOptions->pWatermark)->datum.i : 0); } + return code; +} + +static int32_t translateCreateStream(STranslateContext* pCxt, SCreateStreamStmt* pStmt) { + SCMCreateStreamReq createReq = {0}; + + int32_t code = checkCreateStream(pCxt, pStmt); + if (TSDB_CODE_SUCCESS == code) { + code = buildCreateStreamReq(pCxt, pStmt, &createReq); + } if (TSDB_CODE_SUCCESS == code) { code = buildCmdMsg(pCxt, TDMT_MND_CREATE_STREAM, (FSerializeFunc)tSerializeSCMCreateStreamReq, &createReq); } diff --git a/source/libs/parser/test/parInitialATest.cpp b/source/libs/parser/test/parInitialATest.cpp index 5bd9eb5c43ce6736fe4085085b93bca2a3599b25..4ddb7736b2cf545f0f05981d43ef0574a77154b6 100644 --- a/source/libs/parser/test/parInitialATest.cpp +++ b/source/libs/parser/test/parInitialATest.cpp @@ -19,7 +19,7 @@ using namespace std; namespace ParserTest { -class ParserInitialATest : public ParserTestBase {}; +class ParserInitialATest : public ParserDdlTest {}; TEST_F(ParserInitialATest, alterAccount) { useDb("root", "test"); @@ -72,16 +72,103 @@ TEST_F(ParserInitialATest, alterDatabase) { TEST_F(ParserInitialATest, alterTable) { useDb("root", "test"); - // run("ALTER TABLE t1 TTL 10"); - // run("ALTER TABLE t1 COMMENT 'test'"); + SMAlterStbReq expect = {0}; + + auto setAlterStbReqFunc = [&](const char* pTbname, int8_t alterType, int32_t numOfFields = 0, + const char* pField1Name = nullptr, int8_t field1Type = 0, int32_t field1Bytes = 0, + const char* pField2Name = nullptr, const char* pComment = nullptr, + int32_t ttl = TSDB_DEFAULT_TABLE_TTL) { + int32_t len = snprintf(expect.name, sizeof(expect.name), "0.test.%s", pTbname); + expect.name[len] = '\0'; + expect.alterType = alterType; + expect.ttl = ttl; + if (nullptr != pComment) { + expect.comment = strdup(pComment); + expect.commentLen = strlen(pComment) + 1; + } + + expect.numOfFields = numOfFields; + if (NULL == expect.pFields) { + expect.pFields = taosArrayInit(2, sizeof(TAOS_FIELD)); + TAOS_FIELD field = {0}; + taosArrayPush(expect.pFields, &field); + taosArrayPush(expect.pFields, &field); + } + + TAOS_FIELD* pField = (TAOS_FIELD*)taosArrayGet(expect.pFields, 0); + if (NULL != pField1Name) { + strcpy(pField->name, pField1Name); + pField->name[strlen(pField1Name)] = '\0'; + } else { + memset(pField, 0, sizeof(TAOS_FIELD)); + } + pField->type = field1Type; + pField->bytes = field1Bytes > 0 ? field1Bytes : (field1Type > 0 ? tDataTypes[field1Type].bytes : 0); + + pField = (TAOS_FIELD*)taosArrayGet(expect.pFields, 1); + if (NULL != pField2Name) { + strcpy(pField->name, pField2Name); + pField->name[strlen(pField2Name)] = '\0'; + } else { + memset(pField, 0, sizeof(TAOS_FIELD)); + } + pField->type = 0; + pField->bytes = 0; + }; + + setCheckDdlFunc([&](const SQuery* pQuery, ParserStage stage) { + ASSERT_EQ(nodeType(pQuery->pRoot), QUERY_NODE_ALTER_TABLE_STMT); + SMAlterStbReq req = {0}; + ASSERT_TRUE(TSDB_CODE_SUCCESS == tDeserializeSMAlterStbReq(pQuery->pCmdMsg->pMsg, pQuery->pCmdMsg->msgLen, &req)); + ASSERT_EQ(std::string(req.name), std::string(expect.name)); + ASSERT_EQ(req.alterType, expect.alterType); + ASSERT_EQ(req.numOfFields, expect.numOfFields); + if (expect.numOfFields > 0) { + TAOS_FIELD* pField = (TAOS_FIELD*)taosArrayGet(req.pFields, 0); + TAOS_FIELD* pExpectField = (TAOS_FIELD*)taosArrayGet(expect.pFields, 0); + ASSERT_EQ(std::string(pField->name), std::string(pExpectField->name)); + ASSERT_EQ(pField->type, pExpectField->type); + ASSERT_EQ(pField->bytes, pExpectField->bytes); + } + if (expect.numOfFields > 1) { + TAOS_FIELD* pField = (TAOS_FIELD*)taosArrayGet(req.pFields, 1); + TAOS_FIELD* pExpectField = (TAOS_FIELD*)taosArrayGet(expect.pFields, 1); + ASSERT_EQ(std::string(pField->name), std::string(pExpectField->name)); + ASSERT_EQ(pField->type, pExpectField->type); + ASSERT_EQ(pField->bytes, pExpectField->bytes); + } + }); + + setAlterStbReqFunc("t1", TSDB_ALTER_TABLE_UPDATE_OPTIONS, 0, nullptr, 0, 0, nullptr, nullptr, 10); + run("ALTER TABLE t1 TTL 10"); + + setAlterStbReqFunc("t1", TSDB_ALTER_TABLE_UPDATE_OPTIONS, 0, nullptr, 0, 0, nullptr, "test"); + run("ALTER TABLE t1 COMMENT 'test'"); + + setAlterStbReqFunc("t1", TSDB_ALTER_TABLE_ADD_COLUMN, 1, "cc1", TSDB_DATA_TYPE_BIGINT); run("ALTER TABLE t1 ADD COLUMN cc1 BIGINT"); + + setAlterStbReqFunc("t1", TSDB_ALTER_TABLE_DROP_COLUMN, 1, "c1"); run("ALTER TABLE t1 DROP COLUMN c1"); + + setAlterStbReqFunc("t1", TSDB_ALTER_TABLE_UPDATE_COLUMN_BYTES, 1, "c1", TSDB_DATA_TYPE_VARCHAR, + 20 + VARSTR_HEADER_SIZE); run("ALTER TABLE t1 MODIFY COLUMN c1 VARCHAR(20)"); + + setAlterStbReqFunc("t1", TSDB_ALTER_TABLE_UPDATE_COLUMN_NAME, 2, "c1", 0, 0, "cc1"); run("ALTER TABLE t1 RENAME COLUMN c1 cc1"); + setAlterStbReqFunc("st1", TSDB_ALTER_TABLE_ADD_TAG, 1, "tag11", TSDB_DATA_TYPE_BIGINT); run("ALTER TABLE st1 ADD TAG tag11 BIGINT"); + + setAlterStbReqFunc("st1", TSDB_ALTER_TABLE_DROP_TAG, 1, "tag1"); run("ALTER TABLE st1 DROP TAG tag1"); + + setAlterStbReqFunc("st1", TSDB_ALTER_TABLE_UPDATE_TAG_BYTES, 1, "tag1", TSDB_DATA_TYPE_VARCHAR, + 20 + VARSTR_HEADER_SIZE); run("ALTER TABLE st1 MODIFY TAG tag1 VARCHAR(20)"); + + setAlterStbReqFunc("st1", TSDB_ALTER_TABLE_UPDATE_TAG_NAME, 2, "tag1", 0, 0, "tag11"); run("ALTER TABLE st1 RENAME TAG tag1 tag11"); // run("ALTER TABLE st1s1 SET TAG tag1=10"); diff --git a/source/libs/parser/test/parInitialCTest.cpp b/source/libs/parser/test/parInitialCTest.cpp index 540560fcd72a3c4fa0e579dfab69fa72937a63c2..cf364aba5cce1cc62eeafa64bb39e724ac555095 100644 --- a/source/libs/parser/test/parInitialCTest.cpp +++ b/source/libs/parser/test/parInitialCTest.cpp @@ -19,7 +19,7 @@ using namespace std; namespace ParserTest { -class ParserInitialCTest : public ParserTestBase {}; +class ParserInitialCTest : public ParserDdlTest {}; // todo compact @@ -97,17 +97,143 @@ TEST_F(ParserInitialCTest, createSnode) { TEST_F(ParserInitialCTest, createStable) { useDb("root", "test"); + SMCreateStbReq expect = {0}; + + auto setCreateStbReqFunc = [&](const char* pTbname, int8_t igExists = 0, + float xFilesFactor = TSDB_DEFAULT_ROLLUP_FILE_FACTOR, + int32_t delay = TSDB_DEFAULT_ROLLUP_DELAY, int32_t ttl = TSDB_DEFAULT_TABLE_TTL, + const char* pComment = nullptr) { + memset(&expect, 0, sizeof(SMCreateStbReq)); + int32_t len = snprintf(expect.name, sizeof(expect.name), "0.test.%s", pTbname); + expect.name[len] = '\0'; + expect.igExists = igExists; + expect.xFilesFactor = xFilesFactor; + expect.delay = delay; + expect.ttl = ttl; + if (nullptr != pComment) { + expect.comment = strdup(pComment); + expect.commentLen = strlen(pComment) + 1; + } + }; + + auto addFieldToCreateStbReqFunc = [&](bool col, const char* pFieldName, uint8_t type, int32_t bytes = 0, + int8_t flags = SCHEMA_SMA_ON) { + SField field = {0}; + strcpy(field.name, pFieldName); + field.type = type; + field.bytes = bytes > 0 ? bytes : tDataTypes[type].bytes; + field.flags = flags; + + if (col) { + if (NULL == expect.pColumns) { + expect.pColumns = taosArrayInit(TARRAY_MIN_SIZE, sizeof(SField)); + } + taosArrayPush(expect.pColumns, &field); + expect.numOfColumns += 1; + } else { + if (NULL == expect.pTags) { + expect.pTags = taosArrayInit(TARRAY_MIN_SIZE, sizeof(SField)); + } + taosArrayPush(expect.pTags, &field); + expect.numOfTags += 1; + } + }; + + setCheckDdlFunc([&](const SQuery* pQuery, ParserStage stage) { + ASSERT_EQ(nodeType(pQuery->pRoot), QUERY_NODE_CREATE_TABLE_STMT); + SMCreateStbReq req = {0}; + ASSERT_TRUE(TSDB_CODE_SUCCESS == tDeserializeSMCreateStbReq(pQuery->pCmdMsg->pMsg, pQuery->pCmdMsg->msgLen, &req)); + + ASSERT_EQ(std::string(req.name), std::string(expect.name)); + ASSERT_EQ(req.igExists, expect.igExists); + ASSERT_EQ(req.xFilesFactor, expect.xFilesFactor); + ASSERT_EQ(req.delay, expect.delay); + ASSERT_EQ(req.ttl, expect.ttl); + ASSERT_EQ(req.numOfColumns, expect.numOfColumns); + ASSERT_EQ(req.numOfTags, expect.numOfTags); + ASSERT_EQ(req.commentLen, expect.commentLen); + ASSERT_EQ(req.ast1Len, expect.ast1Len); + ASSERT_EQ(req.ast2Len, expect.ast2Len); + + if (expect.numOfColumns > 0) { + ASSERT_EQ(taosArrayGetSize(req.pColumns), expect.numOfColumns); + ASSERT_EQ(taosArrayGetSize(req.pColumns), taosArrayGetSize(expect.pColumns)); + for (int32_t i = 0; i < expect.numOfColumns; ++i) { + SField* pField = (SField*)taosArrayGet(req.pColumns, i); + SField* pExpectField = (SField*)taosArrayGet(expect.pColumns, i); + ASSERT_EQ(std::string(pField->name), std::string(pExpectField->name)); + ASSERT_EQ(pField->type, pExpectField->type); + ASSERT_EQ(pField->bytes, pExpectField->bytes); + ASSERT_EQ(pField->flags, pExpectField->flags); + } + } + if (expect.numOfTags > 0) { + ASSERT_EQ(taosArrayGetSize(req.pTags), expect.numOfTags); + ASSERT_EQ(taosArrayGetSize(req.pTags), taosArrayGetSize(expect.pTags)); + for (int32_t i = 0; i < expect.numOfTags; ++i) { + SField* pField = (SField*)taosArrayGet(req.pTags, i); + SField* pExpectField = (SField*)taosArrayGet(expect.pTags, i); + ASSERT_EQ(std::string(pField->name), std::string(pExpectField->name)); + ASSERT_EQ(pField->type, pExpectField->type); + ASSERT_EQ(pField->bytes, pExpectField->bytes); + ASSERT_EQ(pField->flags, pExpectField->flags); + } + } + if (expect.commentLen > 0) { + ASSERT_EQ(std::string(req.comment), std::string(expect.comment)); + } + if (expect.ast1Len > 0) { + ASSERT_EQ(std::string(req.pAst1), std::string(expect.pAst1)); + } + if (expect.ast2Len > 0) { + ASSERT_EQ(std::string(req.pAst2), std::string(expect.pAst2)); + } + }); + + setCreateStbReqFunc("t1"); + addFieldToCreateStbReqFunc(true, "ts", TSDB_DATA_TYPE_TIMESTAMP); + addFieldToCreateStbReqFunc(true, "c1", TSDB_DATA_TYPE_INT); + addFieldToCreateStbReqFunc(false, "id", TSDB_DATA_TYPE_INT); run("create stable t1(ts timestamp, c1 int) TAGS(id int)"); + setCreateStbReqFunc("t1", 1, 0.1, 2, 100, "test create table"); + addFieldToCreateStbReqFunc(true, "ts", TSDB_DATA_TYPE_TIMESTAMP, 0, 0); + addFieldToCreateStbReqFunc(true, "c1", TSDB_DATA_TYPE_INT); + addFieldToCreateStbReqFunc(true, "c2", TSDB_DATA_TYPE_UINT); + addFieldToCreateStbReqFunc(true, "c3", TSDB_DATA_TYPE_BIGINT); + addFieldToCreateStbReqFunc(true, "c4", TSDB_DATA_TYPE_UBIGINT, 0, 0); + addFieldToCreateStbReqFunc(true, "c5", TSDB_DATA_TYPE_FLOAT, 0, 0); + addFieldToCreateStbReqFunc(true, "c6", TSDB_DATA_TYPE_DOUBLE, 0, 0); + addFieldToCreateStbReqFunc(true, "c7", TSDB_DATA_TYPE_BINARY, 20 + VARSTR_HEADER_SIZE, 0); + addFieldToCreateStbReqFunc(true, "c8", TSDB_DATA_TYPE_SMALLINT, 0, 0); + addFieldToCreateStbReqFunc(true, "c9", TSDB_DATA_TYPE_USMALLINT, 0, 0); + addFieldToCreateStbReqFunc(true, "c10", TSDB_DATA_TYPE_TINYINT, 0, 0); + addFieldToCreateStbReqFunc(true, "c11", TSDB_DATA_TYPE_UTINYINT, 0, 0); + addFieldToCreateStbReqFunc(true, "c12", TSDB_DATA_TYPE_BOOL, 0, 0); + addFieldToCreateStbReqFunc(true, "c13", TSDB_DATA_TYPE_NCHAR, 30 * TSDB_NCHAR_SIZE + VARSTR_HEADER_SIZE, 0); + addFieldToCreateStbReqFunc(true, "c14", TSDB_DATA_TYPE_VARCHAR, 50 + VARSTR_HEADER_SIZE, 0); + addFieldToCreateStbReqFunc(false, "a1", TSDB_DATA_TYPE_TIMESTAMP); + addFieldToCreateStbReqFunc(false, "a2", TSDB_DATA_TYPE_INT); + addFieldToCreateStbReqFunc(false, "a3", TSDB_DATA_TYPE_UINT); + addFieldToCreateStbReqFunc(false, "a4", TSDB_DATA_TYPE_BIGINT); + addFieldToCreateStbReqFunc(false, "a5", TSDB_DATA_TYPE_UBIGINT); + addFieldToCreateStbReqFunc(false, "a6", TSDB_DATA_TYPE_FLOAT); + addFieldToCreateStbReqFunc(false, "a7", TSDB_DATA_TYPE_DOUBLE); + addFieldToCreateStbReqFunc(false, "a8", TSDB_DATA_TYPE_BINARY, 20 + VARSTR_HEADER_SIZE); + addFieldToCreateStbReqFunc(false, "a9", TSDB_DATA_TYPE_SMALLINT); + addFieldToCreateStbReqFunc(false, "a10", TSDB_DATA_TYPE_USMALLINT); + addFieldToCreateStbReqFunc(false, "a11", TSDB_DATA_TYPE_TINYINT); + addFieldToCreateStbReqFunc(false, "a12", TSDB_DATA_TYPE_UTINYINT); + addFieldToCreateStbReqFunc(false, "a13", TSDB_DATA_TYPE_BOOL); + addFieldToCreateStbReqFunc(false, "a14", TSDB_DATA_TYPE_NCHAR, 30 * TSDB_NCHAR_SIZE + VARSTR_HEADER_SIZE); + addFieldToCreateStbReqFunc(false, "a15", TSDB_DATA_TYPE_VARCHAR, 50 + VARSTR_HEADER_SIZE); run("create stable if not exists test.t1(" - "ts TIMESTAMP, c1 INT, c2 INT UNSIGNED, c3 BIGINT, c4 BIGINT UNSIGNED, c5 FLOAT, c6 DOUBLE, c7 BINARY(20), c8 " - "SMALLINT, " - "c9 SMALLINT UNSIGNED COMMENT 'test column comment', c10 TINYINT, c11 TINYINT UNSIGNED, c12 BOOL, c13 NCHAR(30), " - "c15 VARCHAR(50)) " - "TAGS (tsa TIMESTAMP, a1 INT, a2 INT UNSIGNED, a3 BIGINT, a4 BIGINT UNSIGNED, a5 FLOAT, a6 DOUBLE, a7 " - "BINARY(20), a8 SMALLINT, " - "a9 SMALLINT UNSIGNED COMMENT 'test column comment', a10 TINYINT, a11 TINYINT UNSIGNED, a12 BOOL, a13 NCHAR(30), " - "a15 VARCHAR(50)) " + "ts TIMESTAMP, c1 INT, c2 INT UNSIGNED, c3 BIGINT, c4 BIGINT UNSIGNED, c5 FLOAT, c6 DOUBLE, c7 BINARY(20), " + "c8 SMALLINT, c9 SMALLINT UNSIGNED COMMENT 'test column comment', c10 TINYINT, c11 TINYINT UNSIGNED, c12 BOOL, " + "c13 NCHAR(30), c14 VARCHAR(50)) " + "TAGS (a1 TIMESTAMP, a2 INT, a3 INT UNSIGNED, a4 BIGINT, a5 BIGINT UNSIGNED, a6 FLOAT, a7 DOUBLE, " + "a8 BINARY(20), a9 SMALLINT, a10 SMALLINT UNSIGNED COMMENT 'test column comment', a11 TINYINT, " + "a12 TINYINT UNSIGNED, a13 BOOL, a14 NCHAR(30), a15 VARCHAR(50)) " "TTL 100 COMMENT 'test create table' SMA(c1, c2, c3) ROLLUP (min) FILE_FACTOR 0.1 DELAY 2"); } diff --git a/source/libs/parser/test/parTestUtil.cpp b/source/libs/parser/test/parTestUtil.cpp index a9ff756a95699e8e8f4fb89c0bf734976fa75bf3..250ac1c52885f10d45a4ef96321d410f115b9255 100644 --- a/source/libs/parser/test/parTestUtil.cpp +++ b/source/libs/parser/test/parTestUtil.cpp @@ -49,6 +49,8 @@ struct TerminateFlag : public exception { class ParserTestBaseImpl { public: + ParserTestBaseImpl(ParserTestBase* pBase) : pBase_(pBase) {} + void useDb(const string& acctId, const string& db) { caseEnv_.acctId_ = acctId; caseEnv_.db_ = db; @@ -156,11 +158,13 @@ class ParserTestBaseImpl { void doParse(SParseContext* pCxt, SQuery** pQuery) { DO_WITH_THROW(parse, pCxt, pQuery); + ASSERT_NE(*pQuery, nullptr); res_.parsedAst_ = toString((*pQuery)->pRoot); } void doTranslate(SParseContext* pCxt, SQuery* pQuery) { DO_WITH_THROW(translate, pCxt, pQuery); + checkQuery(pQuery, PARSER_STAGE_TRANSLATE); res_.translatedAst_ = toString(pQuery->pRoot); } @@ -178,12 +182,15 @@ class ParserTestBaseImpl { return str; } - caseEnv caseEnv_; - stmtEnv stmtEnv_; - stmtRes res_; + void checkQuery(const SQuery* pQuery, ParserStage stage) { pBase_->checkDdl(pQuery, stage); } + + caseEnv caseEnv_; + stmtEnv stmtEnv_; + stmtRes res_; + ParserTestBase* pBase_; }; -ParserTestBase::ParserTestBase() : impl_(new ParserTestBaseImpl()) {} +ParserTestBase::ParserTestBase() : impl_(new ParserTestBaseImpl(this)) {} ParserTestBase::~ParserTestBase() {} @@ -193,4 +200,6 @@ void ParserTestBase::run(const std::string& sql, int32_t expect, ParserStage che return impl_->run(sql, expect, checkStage); } +void ParserTestBase::checkDdl(const SQuery* pQuery, ParserStage stage) { return; } + } // namespace ParserTest diff --git a/source/libs/parser/test/parTestUtil.h b/source/libs/parser/test/parTestUtil.h index 0e8703b2c82fa85772e5bf8650ef1b3be78dd3f3..c7d7ead8dbc8a5d6b7a45cde0552e9e979ea07ec 100644 --- a/source/libs/parser/test/parTestUtil.h +++ b/source/libs/parser/test/parTestUtil.h @@ -18,6 +18,9 @@ #include +#define ALLOW_FORBID_FUNC + +#include "querynodes.h" #include "taoserror.h" namespace ParserTest { @@ -34,10 +37,32 @@ class ParserTestBase : public testing::Test { void useDb(const std::string& acctId, const std::string& db); void run(const std::string& sql, int32_t expect = TSDB_CODE_SUCCESS, ParserStage checkStage = PARSER_STAGE_ALL); + virtual void checkDdl(const SQuery* pQuery, ParserStage stage); + private: std::unique_ptr impl_; }; +class ParserDdlTest : public ParserTestBase { + public: + void setCheckDdlFunc(const std::function& func) { checkDdl_ = func; } + + virtual void checkDdl(const SQuery* pQuery, ParserStage stage) { + ASSERT_NE(pQuery, nullptr); + ASSERT_EQ(pQuery->haveResultSet, false); + ASSERT_NE(pQuery->pRoot, nullptr); + ASSERT_EQ(pQuery->numOfResCols, 0); + ASSERT_EQ(pQuery->pResSchema, nullptr); + ASSERT_EQ(pQuery->precision, 0); + if (nullptr != checkDdl_) { + checkDdl_(pQuery, stage); + } + } + + private: + std::function checkDdl_; +}; + extern bool g_isDump; } // namespace ParserTest