/* * 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 "parTestUtil.h" using namespace std; namespace ParserTest { class ParserInitialCTest : public ParserDdlTest {}; /* * COMPACT DATABASE db_name [START WITH start_time] [END WITH END_time] */ TEST_F(ParserInitialCTest, compact) { SCompactDbReq expect = {0}; auto setCompactDbReq = [&](const char* pDb, int64_t start = INT64_MIN, int64_t end = INT64_MAX) { snprintf(expect.db, sizeof(expect.db), "0.%s", pDb); expect.timeRange.skey = start; expect.timeRange.ekey = end; }; setCheckDdlFunc([&](const SQuery* pQuery, ParserStage stage) { ASSERT_EQ(nodeType(pQuery->pRoot), QUERY_NODE_COMPACT_DATABASE_STMT); ASSERT_EQ(pQuery->pCmdMsg->msgType, TDMT_MND_COMPACT_DB); SCompactDbReq req = {0}; ASSERT_EQ(tDeserializeSCompactDbReq(pQuery->pCmdMsg->pMsg, pQuery->pCmdMsg->msgLen, &req), TSDB_CODE_SUCCESS); ASSERT_EQ(std::string(req.db), std::string(expect.db)); ASSERT_EQ(req.timeRange.skey, expect.timeRange.skey); ASSERT_EQ(req.timeRange.ekey, expect.timeRange.ekey); }); setCompactDbReq("test"); run("COMPACT DATABASE test"); setCompactDbReq("test", 1678168883000, 1678255283000); run("COMPACT DATABASE test START WITH '2023-03-07 14:01:23' END WITH '2023-03-08 14:01:23'"); setCompactDbReq("testus", 1673071283000000000); run("COMPACT DATABASE testus START WITH TIMESTAMP '2023-01-07 14:01:23'"); setCompactDbReq("testus", INT64_MIN, 1675749683000000000); run("COMPACT DATABASE testus END WITH 1675749683000000000"); } /* * CREATE ACCOUNT account_name PASS value [create_account_options] * * create_account_options: * create_account_option ... * * create_account_option: { * PPS value * | TSERIES value * | STORAGE value * | STREAMS value * | QTIME value * | DBS value * | USERS value * | CONNS value * | STATE value * } */ TEST_F(ParserInitialCTest, createAccount) { useDb("root", "test"); run("CREATE ACCOUNT ac_wxy PASS '123456'", TSDB_CODE_PAR_EXPRIE_STATEMENT, PARSER_STAGE_PARSE); } /* * CREATE BNODE ON DNODE dnode_id * the server does not support it temporarily */ /* * CREATE DATABASE [IF NOT EXISTS] db_name [database_options] * * database_options: * database_option ... * * database_option: { * BUFFER value * | CACHEMODEL {'none' | 'last_row' | 'last_value' | 'both'} * | CACHESIZE value * | COMP {0 | 1 | 2} * | DURATION value * | WAL_FSYNC_PERIOD value * | MAXROWS value * | MINROWS value * | KEEP value * | PAGES value * | PAGESIZE value * | PRECISION {'ms' | 'us' | 'ns'} * | REPLICA value * | RETENTIONS ingestion_duration:keep_duration ... * | STRICT {'off' | 'on'} // not support * | WAL_LEVEL value * | VGROUPS value * | SINGLE_STABLE {0 | 1} * | WAL_RETENTION_PERIOD value * | WAL_ROLL_PERIOD value * | WAL_RETENTION_SIZE value * | WAL_SEGMENT_SIZE value * } */ TEST_F(ParserInitialCTest, createDatabase) { useDb("root", "test"); SCreateDbReq expect = {0}; auto clearCreateDbReq = [&]() { tFreeSCreateDbReq(&expect); memset(&expect, 0, sizeof(SCreateDbReq)); }; auto setCreateDbReq = [&](const char* pDbname, int8_t igExists = 0) { int32_t len = snprintf(expect.db, sizeof(expect.db), "0.%s", pDbname); expect.db[len] = '\0'; expect.ignoreExist = igExists; expect.buffer = TSDB_DEFAULT_BUFFER_PER_VNODE; expect.cacheLast = TSDB_DEFAULT_CACHE_MODEL; expect.cacheLastSize = TSDB_DEFAULT_CACHE_SIZE; expect.compression = TSDB_DEFAULT_COMP_LEVEL; expect.daysPerFile = TSDB_DEFAULT_DAYS_PER_FILE; expect.walFsyncPeriod = TSDB_DEFAULT_FSYNC_PERIOD; expect.maxRows = TSDB_DEFAULT_MAXROWS_FBLOCK; expect.minRows = TSDB_DEFAULT_MINROWS_FBLOCK; expect.daysToKeep0 = TSDB_DEFAULT_KEEP; expect.daysToKeep1 = TSDB_DEFAULT_KEEP; expect.daysToKeep2 = TSDB_DEFAULT_KEEP; expect.pages = TSDB_DEFAULT_PAGES_PER_VNODE; expect.pageSize = TSDB_DEFAULT_PAGESIZE_PER_VNODE; expect.precision = TSDB_DEFAULT_PRECISION; expect.replications = TSDB_DEFAULT_DB_REPLICA; expect.strict = TSDB_DEFAULT_DB_STRICT; expect.walLevel = TSDB_DEFAULT_WAL_LEVEL; expect.numOfVgroups = TSDB_DEFAULT_VN_PER_DB; expect.numOfStables = TSDB_DEFAULT_DB_SINGLE_STABLE; expect.schemaless = TSDB_DEFAULT_DB_SCHEMALESS; expect.walRetentionPeriod = TSDB_REP_DEF_DB_WAL_RET_PERIOD; expect.walRetentionSize = TSDB_REP_DEF_DB_WAL_RET_SIZE; expect.walRollPeriod = TSDB_REP_DEF_DB_WAL_ROLL_PERIOD; expect.walSegmentSize = TSDB_DEFAULT_DB_WAL_SEGMENT_SIZE; expect.sstTrigger = TSDB_DEFAULT_SST_TRIGGER; expect.hashPrefix = TSDB_DEFAULT_HASH_PREFIX; expect.hashSuffix = TSDB_DEFAULT_HASH_SUFFIX; expect.tsdbPageSize = TSDB_DEFAULT_TSDB_PAGESIZE; }; auto setDbBuffer = [&](int32_t buffer) { expect.buffer = buffer; }; auto setDbCachelast = [&](int8_t cachelast) { expect.cacheLast = cachelast; }; auto setDbCachelastSize = [&](int8_t cachelastSize) { expect.cacheLastSize = cachelastSize; }; auto setDbCompression = [&](int8_t compressionLevel) { expect.compression = compressionLevel; }; auto setDbDays = [&](int32_t daysPerFile) { expect.daysPerFile = daysPerFile; }; auto setDbFsync = [&](int32_t fsyncPeriod) { expect.walFsyncPeriod = fsyncPeriod; }; auto setDbMaxRows = [&](int32_t maxRowsPerBlock) { expect.maxRows = maxRowsPerBlock; }; auto setDbMinRows = [&](int32_t minRowsPerBlock) { expect.minRows = minRowsPerBlock; }; auto setDbKeep = [&](int32_t keep0, int32_t keep1 = 0, int32_t keep2 = 0) { expect.daysToKeep0 = keep0; expect.daysToKeep1 = 0 == keep1 ? expect.daysToKeep0 : keep1; expect.daysToKeep2 = 0 == keep2 ? expect.daysToKeep1 : keep2; }; auto setDbPages = [&](int32_t pages) { expect.pages = pages; }; auto setDbPageSize = [&](int32_t pagesize) { expect.pageSize = pagesize; }; auto setDbPrecision = [&](int8_t precision) { expect.precision = precision; }; auto setDbReplica = [&](int8_t replica) { expect.replications = replica; }; auto setDbStricta = [&](int8_t strict) { expect.strict = strict; }; auto setDbWalLevel = [&](int8_t walLevel) { expect.walLevel = walLevel; }; auto setDbVgroups = [&](int32_t numOfVgroups) { expect.numOfVgroups = numOfVgroups; }; auto setDbSingleStable = [&](int8_t singleStable) { expect.numOfStables = singleStable; }; auto addDbRetention = [&](int64_t freq, int64_t keep, int8_t freqUnit, int8_t keepUnit) { SRetention retention = {0}; retention.freq = freq; retention.keep = keep; retention.freqUnit = freqUnit; retention.keepUnit = keepUnit; if (NULL == expect.pRetensions) { expect.pRetensions = taosArrayInit(TARRAY_MIN_SIZE, sizeof(SRetention)); } taosArrayPush(expect.pRetensions, &retention); ++expect.numOfRetensions; }; auto setDbSchemaless = [&](int8_t schemaless) { expect.schemaless = schemaless; }; auto setDbWalRetentionPeriod = [&](int32_t walRetentionPeriod) { expect.walRetentionPeriod = walRetentionPeriod; }; auto setDbWalRetentionSize = [&](int32_t walRetentionSize) { expect.walRetentionSize = walRetentionSize; }; auto setDbWalRollPeriod = [&](int32_t walRollPeriod) { expect.walRollPeriod = walRollPeriod; }; auto setDbWalSegmentSize = [&](int32_t walSegmentSize) { expect.walSegmentSize = walSegmentSize; }; auto setDbSstTrigger = [&](int32_t sstTrigger) { expect.sstTrigger = sstTrigger; }; auto setDbHashPrefix = [&](int32_t hashPrefix) { expect.hashPrefix = hashPrefix; }; auto setDbHashSuffix = [&](int32_t hashSuffix) { expect.hashSuffix = hashSuffix; }; auto setDbTsdbPageSize = [&](int32_t tsdbPageSize) { expect.tsdbPageSize = tsdbPageSize; }; setCheckDdlFunc([&](const SQuery* pQuery, ParserStage stage) { ASSERT_EQ(nodeType(pQuery->pRoot), QUERY_NODE_CREATE_DATABASE_STMT); ASSERT_EQ(pQuery->pCmdMsg->msgType, TDMT_MND_CREATE_DB); SCreateDbReq req = {0}; ASSERT_TRUE(TSDB_CODE_SUCCESS == tDeserializeSCreateDbReq(pQuery->pCmdMsg->pMsg, pQuery->pCmdMsg->msgLen, &req)); ASSERT_EQ(std::string(req.db), std::string(expect.db)); ASSERT_EQ(req.numOfVgroups, expect.numOfVgroups); ASSERT_EQ(req.numOfStables, expect.numOfStables); ASSERT_EQ(req.buffer, expect.buffer); ASSERT_EQ(req.pageSize, expect.pageSize); ASSERT_EQ(req.pages, expect.pages); ASSERT_EQ(req.daysPerFile, expect.daysPerFile); ASSERT_EQ(req.daysToKeep0, expect.daysToKeep0); ASSERT_EQ(req.daysToKeep1, expect.daysToKeep1); ASSERT_EQ(req.daysToKeep2, expect.daysToKeep2); ASSERT_EQ(req.minRows, expect.minRows); ASSERT_EQ(req.maxRows, expect.maxRows); ASSERT_EQ(req.walFsyncPeriod, expect.walFsyncPeriod); ASSERT_EQ(req.walLevel, expect.walLevel); ASSERT_EQ(req.precision, expect.precision); ASSERT_EQ(req.compression, expect.compression); ASSERT_EQ(req.replications, expect.replications); ASSERT_EQ(req.strict, expect.strict); ASSERT_EQ(req.cacheLast, expect.cacheLast); ASSERT_EQ(req.cacheLastSize, expect.cacheLastSize); ASSERT_EQ(req.walRetentionPeriod, expect.walRetentionPeriod); ASSERT_EQ(req.walRetentionSize, expect.walRetentionSize); ASSERT_EQ(req.walRollPeriod, expect.walRollPeriod); ASSERT_EQ(req.walSegmentSize, expect.walSegmentSize); ASSERT_EQ(req.sstTrigger, expect.sstTrigger); ASSERT_EQ(req.hashPrefix, expect.hashPrefix); ASSERT_EQ(req.hashSuffix, expect.hashSuffix); ASSERT_EQ(req.tsdbPageSize, expect.tsdbPageSize); ASSERT_EQ(req.ignoreExist, expect.ignoreExist); ASSERT_EQ(req.numOfRetensions, expect.numOfRetensions); if (expect.numOfRetensions > 0) { ASSERT_EQ(taosArrayGetSize(req.pRetensions), expect.numOfRetensions); ASSERT_EQ(taosArrayGetSize(req.pRetensions), taosArrayGetSize(expect.pRetensions)); for (int32_t i = 0; i < expect.numOfRetensions; ++i) { SRetention* pReten = (SRetention*)taosArrayGet(req.pRetensions, i); SRetention* pExpectReten = (SRetention*)taosArrayGet(expect.pRetensions, i); ASSERT_EQ(pReten->freq, pExpectReten->freq); ASSERT_EQ(pReten->keep, pExpectReten->keep); ASSERT_EQ(pReten->freqUnit, pExpectReten->freqUnit); ASSERT_EQ(pReten->keepUnit, pExpectReten->keepUnit); } } tFreeSCreateDbReq(&req); }); setCreateDbReq("wxy_db"); run("CREATE DATABASE wxy_db"); clearCreateDbReq(); setCreateDbReq("wxy_db", 1); setDbBuffer(64); setDbCachelast(2); setDbCachelastSize(20); setDbCompression(1); setDbDays(100 * 1440); setDbFsync(100); setDbMaxRows(1000); setDbMinRows(100); setDbKeep(1440 * 1440); setDbPages(96); setDbPageSize(8); setDbPrecision(TSDB_TIME_PRECISION_NANO); setDbReplica(3); addDbRetention(15 * MILLISECOND_PER_SECOND, 7 * MILLISECOND_PER_DAY, TIME_UNIT_SECOND, TIME_UNIT_DAY); addDbRetention(1 * MILLISECOND_PER_MINUTE, 21 * MILLISECOND_PER_DAY, TIME_UNIT_MINUTE, TIME_UNIT_DAY); addDbRetention(15 * MILLISECOND_PER_MINUTE, 500 * MILLISECOND_PER_DAY, TIME_UNIT_MINUTE, TIME_UNIT_DAY); // setDbStricta(1); setDbWalLevel(2); setDbVgroups(100); setDbSingleStable(1); setDbSchemaless(1); setDbWalRetentionPeriod(-1); setDbWalRetentionSize(-1); setDbWalRollPeriod(10); setDbWalSegmentSize(20); setDbSstTrigger(16); setDbHashPrefix(3); setDbHashSuffix(4); setDbTsdbPageSize(32); run("CREATE DATABASE IF NOT EXISTS wxy_db " "BUFFER 64 " "CACHEMODEL 'last_value' " "CACHESIZE 20 " "COMP 1 " "DURATION 100 " "WAL_FSYNC_PERIOD 100 " "MAXROWS 1000 " "MINROWS 100 " "KEEP 1440 " "PAGES 96 " "PAGESIZE 8 " "PRECISION 'ns' " "REPLICA 3 " "RETENTIONS 15s:7d,1m:21d,15m:500d " // "STRICT 'on' " "WAL_LEVEL 2 " "VGROUPS 100 " "SINGLE_STABLE 1 " "SCHEMALESS 1 " "WAL_RETENTION_PERIOD -1 " "WAL_RETENTION_SIZE -1 " "WAL_ROLL_PERIOD 10 " "WAL_SEGMENT_SIZE 20 " "STT_TRIGGER 16 " "TABLE_PREFIX 3 " "TABLE_SUFFIX 4 " "TSDB_PAGESIZE 32"); clearCreateDbReq(); setCreateDbReq("wxy_db", 1); setDbDays(100); setDbKeep(1440, 300 * 60, 400 * 1440); run("CREATE DATABASE IF NOT EXISTS wxy_db " "DURATION 100m " "KEEP 1440m,300h,400d "); clearCreateDbReq(); setCreateDbReq("wxy_db", 1); setDbReplica(3); setDbWalRetentionPeriod(TSDB_REPS_DEF_DB_WAL_RET_PERIOD); setDbWalRetentionSize(TSDB_REPS_DEF_DB_WAL_RET_SIZE); setDbWalRollPeriod(TSDB_REPS_DEF_DB_WAL_ROLL_PERIOD); run("CREATE DATABASE IF NOT EXISTS wxy_db REPLICA 3"); clearCreateDbReq(); } TEST_F(ParserInitialCTest, createDatabaseSemanticCheck) { useDb("root", "test"); run("create database db2 retentions 0s:1d", TSDB_CODE_PAR_INVALID_DB_OPTION); run("create database db2 retentions 10s:0d", TSDB_CODE_PAR_INVALID_DB_OPTION); run("create database db2 retentions 1w:1d", TSDB_CODE_PAR_INVALID_DB_OPTION); run("create database db2 retentions 1w:1n", TSDB_CODE_PAR_INVALID_DB_OPTION); run("create database db2 retentions 15s:7d,15m:21d,10m:500d", TSDB_CODE_PAR_INVALID_DB_OPTION); run("create database db2 retentions 15s:7d,5m:21d,10m:10d", TSDB_CODE_PAR_INVALID_DB_OPTION); } /* * CREATE DNODE {dnode_endpoint | dnode_host_name PORT port_val} */ TEST_F(ParserInitialCTest, createDnode) { useDb("root", "test"); SCreateDnodeReq expect = {0}; auto clearCreateDnodeReq = [&]() { memset(&expect, 0, sizeof(SCreateDnodeReq)); }; auto setCreateDnodeReq = [&](const char* pFqdn, int32_t port = tsServerPort) { strcpy(expect.fqdn, pFqdn); expect.port = port; }; setCheckDdlFunc([&](const SQuery* pQuery, ParserStage stage) { ASSERT_EQ(nodeType(pQuery->pRoot), QUERY_NODE_CREATE_DNODE_STMT); SCreateDnodeReq req = {0}; ASSERT_TRUE(TSDB_CODE_SUCCESS == tDeserializeSCreateDnodeReq(pQuery->pCmdMsg->pMsg, pQuery->pCmdMsg->msgLen, &req)); ASSERT_EQ(std::string(req.fqdn), std::string(expect.fqdn)); ASSERT_EQ(req.port, expect.port); }); setCreateDnodeReq("abc1", 7030); run("CREATE DNODE 'abc1' PORT 7030"); clearCreateDnodeReq(); setCreateDnodeReq("1.1.1.1", 8030); run("CREATE DNODE 1.1.1.1 PORT 8030"); clearCreateDnodeReq(); setCreateDnodeReq("host1", 9030); run("CREATE DNODE host1 PORT 9030"); clearCreateDnodeReq(); setCreateDnodeReq("abc2", 7040); run("CREATE DNODE 'abc2:7040'"); clearCreateDnodeReq(); setCreateDnodeReq("1.1.1.2"); run("CREATE DNODE 1.1.1.2"); clearCreateDnodeReq(); setCreateDnodeReq("host2"); run("CREATE DNODE host2"); clearCreateDnodeReq(); } /* * CREATE [OR REPLACE] [AGGREGATE] FUNCTION [IF NOT EXISTS] func_name * AS library_path OUTPUTTYPE type_name [BUFSIZE value] [LANGUAGE value] */ TEST_F(ParserInitialCTest, createFunction) { useDb("root", "test"); SCreateFuncReq expect = {0}; auto setCreateFuncReq = [&](const char* pUdfName, int8_t outputType, int32_t outputBytes = 0, int8_t funcType = TSDB_FUNC_TYPE_SCALAR, int8_t igExists = 0, int32_t bufSize = 0, int8_t language = TSDB_FUNC_SCRIPT_BIN_LIB, int8_t orReplace = 0) { memset(&expect, 0, sizeof(SCreateFuncReq)); strcpy(expect.name, pUdfName); expect.orReplace = orReplace; expect.igExists = igExists; expect.funcType = funcType; expect.scriptType = language; expect.outputType = outputType; expect.outputLen = outputBytes > 0 ? outputBytes : tDataTypes[outputType].bytes; expect.bufSize = bufSize; }; setCheckDdlFunc([&](const SQuery* pQuery, ParserStage stage) { ASSERT_EQ(nodeType(pQuery->pRoot), QUERY_NODE_CREATE_FUNCTION_STMT); SCreateFuncReq req = {0}; ASSERT_TRUE(TSDB_CODE_SUCCESS == tDeserializeSCreateFuncReq(pQuery->pCmdMsg->pMsg, pQuery->pCmdMsg->msgLen, &req)); ASSERT_EQ(std::string(req.name), std::string(expect.name)); ASSERT_EQ(req.orReplace, expect.orReplace); ASSERT_EQ(req.igExists, expect.igExists); ASSERT_EQ(req.funcType, expect.funcType); ASSERT_EQ(req.scriptType, expect.scriptType); ASSERT_EQ(req.outputType, expect.outputType); ASSERT_EQ(req.outputLen, expect.outputLen); ASSERT_EQ(req.bufSize, expect.bufSize); tFreeSCreateFuncReq(&req); }); struct udfFile { udfFile(const std::string& filename) : path_(filename) { std::ofstream file(filename, std::ios::binary); file << 123 << "abc" << '\n'; file.close(); } ~udfFile() { remove(path_.c_str()); } std::string path_; } udffile("udf"); setCreateFuncReq("udf1", TSDB_DATA_TYPE_INT); run("CREATE FUNCTION udf1 AS 'udf' OUTPUTTYPE INT"); setCreateFuncReq("udf2", TSDB_DATA_TYPE_DOUBLE, 0, TSDB_FUNC_TYPE_AGGREGATE, 1, 8, TSDB_FUNC_SCRIPT_PYTHON, 1); run("CREATE OR REPLACE AGGREGATE FUNCTION IF NOT EXISTS udf2 AS 'udf' OUTPUTTYPE DOUBLE BUFSIZE 8 LANGUAGE 'python'"); } /* * CREATE MNODE ON DNODE dnode_id */ TEST_F(ParserInitialCTest, createMnode) { useDb("root", "test"); SMCreateMnodeReq expect = {0}; auto setCreateMnodeReq = [&](int32_t dnodeId) { expect.dnodeId = dnodeId; }; setCheckDdlFunc([&](const SQuery* pQuery, ParserStage stage) { ASSERT_EQ(nodeType(pQuery->pRoot), QUERY_NODE_CREATE_MNODE_STMT); SMCreateMnodeReq req = {0}; ASSERT_TRUE(TSDB_CODE_SUCCESS == tDeserializeSCreateDropMQSNodeReq(pQuery->pCmdMsg->pMsg, pQuery->pCmdMsg->msgLen, &req)); ASSERT_EQ(req.dnodeId, expect.dnodeId); }); setCreateMnodeReq(1); run("CREATE MNODE ON DNODE 1"); } /* * CREATE QNODE ON DNODE dnode_id */ TEST_F(ParserInitialCTest, createQnode) { useDb("root", "test"); SMCreateQnodeReq expect = {0}; auto setCreateQnodeReq = [&](int32_t dnodeId) { expect.dnodeId = dnodeId; }; setCheckDdlFunc([&](const SQuery* pQuery, ParserStage stage) { ASSERT_EQ(nodeType(pQuery->pRoot), QUERY_NODE_CREATE_QNODE_STMT); SMCreateQnodeReq req = {0}; ASSERT_TRUE(TSDB_CODE_SUCCESS == tDeserializeSCreateDropMQSNodeReq(pQuery->pCmdMsg->pMsg, pQuery->pCmdMsg->msgLen, &req)); ASSERT_EQ(req.dnodeId, expect.dnodeId); }); setCreateQnodeReq(1); run("CREATE QNODE ON DNODE 1"); } /* * CREATE SMA INDEX index_name ON tb_name index_option * * index_option: * FUNCTION(functions) INTERVAL(interval_val [, interval_offset]) [SLIDING(sliding_val)] * [WATERMARK(watermark_val)] [MAX_DELAY(max_delay_val)] * * functions: * function [, function] ... */ TEST_F(ParserInitialCTest, createSmaIndex) { useDb("root", "test"); SMCreateSmaReq expect = {0}; auto setCreateSmacReq = [&](const char* pIndexName, const char* pStbName, int64_t interval, int8_t intervalUnit, int64_t offset = 0, int64_t sliding = -1, int8_t slidingUnit = -1, int8_t igExists = 0) { memset(&expect, 0, sizeof(SMCreateSmaReq)); strcpy(expect.name, pIndexName); strcpy(expect.stb, pStbName); expect.igExists = igExists; expect.intervalUnit = intervalUnit; expect.slidingUnit = slidingUnit < 0 ? intervalUnit : slidingUnit; expect.timezone = 0; expect.dstVgId = 1; expect.interval = interval; expect.offset = offset; expect.sliding = sliding < 0 ? interval : sliding; expect.maxDelay = -1; expect.watermark = TSDB_DEFAULT_ROLLUP_WATERMARK; expect.deleteMark = TSDB_DEFAULT_ROLLUP_DELETE_MARK; }; auto setOptionsForCreateSmacReq = [&](int64_t maxDelay, int64_t watermark, int64_t deleteMark) { expect.maxDelay = maxDelay; expect.watermark = watermark; expect.deleteMark = deleteMark; }; setCheckDdlFunc([&](const SQuery* pQuery, ParserStage stage) { ASSERT_EQ(nodeType(pQuery->pRoot), QUERY_NODE_CREATE_INDEX_STMT); SMCreateSmaReq req = {0}; ASSERT_TRUE(TSDB_CODE_SUCCESS == tDeserializeSMCreateSmaReq(pQuery->pCmdMsg->pMsg, pQuery->pCmdMsg->msgLen, &req)); ASSERT_EQ(std::string(req.name), std::string(expect.name)); ASSERT_EQ(std::string(req.stb), std::string(expect.stb)); ASSERT_EQ(req.igExists, expect.igExists); ASSERT_EQ(req.intervalUnit, expect.intervalUnit); ASSERT_EQ(req.slidingUnit, expect.slidingUnit); ASSERT_EQ(req.timezone, expect.timezone); ASSERT_EQ(req.dstVgId, expect.dstVgId); ASSERT_EQ(req.interval, expect.interval); ASSERT_EQ(req.offset, expect.offset); ASSERT_EQ(req.sliding, expect.sliding); ASSERT_EQ(req.maxDelay, expect.maxDelay); ASSERT_EQ(req.watermark, expect.watermark); ASSERT_EQ(req.deleteMark, expect.deleteMark); ASSERT_GT(req.exprLen, 0); ASSERT_EQ(req.tagsFilterLen, 0); ASSERT_GT(req.sqlLen, 0); ASSERT_GT(req.astLen, 0); ASSERT_NE(req.expr, nullptr); ASSERT_EQ(req.tagsFilter, nullptr); ASSERT_NE(req.sql, nullptr); ASSERT_NE(req.ast, nullptr); tFreeSMCreateSmaReq(&req); }); setCreateSmacReq("0.test.index1", "0.test.t1", 10 * MILLISECOND_PER_SECOND, 's'); run("CREATE SMA INDEX index1 ON t1 FUNCTION(MAX(c1), MIN(c3 + 10), SUM(c4)) INTERVAL(10s)"); setCreateSmacReq("0.test.index2", "0.test.st1", 5 * MILLISECOND_PER_SECOND, 's'); setOptionsForCreateSmacReq(10 * MILLISECOND_PER_SECOND, 20 * MILLISECOND_PER_SECOND, 1000 * MILLISECOND_PER_SECOND); run("CREATE SMA INDEX index2 ON st1 FUNCTION(MAX(c1), MIN(tag1)) INTERVAL(5s) WATERMARK 20s MAX_DELAY 10s " "DELETE_MARK 1000s"); } /* * CREATE SNODE ON DNODE dnode_id */ TEST_F(ParserInitialCTest, createSnode) { useDb("root", "test"); SMCreateSnodeReq expect = {0}; auto setCreateSnodeReq = [&](int32_t dnodeId) { expect.dnodeId = dnodeId; }; setCheckDdlFunc([&](const SQuery* pQuery, ParserStage stage) { ASSERT_EQ(nodeType(pQuery->pRoot), QUERY_NODE_CREATE_SNODE_STMT); SMCreateSnodeReq req = {0}; ASSERT_TRUE(TSDB_CODE_SUCCESS == tDeserializeSCreateDropMQSNodeReq(pQuery->pCmdMsg->pMsg, pQuery->pCmdMsg->msgLen, &req)); ASSERT_EQ(req.dnodeId, expect.dnodeId); }); setCreateSnodeReq(1); run("CREATE SNODE ON DNODE 1"); } /* * CREATE STABLE [IF NOT EXISTS] stb_name (create_definition [, create_definitionn] ...) * TAGS (create_definition [, create_definition] ...) [table_options] * * create_definition: * col_name column_definition * * column_definition: * type_name [COMMENT 'string_value'] */ TEST_F(ParserInitialCTest, createStable) { useDb("root", "test"); SMCreateStbReq expect = {0}; auto clearCreateStbReq = [&]() { tFreeSMCreateStbReq(&expect); memset(&expect, 0, sizeof(SMCreateStbReq)); }; auto setCreateStbReq = [&](const char* pDbName, const char* pTbName, int8_t igExists = 0, int64_t delay1 = -1, int64_t delay2 = -1, int64_t watermark1 = TSDB_DEFAULT_ROLLUP_WATERMARK, int64_t watermark2 = TSDB_DEFAULT_ROLLUP_WATERMARK, int64_t deleteMark1 = TSDB_DEFAULT_ROLLUP_DELETE_MARK, int64_t deleteMark2 = TSDB_DEFAULT_ROLLUP_DELETE_MARK, int32_t ttl = TSDB_DEFAULT_TABLE_TTL, const char* pComment = nullptr) { int32_t len = snprintf(expect.name, sizeof(expect.name), "0.%s.%s", pDbName, pTbName); expect.name[len] = '\0'; expect.igExists = igExists; expect.delay1 = delay1; expect.delay2 = delay2; expect.watermark1 = watermark1; expect.watermark2 = watermark2; expect.deleteMark1 = deleteMark1; expect.deleteMark2 = deleteMark2; // expect.ttl = ttl; if (nullptr != pComment) { expect.pComment = taosStrdup(pComment); expect.commentLen = strlen(pComment); } }; auto addFieldToCreateStbReq = [&](bool col, const char* pFieldName, uint8_t type, int32_t bytes = 0, int8_t flags = COL_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.delay1, expect.delay1); ASSERT_EQ(req.delay2, expect.delay2); ASSERT_EQ(req.watermark1, expect.watermark1); ASSERT_EQ(req.watermark2, expect.watermark2); 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.pComment), std::string(expect.pComment)); } 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)); } tFreeSMCreateStbReq(&req); }); setCreateStbReq("test", "t1"); addFieldToCreateStbReq(true, "ts", TSDB_DATA_TYPE_TIMESTAMP); addFieldToCreateStbReq(true, "c1", TSDB_DATA_TYPE_INT); addFieldToCreateStbReq(false, "id", TSDB_DATA_TYPE_INT); run("CREATE STABLE t1(ts TIMESTAMP, c1 INT) TAGS(id INT)"); clearCreateStbReq(); setCreateStbReq("rollup_db", "t1", 1, 100 * MILLISECOND_PER_SECOND, 10 * MILLISECOND_PER_MINUTE, 10, 1 * MILLISECOND_PER_MINUTE, 1000 * MILLISECOND_PER_SECOND, 200 * MILLISECOND_PER_MINUTE, 100, "test create table"); addFieldToCreateStbReq(true, "ts", TSDB_DATA_TYPE_TIMESTAMP, 0, 0); addFieldToCreateStbReq(true, "c1", TSDB_DATA_TYPE_INT); addFieldToCreateStbReq(true, "c2", TSDB_DATA_TYPE_UINT); addFieldToCreateStbReq(true, "c3", TSDB_DATA_TYPE_BIGINT); addFieldToCreateStbReq(true, "c4", TSDB_DATA_TYPE_UBIGINT, 0, 0); addFieldToCreateStbReq(true, "c5", TSDB_DATA_TYPE_FLOAT, 0, 0); addFieldToCreateStbReq(true, "c6", TSDB_DATA_TYPE_DOUBLE, 0, 0); addFieldToCreateStbReq(true, "c7", TSDB_DATA_TYPE_BINARY, 20 + VARSTR_HEADER_SIZE, 0); addFieldToCreateStbReq(true, "c8", TSDB_DATA_TYPE_SMALLINT, 0, 0); addFieldToCreateStbReq(true, "c9", TSDB_DATA_TYPE_USMALLINT, 0, 0); addFieldToCreateStbReq(true, "c10", TSDB_DATA_TYPE_TINYINT, 0, 0); addFieldToCreateStbReq(true, "c11", TSDB_DATA_TYPE_UTINYINT, 0, 0); addFieldToCreateStbReq(true, "c12", TSDB_DATA_TYPE_BOOL, 0, 0); addFieldToCreateStbReq(true, "c13", TSDB_DATA_TYPE_NCHAR, 30 * TSDB_NCHAR_SIZE + VARSTR_HEADER_SIZE, 0); addFieldToCreateStbReq(true, "c14", TSDB_DATA_TYPE_VARCHAR, 50 + VARSTR_HEADER_SIZE, 0); addFieldToCreateStbReq(false, "a1", TSDB_DATA_TYPE_TIMESTAMP); addFieldToCreateStbReq(false, "a2", TSDB_DATA_TYPE_INT); addFieldToCreateStbReq(false, "a3", TSDB_DATA_TYPE_UINT); addFieldToCreateStbReq(false, "a4", TSDB_DATA_TYPE_BIGINT); addFieldToCreateStbReq(false, "a5", TSDB_DATA_TYPE_UBIGINT); addFieldToCreateStbReq(false, "a6", TSDB_DATA_TYPE_FLOAT); addFieldToCreateStbReq(false, "a7", TSDB_DATA_TYPE_DOUBLE); addFieldToCreateStbReq(false, "a8", TSDB_DATA_TYPE_BINARY, 20 + VARSTR_HEADER_SIZE); addFieldToCreateStbReq(false, "a9", TSDB_DATA_TYPE_SMALLINT); addFieldToCreateStbReq(false, "a10", TSDB_DATA_TYPE_USMALLINT); addFieldToCreateStbReq(false, "a11", TSDB_DATA_TYPE_TINYINT); addFieldToCreateStbReq(false, "a12", TSDB_DATA_TYPE_UTINYINT); addFieldToCreateStbReq(false, "a13", TSDB_DATA_TYPE_BOOL); addFieldToCreateStbReq(false, "a14", TSDB_DATA_TYPE_NCHAR, 30 * TSDB_NCHAR_SIZE + VARSTR_HEADER_SIZE); addFieldToCreateStbReq(false, "a15", TSDB_DATA_TYPE_VARCHAR, 50 + VARSTR_HEADER_SIZE); run("CREATE STABLE IF NOT EXISTS rollup_db.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, 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, 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) MAX_DELAY 100s,10m WATERMARK 10a,1m " "DELETE_MARK 1000s,200m"); clearCreateStbReq(); } TEST_F(ParserInitialCTest, createStableSemanticCheck) { useDb("root", "test"); run("CREATE STABLE rollup_db.stb2 (ts TIMESTAMP, c1 INT) TAGS (tag1 INT) ROLLUP(CEIL)", TSDB_CODE_PAR_INVALID_TABLE_OPTION); run("CREATE STABLE rollup_db.stb2 (ts TIMESTAMP, c1 INT) TAGS (tag1 INT) ROLLUP(MAX) MAX_DELAY 0s WATERMARK 1m", TSDB_CODE_PAR_INVALID_TABLE_OPTION); run("CREATE STABLE rollup_db.stb2 (ts TIMESTAMP, c1 INT) TAGS (tag1 INT) ROLLUP(MAX) MAX_DELAY 10s WATERMARK 18m", TSDB_CODE_PAR_INVALID_TABLE_OPTION); } /* * CREATE STREAM [IF NOT EXISTS] stream_name [stream_options] * INTO stb_name [TAGS (create_definition [, create_definition] ...)] [SUBTABLE (expr)] AS subquery * * stream_options: * stream_option ... * * stream_option: { * TRIGGER [AT_ONCE | WINDOW_CLOSE | MAX_DELAY time] * | WATERMARK time * | IGNORE EXPIRED value * | FILL_HISTORY value * } */ TEST_F(ParserInitialCTest, createStream) { useDb("root", "test"); SCMCreateStreamReq expect = {0}; auto clearCreateStreamReq = [&]() { tFreeSCMCreateStreamReq(&expect); memset(&expect, 0, sizeof(SCMCreateStreamReq)); }; auto setCreateStreamReq = [&](const char* pStream, const char* pSrcDb, const char* pSql, const char* pDstStb, int8_t igExists = 0) { snprintf(expect.name, sizeof(expect.name), "0.%s", pStream); snprintf(expect.sourceDB, sizeof(expect.sourceDB), "0.%s", pSrcDb); snprintf(expect.targetStbFullName, sizeof(expect.targetStbFullName), "0.test.%s", pDstStb); expect.igExists = igExists; expect.sql = taosStrdup(pSql); }; auto setStreamOptions = [&](int8_t createStb = STREAM_CREATE_STABLE_TRUE, int8_t triggerType = STREAM_TRIGGER_WINDOW_CLOSE, int64_t maxDelay = 0, int64_t watermark = 0, int8_t igExpired = STREAM_DEFAULT_IGNORE_EXPIRED, int8_t fillHistory = STREAM_DEFAULT_FILL_HISTORY, int8_t igUpdate = STREAM_DEFAULT_IGNORE_UPDATE) { expect.createStb = createStb; expect.triggerType = triggerType; expect.maxDelay = maxDelay; expect.watermark = watermark; expect.fillHistory = fillHistory; expect.igExpired = igExpired; expect.igUpdate = igUpdate; }; auto addTag = [&](const char* pFieldName, uint8_t type, int32_t bytes = 0) { SField field = {0}; strcpy(field.name, pFieldName); field.type = type; field.bytes = bytes > 0 ? bytes : tDataTypes[type].bytes; field.flags |= COL_SMA_ON; 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_STREAM_STMT); SCMCreateStreamReq req = {0}; ASSERT_TRUE(TSDB_CODE_SUCCESS == tDeserializeSCMCreateStreamReq(pQuery->pCmdMsg->pMsg, pQuery->pCmdMsg->msgLen, &req)); ASSERT_EQ(std::string(req.name), std::string(expect.name)); ASSERT_EQ(std::string(req.sourceDB), std::string(expect.sourceDB)); ASSERT_EQ(std::string(req.targetStbFullName), std::string(expect.targetStbFullName)); ASSERT_EQ(req.igExists, expect.igExists); ASSERT_EQ(std::string(req.sql), std::string(expect.sql)); ASSERT_EQ(req.triggerType, expect.triggerType); ASSERT_EQ(req.maxDelay, expect.maxDelay); ASSERT_EQ(req.watermark, expect.watermark); ASSERT_EQ(req.fillHistory, expect.fillHistory); ASSERT_EQ(req.igExpired, expect.igExpired); ASSERT_EQ(req.numOfTags, expect.numOfTags); 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); } } ASSERT_EQ(req.checkpointFreq, expect.checkpointFreq); ASSERT_EQ(req.createStb, expect.createStb); ASSERT_EQ(req.igUpdate, expect.igUpdate); tFreeSCMCreateStreamReq(&req); }); setCreateStreamReq("s1", "test", "create stream s1 into st3 as select count(*) from t1 interval(10s)", "st3"); setStreamOptions(); run("CREATE STREAM s1 INTO st3 AS SELECT COUNT(*) FROM t1 INTERVAL(10S)"); clearCreateStreamReq(); setCreateStreamReq( "s1", "test", "create stream if not exists s1 trigger max_delay 20s watermark 10s ignore expired 0 fill_history 1 ignore " "update 1 into st3 as select count(*) from t1 interval(10s)", "st3", 1); setStreamOptions(STREAM_CREATE_STABLE_TRUE, STREAM_TRIGGER_MAX_DELAY, 20 * MILLISECOND_PER_SECOND, 10 * MILLISECOND_PER_SECOND, 0, 1, 1); run("CREATE STREAM IF NOT EXISTS s1 TRIGGER MAX_DELAY 20s WATERMARK 10s IGNORE EXPIRED 0 FILL_HISTORY 1 IGNORE " "UPDATE 1 INTO st3 AS SELECT COUNT(*) FROM t1 INTERVAL(10S)"); clearCreateStreamReq(); setCreateStreamReq("s1", "test", "create stream s1 into st3 tags(tname varchar(10), id int) subtable(concat('new-', tname)) as " "select _wstart wstart, count(*) cnt from st1 partition by tbname tname, tag1 id interval(10s)", "st3"); addTag("tname", TSDB_DATA_TYPE_VARCHAR, 10 + VARSTR_HEADER_SIZE); addTag("id", TSDB_DATA_TYPE_INT); setStreamOptions(); run("CREATE STREAM s1 INTO st3 TAGS(tname VARCHAR(10), id INT) SUBTABLE(CONCAT('new-', tname)) " "AS SELECT _WSTART wstart, COUNT(*) cnt FROM st1 PARTITION BY TBNAME tname, tag1 id INTERVAL(10S)"); clearCreateStreamReq(); // st1 already exists setCreateStreamReq( "s1", "test", "create stream s1 into st1 tags(tag2) as select max(c1), c2 from t1 partition by tbname tag2 interval(10s)", "st1"); setStreamOptions(STREAM_CREATE_STABLE_FALSE); run("CREATE STREAM s1 INTO st1 TAGS(tag2) AS SELECT MAX(c1), c2 FROM t1 PARTITION BY TBNAME tag2 INTERVAL(10S)"); clearCreateStreamReq(); } TEST_F(ParserInitialCTest, createStreamSemanticCheck) { useDb("root", "test"); run("CREATE STREAM s1 INTO st1 AS SELECT PERCENTILE(c1, 30) FROM t1 INTERVAL(10S)", TSDB_CODE_PAR_STREAM_NOT_ALLOWED_FUNC); run("CREATE STREAM s2 INTO st1 AS SELECT ts, to_json('{c1:1}') FROM st1 PARTITION BY TBNAME", TSDB_CODE_PAR_INVALID_STREAM_QUERY); run("CREATE STREAM s3 INTO st3 TAGS(tname VARCHAR(10), id INT) SUBTABLE(CONCAT('new-', tbname)) " "AS SELECT _WSTART wstart, COUNT(*) cnt FROM st1 INTERVAL(10S)", TSDB_CODE_PAR_INVALID_STREAM_QUERY); } /* * CREATE TABLE [IF NOT EXISTS] [db_name.]tb_name (create_definition [, create_definitionn] ...) [table_options] * * CREATE TABLE create_subtable_clause * * CREATE TABLE [IF NOT EXISTS] [db_name.]tb_name (create_definition [, create_definitionn] ...) * [TAGS (create_definition [, create_definitionn] ...)] * [table_options] * * create_subtable_clause: { * create_subtable_clause [create_subtable_clause] ... * | [IF NOT EXISTS] [db_name.]tb_name USING [db_name.]stb_name [(tag_name [, tag_name] ...)] * TAGS (tag_value [, tag_value] ...) * } * * create_definition: * col_name column_definition * * column_definition: * type_name [comment 'string_value'] * * table_options: * table_option ... * * table_option: { * COMMENT 'string_value' * | WATERMARK duration[,duration] * | MAX_DELAY duration[,duration] * | ROLLUP(func_name [, func_name] ...) * | SMA(col_name [, col_name] ...) * | TTL value * } */ TEST_F(ParserInitialCTest, createTable) { useDb("root", "test"); SVCreateTbBatchReq expect = {0}; auto addCreateTbReq = [&](const char* pName, bool ignoreExists = false, int32_t ttl = TSDB_DEFAULT_TABLE_TTL, const char* pComment = nullptr) { SVCreateTbReq req = {0}; req.name = taosStrdup(pName); if (ignoreExists) { req.flags |= TD_CREATE_IF_NOT_EXISTS; } req.ttl = ttl; if (nullptr != pComment) { req.comment = taosStrdup(pComment); req.commentLen = strlen(pComment); } ++expect.nReqs; if (nullptr == expect.pArray) { expect.pArray = taosArrayInit(TARRAY_MIN_SIZE, sizeof(SVCreateTbReq)); } taosArrayPush(expect.pArray, &req); }; setCheckDdlFunc([&](const SQuery* pQuery, ParserStage stage) { return; // todo ASSERT_EQ(nodeType(pQuery->pRoot), QUERY_NODE_VNODE_MODIFY_STMT); SVnodeModifyOpStmt* pStmt = (SVnodeModifyOpStmt*)pQuery->pRoot; ASSERT_EQ(pStmt->sqlNodeType, QUERY_NODE_CREATE_TABLE_STMT); ASSERT_NE(pStmt->pDataBlocks, nullptr); int32_t numOfBlocks = taosArrayGetSize(pStmt->pDataBlocks); for (int32_t i = 0; i < numOfBlocks; ++i) { SVgDataBlocks* pVgData = (SVgDataBlocks*)taosArrayGetP(pStmt->pDataBlocks, i); void* pBuf = POINTER_SHIFT(pVgData->pData, sizeof(SMsgHead)); SVCreateTbBatchReq req = {0}; SDecoder coder = {0}; tDecoderInit(&coder, (uint8_t*)pBuf, pVgData->size); ASSERT_EQ(tDecodeSVCreateTbBatchReq(&coder, &req), TSDB_CODE_SUCCESS); ASSERT_EQ(req.nReqs, expect.nReqs); for (int32_t j = 0; j < req.nReqs; ++j) { SVCreateTbReq* pReq = req.pReqs + j; SVCreateTbReq* pExpect = (SVCreateTbReq*)taosArrayGet(expect.pArray, j); ASSERT_EQ(pReq->flags, pExpect->flags); ASSERT_EQ(std::string(pReq->name), std::string(pExpect->name)); ASSERT_EQ(pReq->uid, pExpect->uid); ASSERT_EQ(pReq->ctime, pExpect->ctime); ASSERT_EQ(pReq->ttl, pExpect->ttl); ASSERT_EQ(pReq->commentLen, pExpect->commentLen); ASSERT_EQ(std::string(pReq->comment), std::string(pExpect->comment)); ASSERT_EQ(pReq->type, pExpect->type); if (TD_NORMAL_TABLE == pExpect->type) { ASSERT_EQ(pReq->ntb.schemaRow.version, pExpect->ntb.schemaRow.version); ASSERT_EQ(pReq->ntb.schemaRow.nCols, pExpect->ntb.schemaRow.nCols); } else if (TD_CHILD_TABLE == pExpect->type) { ASSERT_EQ(std::string(pReq->ctb.stbName), std::string(pExpect->ctb.stbName)); ASSERT_EQ(pReq->ctb.tagNum, pExpect->ctb.tagNum); ASSERT_EQ(pReq->ctb.suid, pExpect->ctb.suid); } } tDecoderClear(&coder); } }); run("CREATE TABLE t1(ts TIMESTAMP, c1 INT)"); run("CREATE TABLE 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, c10 TINYINT, c11 TINYINT UNSIGNED, c12 BOOL, " "c13 NCHAR(30), c15 VARCHAR(50)) " "TTL 100 COMMENT 'test create table' SMA(c1, c2, c3)"); run("CREATE TABLE IF NOT EXISTS rollup_db.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, 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, 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)"); run("CREATE TABLE IF NOT EXISTS t1 USING st1 TAGS(1, 'wxy', NOW)"); run("CREATE TABLE " "IF NOT EXISTS test.t1 USING test.st1 (tag1, tag2) TAGS(1, 'abc') " "IF NOT EXISTS test.t2 USING test.st1 (tag1, tag2) TAGS(2, 'abc') " "IF NOT EXISTS test.t3 USING test.st1 (tag1, tag2) TAGS(3, 'abc') "); run("CREATE TABLE IF NOT EXISTS t1 USING st1 TAGS(1, 'wxy', NOW + 1S)"); } TEST_F(ParserInitialCTest, createTableSemanticCheck) { useDb("root", "test"); string sql = "CREATE TABLE st1(ts TIMESTAMP, "; for (int32_t i = 1; i < 4096; ++i) { if (i > 1) { sql.append(", "); } sql.append("c" + to_string(i) + " INT"); } sql.append(") TAGS (t1 int)"); run(sql, TSDB_CODE_PAR_TOO_MANY_COLUMNS); } /* * CREATE TOPIC [IF NOT EXISTS] topic_name AS subquery * * CREATE TOPIC [IF NOT EXISTS] topic_name [WITH META] AS {DATABASE db_name | STABLE stb_name } */ TEST_F(ParserInitialCTest, createTopic) { useDb("root", "test"); SCMCreateTopicReq expect = {0}; auto clearCreateTopicReq = [&]() { memset(&expect, 0, sizeof(SCMCreateTopicReq)); }; auto setCreateTopicReq = [&](const char* pTopicName, int8_t igExists, const char* pSql, const char* pAst, const char* pDbName = nullptr, const char* pTbname = nullptr, int8_t withMeta = 0) { snprintf(expect.name, sizeof(expect.name), "0.%s", pTopicName); expect.igExists = igExists; expect.sql = (char*)pSql; expect.withMeta = withMeta; if (nullptr != pTbname) { expect.subType = TOPIC_SUB_TYPE__TABLE; snprintf(expect.subStbName, sizeof(expect.subStbName), "0.%s.%s", pDbName, pTbname); } else if (nullptr != pAst) { expect.subType = TOPIC_SUB_TYPE__COLUMN; expect.ast = (char*)pAst; } else { expect.subType = TOPIC_SUB_TYPE__DB; snprintf(expect.subDbName, sizeof(expect.subDbName), "0.%s", pDbName); } }; setCheckDdlFunc([&](const SQuery* pQuery, ParserStage stage) { ASSERT_EQ(nodeType(pQuery->pRoot), QUERY_NODE_CREATE_TOPIC_STMT); SCMCreateTopicReq req = {0}; ASSERT_TRUE(TSDB_CODE_SUCCESS == tDeserializeSCMCreateTopicReq(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.subType, expect.subType); ASSERT_EQ(std::string(req.sql), std::string(expect.sql)); ASSERT_EQ(req.withMeta, expect.withMeta); switch (expect.subType) { case TOPIC_SUB_TYPE__DB: ASSERT_EQ(std::string(req.subDbName), std::string(expect.subDbName)); break; case TOPIC_SUB_TYPE__TABLE: ASSERT_EQ(std::string(req.subStbName), std::string(expect.subStbName)); break; case TOPIC_SUB_TYPE__COLUMN: ASSERT_NE(req.ast, nullptr); break; default: ASSERT_TRUE(false); } tFreeSCMCreateTopicReq(&req); }); setCreateTopicReq("tp1", 0, "create topic tp1 as select * from t1", "ast"); run("CREATE TOPIC tp1 AS SELECT * FROM t1"); clearCreateTopicReq(); setCreateTopicReq("tp1", 1, "create topic if not exists tp1 as select ts, ceil(c1) from t1", "ast"); run("CREATE TOPIC IF NOT EXISTS tp1 AS SELECT ts, CEIL(c1) FROM t1"); clearCreateTopicReq(); setCreateTopicReq("tp1", 0, "create topic tp1 as database test", nullptr, "test"); run("CREATE TOPIC tp1 AS DATABASE test"); clearCreateTopicReq(); setCreateTopicReq("tp1", 0, "create topic tp1 with meta as database test", nullptr, "test", nullptr, 1); run("CREATE TOPIC tp1 WITH META AS DATABASE test"); clearCreateTopicReq(); setCreateTopicReq("tp1", 1, "create topic if not exists tp1 as stable st1", nullptr, "test", "st1"); run("CREATE TOPIC IF NOT EXISTS tp1 AS STABLE st1"); clearCreateTopicReq(); setCreateTopicReq("tp1", 1, "create topic if not exists tp1 with meta as stable st1", nullptr, "test", "st1", 1); run("CREATE TOPIC IF NOT EXISTS tp1 WITH META AS STABLE st1"); clearCreateTopicReq(); } /* * CREATE USER use_name PASS password [SYSINFO value] */ TEST_F(ParserInitialCTest, createUser) { useDb("root", "test"); SCreateUserReq expect = {0}; auto clearCreateUserReq = [&]() { memset(&expect, 0, sizeof(SCreateUserReq)); }; auto setCreateUserReq = [&](const char* pUser, const char* pPass, int8_t sysInfo = 1) { strcpy(expect.user, pUser); strcpy(expect.pass, pPass); expect.createType = 0; expect.superUser = 0; expect.sysInfo = sysInfo; expect.enable = 1; }; setCheckDdlFunc([&](const SQuery* pQuery, ParserStage stage) { ASSERT_EQ(nodeType(pQuery->pRoot), QUERY_NODE_CREATE_USER_STMT); SCreateUserReq req = {0}; ASSERT_TRUE(TSDB_CODE_SUCCESS == tDeserializeSCreateUserReq(pQuery->pCmdMsg->pMsg, pQuery->pCmdMsg->msgLen, &req)); ASSERT_EQ(req.createType, expect.createType); ASSERT_EQ(req.superUser, expect.superUser); ASSERT_EQ(req.sysInfo, expect.sysInfo); ASSERT_EQ(req.enable, expect.enable); ASSERT_EQ(std::string(req.user), std::string(expect.user)); ASSERT_EQ(std::string(req.pass), std::string(expect.pass)); }); setCreateUserReq("wxy", "123456"); run("CREATE USER wxy PASS '123456'"); clearCreateUserReq(); setCreateUserReq("wxy1", "a123456", 1); run("CREATE USER wxy1 PASS 'a123456' SYSINFO 1"); clearCreateUserReq(); } } // namespace ParserTest