From b0fba34f527d17557da148762f628a3d687340f0 Mon Sep 17 00:00:00 2001 From: Xiaoyu Wang Date: Mon, 16 May 2022 15:49:01 +0800 Subject: [PATCH 1/6] feat: sql command 'alter table' --- include/util/taoserror.h | 1 + source/libs/parser/src/parTranslater.c | 25 ++++++++++++++++++------- source/libs/parser/src/parUtil.c | 2 ++ 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/include/util/taoserror.h b/include/util/taoserror.h index 96fb210e26..8b160f54f6 100644 --- a/include/util/taoserror.h +++ b/include/util/taoserror.h @@ -639,6 +639,7 @@ int32_t* taosGetErrno(); #define TSDB_CODE_PAR_INVALID_INTERNAL_PK TAOS_DEF_ERROR_CODE(0, 0x2646) #define TSDB_CODE_PAR_INVALID_TIMELINE_FUNC TAOS_DEF_ERROR_CODE(0, 0x2647) #define TSDB_CODE_PAR_INVALID_PASSWD TAOS_DEF_ERROR_CODE(0, 0x2648) +#define TSDB_CODE_PAR_INVALID_ALTER_TABLE TAOS_DEF_ERROR_CODE(0, 0x2649) //planner #define TSDB_CODE_PLAN_INTERNAL_ERROR TAOS_DEF_ERROR_CODE(0, 0x2700) diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index 9773b69ee7..3fa8225152 100644 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -2949,8 +2949,8 @@ static int32_t translateCreateIndex(STranslateContext* pCxt, SCreateIndexStmt* p } static int32_t translateDropIndex(STranslateContext* pCxt, SDropIndexStmt* pStmt) { - SEncoder encoder = {0}; - int32_t contLen = 0; + SEncoder encoder = {0}; + int32_t contLen = 0; SVDropTSmaReq dropSmaReq = {0}; strcpy(dropSmaReq.indexName, pStmt->indexName); @@ -2958,7 +2958,7 @@ static int32_t translateDropIndex(STranslateContext* pCxt, SDropIndexStmt* pStmt if (NULL == pCxt->pCmdMsg) { return TSDB_CODE_OUT_OF_MEMORY; } - + int32_t ret = 0; tEncodeSize(tEncodeSVDropTSmaReq, &dropSmaReq, contLen, ret); if (ret < 0) { @@ -4255,7 +4255,20 @@ static int32_t rewriteDropTable(STranslateContext* pCxt, SQuery* pQuery) { } static int32_t rewriteAlterTable(STranslateContext* pCxt, SQuery* pQuery) { - // todo + SAlterTableStmt* pStmt = (SAlterTableStmt*)pQuery->pRoot; + + STableMeta* pTableMeta = NULL; + int32_t code = getTableMeta(pCxt, pStmt->dbName, pStmt->tableName, &pTableMeta); + if (TSDB_CODE_SUCCESS != code) { + return code; + } + + if (TSDB_SUPER_TABLE == pTableMeta->tableType) { + return TSDB_CODE_SUCCESS; + } else if (TSDB_CHILD_TABLE != pTableMeta->tableType && TSDB_NORMAL_TABLE != pTableMeta->tableType) { + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_DROP_STABLE); + } + return TSDB_CODE_SUCCESS; } @@ -4296,9 +4309,7 @@ static int32_t rewriteQuery(STranslateContext* pCxt, SQuery* pQuery) { code = rewriteDropTable(pCxt, pQuery); break; case QUERY_NODE_ALTER_TABLE_STMT: - if (TSDB_ALTER_TABLE_UPDATE_TAG_VAL == ((SAlterTableStmt*)pQuery->pRoot)->alterType) { - code = rewriteAlterTable(pCxt, pQuery); - } + code = rewriteAlterTable(pCxt, pQuery); break; default: break; diff --git a/source/libs/parser/src/parUtil.c b/source/libs/parser/src/parUtil.c index 0c703c9dfc..e7716741ed 100644 --- a/source/libs/parser/src/parUtil.c +++ b/source/libs/parser/src/parUtil.c @@ -152,6 +152,8 @@ static char* getSyntaxErrFormat(int32_t errCode) { return "Invalid timeline function"; case TSDB_CODE_PAR_INVALID_PASSWD: return "Invalid password"; + case TSDB_CODE_PAR_INVALID_ALTER_TABLE: + return "Invalid alter table statement"; case TSDB_CODE_OUT_OF_MEMORY: return "Out of memory"; default: From 745f64aff61a520f43f031b8fd495c7d56c96558 Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Mon, 16 May 2022 17:16:20 +0800 Subject: [PATCH 2/6] refactor(query): do some internal refactor. --- source/libs/executor/inc/executorimpl.h | 1 + source/libs/executor/src/executorimpl.c | 6 ++--- source/libs/executor/src/scanoperator.c | 32 ++++++++++++++----------- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/source/libs/executor/inc/executorimpl.h b/source/libs/executor/inc/executorimpl.h index a032645493..6100d416b1 100644 --- a/source/libs/executor/inc/executorimpl.h +++ b/source/libs/executor/inc/executorimpl.h @@ -658,6 +658,7 @@ void initExecTimeWindowInfo(SColumnInfoData* pColData, STimeWindow* pQueryWin void cleanupAggSup(SAggSupporter* pAggSup); void destroyBasicOperatorInfo(void* param, int32_t numOfOutput); void appendOneRowToDataBlock(SSDataBlock* pBlock, STupleHandle* pTupleHandle); +void setTbNameColData(void* pMeta, const SSDataBlock* pBlock, SColumnInfoData* pColInfoData, int32_t functionId); SInterval extractIntervalInfo(const STableScanPhysiNode* pTableScanNode); SColumn extractColumnFromColumnNode(SColumnNode* pColNode); diff --git a/source/libs/executor/src/executorimpl.c b/source/libs/executor/src/executorimpl.c index 0ab172f03a..68417b4b8b 100644 --- a/source/libs/executor/src/executorimpl.c +++ b/source/libs/executor/src/executorimpl.c @@ -4372,9 +4372,9 @@ SOperatorInfo* createProjectOperatorInfo(SOperatorInfo* downstream, SExprInfo* p goto _error; } - pInfo->limit = *pLimit; - pInfo->slimit = *pSlimit; - pInfo->curOffset = pLimit->offset; + pInfo->limit = *pLimit; + pInfo->slimit = *pSlimit; + pInfo->curOffset = pLimit->offset; pInfo->curSOffset = pSlimit->offset; pInfo->binfo.pRes = pResBlock; diff --git a/source/libs/executor/src/scanoperator.c b/source/libs/executor/src/scanoperator.c index 65bd8f4bda..08539206a6 100644 --- a/source/libs/executor/src/scanoperator.c +++ b/source/libs/executor/src/scanoperator.c @@ -291,20 +291,7 @@ void addTagPseudoColumnData(STableScanInfo* pTableScanInfo, SSDataBlock* pBlock) // this is to handle the tbname if (fmIsScanPseudoColumnFunc(functionId)) { - struct SScalarFuncExecFuncs fpSet = {0}; - fmGetScalarFuncExecFuncs(functionId, &fpSet); - - SColumnInfoData infoData = {0}; - infoData.info.type = TSDB_DATA_TYPE_BIGINT; - infoData.info.bytes = sizeof(uint64_t); - colInfoDataEnsureCapacity(&infoData, 0, 1); - - colDataAppendInt64(&infoData, 0, &pBlock->info.uid); - SScalarParam srcParam = { - .numOfRows = pBlock->info.rows, .param = pTableScanInfo->readHandle.meta, .columnData = &infoData}; - - SScalarParam param = {.columnData = pColInfoData}; - fpSet.process(&srcParam, 1, ¶m); + setTbNameColData(pTableScanInfo->readHandle.meta, pBlock, pColInfoData, functionId); } else { // these are tags const char* p = metaGetTableTagVal(&mr.me, pExpr->base.pParam[0].pCol->colId); for (int32_t i = 0; i < pBlock->info.rows; ++i) { @@ -316,6 +303,23 @@ void addTagPseudoColumnData(STableScanInfo* pTableScanInfo, SSDataBlock* pBlock) metaReaderClear(&mr); } +void setTbNameColData(void* pMeta, const SSDataBlock* pBlock, SColumnInfoData* pColInfoData, int32_t functionId) { + struct SScalarFuncExecFuncs fpSet = {0}; + fmGetScalarFuncExecFuncs(functionId, &fpSet); + + SColumnInfoData infoData = {0}; + infoData.info.type = TSDB_DATA_TYPE_BIGINT; + infoData.info.bytes = sizeof(uint64_t); + colInfoDataEnsureCapacity(&infoData, 0, 1); + + colDataAppendInt64(&infoData, 0, (int64_t*) &pBlock->info.uid); + SScalarParam srcParam = { + .numOfRows = pBlock->info.rows, .param = pMeta, .columnData = &infoData}; + + SScalarParam param = {.columnData = pColInfoData}; + fpSet.process(&srcParam, 1, ¶m); +} + static SSDataBlock* doTableScanImpl(SOperatorInfo* pOperator) { STableScanInfo* pTableScanInfo = pOperator->info; SSDataBlock* pBlock = pTableScanInfo->pResBlock; From 4bac6c4fef1eb7ad9a3fffce9320bc368555f2f8 Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Mon, 16 May 2022 18:29:34 +0800 Subject: [PATCH 3/6] fix(query): avoid copy the unassigned column to the destination datablock after filter applied. --- source/libs/executor/src/executorimpl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/libs/executor/src/executorimpl.c b/source/libs/executor/src/executorimpl.c index 68417b4b8b..1cfabf2975 100644 --- a/source/libs/executor/src/executorimpl.c +++ b/source/libs/executor/src/executorimpl.c @@ -2055,6 +2055,11 @@ void extractQualifiedTupleByFilterResult(SSDataBlock* pBlock, const int8_t* rowR SColumnInfoData* pDst = taosArrayGet(px->pDataBlock, i); SColumnInfoData* pSrc = taosArrayGet(pBlock->pDataBlock, i); + // it is a reserved column for scalar function, and no data in this column yet. + if (pSrc->pData == NULL) { + continue; + } + int32_t numOfRows = 0; for (int32_t j = 0; j < totalRows; ++j) { if (rowRes[j] == 0) { From 8956b6f087b6a7ce5ce3b97b838a07f13f2bf70a Mon Sep 17 00:00:00 2001 From: jiajingbin Date: Mon, 16 May 2022 18:39:33 +0800 Subject: [PATCH 4/6] test: query_cols_tags_and_or.py optimization and add to ci --- .../2-query/query_cols_tags_and_or.py | 42 ++++++++++++------- tests/system-test/fulltest.sh | 2 +- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/tests/system-test/2-query/query_cols_tags_and_or.py b/tests/system-test/2-query/query_cols_tags_and_or.py index 77e91aa983..293afbbd7e 100644 --- a/tests/system-test/2-query/query_cols_tags_and_or.py +++ b/tests/system-test/2-query/query_cols_tags_and_or.py @@ -22,18 +22,6 @@ class TDTestCase: tdSql.init(conn.cursor(), logSql) def insertData(self, tb_name): - # insert_sql_list = [f'insert into {tb_name} values ("2021-01-01 12:00:00", 1, 1, 1, 3, 1.1, 1.1, "binary", "nchar", true, 1)', - # f'insert into {tb_name} values ("2021-01-05 12:00:00", 2, 2, 1, 3, 1.1, 1.1, "binary", "nchar", true, 2)', - # f'insert into {tb_name} values ("2021-01-07 12:00:00", 1, 3, 1, 2, 1.1, 1.1, "binary", "nchar", true, 3)', - # f'insert into {tb_name} values ("2021-01-09 12:00:00", 1, 2, 4, 3, 1.1, 1.1, "binary", "nchar", true, 4)', - # f'insert into {tb_name} values ("2021-01-11 12:00:00", 1, 2, 5, 5, 1.1, 1.1, "binary", "nchar", true, 5)', - # f'insert into {tb_name} values ("2021-01-13 12:00:00", 1, 2, 1, 3, 6.6, 1.1, "binary", "nchar", true, 6)', - # f'insert into {tb_name} values ("2021-01-15 12:00:00", 1, 2, 1, 3, 1.1, 7.7, "binary", "nchar", true, 7)', - # f'insert into {tb_name} values ("2021-01-17 12:00:00", 1, 2, 1, 3, 1.1, 1.1, "binary8", "nchar", true, 8)', - # f'insert into {tb_name} values ("2021-01-19 12:00:00", 1, 2, 1, 3, 1.1, 1.1, "binary", "nchar9", true, 9)', - # f'insert into {tb_name} values ("2021-01-21 12:00:00", 1, 2, 1, 3, 1.1, 1.1, "binary", "nchar", false, 10)', - # f'insert into {tb_name} values ("2021-01-23 12:00:00", 1, 3, 1, 3, 1.1, 1.1, Null, Null, false, 11)' - # ] insert_sql_list = [f'insert into {tb_name} values ("2021-01-01 12:00:00", 1, 1, 1, 3, 1.1, 1.1, "binary", "nchar", true, 1, 2, 3, 4)', f'insert into {tb_name} values ("2021-01-05 12:00:00", 2, 2, 1, 3, 1.1, 1.1, "binary", "nchar", true, 2, 3, 4, 5)', f'insert into {tb_name} values ("2021-01-07 12:00:00", 1, 3, 1, 2, 1.1, 1.1, "binary", "nchar", true, 3, 4, 5, 6)', @@ -54,7 +42,6 @@ class TDTestCase: tb_name = tdCom.getLongName(8, "letters") tdSql.execute( f"CREATE TABLE {tb_name} (ts timestamp, c1 tinyint, c2 smallint, c3 int, c4 bigint, c5 float, c6 double, c7 binary(100), c8 nchar(200), c9 bool, c10 tinyint unsigned, c11 smallint unsigned, c12 int unsigned, c13 bigint unsigned)") - # f"CREATE TABLE {tb_name} (ts timestamp, c1 tinyint, c2 smallint, c3 int, c4 bigint, c5 float, c6 double, c7 binary(100), c8 nchar(200), c9 bool, c10 int)") self.insertData(tb_name) return tb_name @@ -95,6 +82,31 @@ class TDTestCase: def queryTsCol(self, tb_name, check_elm=None): select_elm = "*" if check_elm is None else check_elm + # ts in + query_sql = f'select {select_elm} from {tb_name} where ts in ("2021-01-11 12:00:00", "2021-01-13 12:00:00")' + tdSql.query(query_sql) + tdSql.checkRows(2) + tdSql.checkEqual(self.queryLastC10(query_sql), 6) if select_elm == "*" else False + # ts in + query_sql = f'select {select_elm} from {tb_name} where ts not in ("2021-01-11 12:00:00", "2021-01-13 12:00:00")' + tdSql.query(query_sql) + tdSql.checkRows(9) + tdSql.checkEqual(self.queryLastC10(query_sql), 11) if select_elm == "*" else False + # ts not null + query_sql = f'select {select_elm} from {tb_name} where ts is not Null' + tdSql.query(query_sql) + tdSql.checkRows(11) + tdSql.checkEqual(self.queryLastC10(query_sql), 11) if select_elm == "*" else False + # ts null + query_sql = f'select {select_elm} from {tb_name} where ts is Null' + tdSql.query(query_sql) + tdSql.checkRows(0) + # not support like not like match nmatch + tdSql.error(f'select {select_elm} from {tb_name} where ts like ("2021-01-11 12:00:00%")') + tdSql.error(f'select {select_elm} from {tb_name} where ts not like ("2021-01-11 12:00:0_")') + tdSql.error(f'select {select_elm} from {tb_name} where ts match "2021-01-11 12:00:00%"') + tdSql.error(f'select {select_elm} from {tb_name} where ts nmatch "2021-01-11 12:00:00%"') + # ts and ts query_sql = f'select {select_elm} from {tb_name} where ts > "2021-01-11 12:00:00" or ts < "2021-01-13 12:00:00"' tdSql.query(query_sql) @@ -1422,9 +1434,9 @@ class TDTestCase: tdSql.query(query_sql) tdSql.checkRows(11) tdSql.checkEqual(self.queryLastC10(query_sql), 11) if select_elm == "*" else False - query_sql = f'select c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13 from {tb_name} where c9 > "binary" and c9 >= "binary8" or c9 < "binary9" and c9 <= "binary" and c9 != 2 and c9 <> 2 and c9 = 4 or c9 is not null and c9 between 2 and 4 and c9 not between 1 and 2 and c9 in (2,4) and c9 not in (1,2) or c9 match "binary[28]" or c9 nmatch "binary"' + query_sql = f'select c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13 from {tb_name} where c9 > "binary" and c9 >= "binary8" or c9 < "binary9" and c9 <= "binary" and c9 != 2 and c9 <> 2 and c9 = 4 or c9 is not null and c9 between 2 and 4 and c9 not between 1 and 2 and c9 in (2,4) and c9 not in (1,2)' tdSql.query(query_sql) - tdSql.checkRows(11) + tdSql.checkRows(9) def queryFullColType(self, tb_name, check_elm=None): select_elm = "*" if check_elm is None else check_elm diff --git a/tests/system-test/fulltest.sh b/tests/system-test/fulltest.sh index 2b813f83ca..585acb733a 100755 --- a/tests/system-test/fulltest.sh +++ b/tests/system-test/fulltest.sh @@ -53,6 +53,6 @@ python3 ./test.py -f 2-query/tan.py python3 ./test.py -f 2-query/arcsin.py python3 ./test.py -f 2-query/arccos.py python3 ./test.py -f 2-query/arctan.py -# python3 ./test.py -f 2-query/query_cols_tags_and_or.py +python3 ./test.py -f 2-query/query_cols_tags_and_or.py python3 ./test.py -f 7-tmq/basic5.py From 5c29cd816cd8a299241102fb18ecc872ed88c91f Mon Sep 17 00:00:00 2001 From: jiajingbin <39030567+jiajingbin@users.noreply.github.com> Date: Mon, 16 May 2022 18:47:12 +0800 Subject: [PATCH 5/6] Update query_cols_tags_and_or.py --- tests/system-test/2-query/query_cols_tags_and_or.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system-test/2-query/query_cols_tags_and_or.py b/tests/system-test/2-query/query_cols_tags_and_or.py index 293afbbd7e..5dc5a2f123 100644 --- a/tests/system-test/2-query/query_cols_tags_and_or.py +++ b/tests/system-test/2-query/query_cols_tags_and_or.py @@ -87,7 +87,7 @@ class TDTestCase: tdSql.query(query_sql) tdSql.checkRows(2) tdSql.checkEqual(self.queryLastC10(query_sql), 6) if select_elm == "*" else False - # ts in + # ts not in query_sql = f'select {select_elm} from {tb_name} where ts not in ("2021-01-11 12:00:00", "2021-01-13 12:00:00")' tdSql.query(query_sql) tdSql.checkRows(9) From 9a3e1f03af12a7a16cece9e43bbfdccbac8a6207 Mon Sep 17 00:00:00 2001 From: Xiaoyu Wang Date: Mon, 16 May 2022 18:59:14 +0800 Subject: [PATCH 6/6] feat: sql command 'alter table' --- source/common/src/tmsg.c | 1 - source/libs/parser/inc/sql.y | 2 +- source/libs/parser/src/parTranslater.c | 147 ++++++++++++++++++- source/libs/parser/src/sql.c | 2 +- source/libs/parser/test/parInitialATest.cpp | 150 ++++++++++++++++++-- source/libs/planner/src/planLogicCreater.c | 2 + source/libs/scheduler/src/scheduler.c | 27 ++++ 7 files changed, 307 insertions(+), 24 deletions(-) diff --git a/source/common/src/tmsg.c b/source/common/src/tmsg.c index 52edd79f3b..d180c2ff6e 100644 --- a/source/common/src/tmsg.c +++ b/source/common/src/tmsg.c @@ -4217,7 +4217,6 @@ int32_t tDecodeSVAlterTbReq(SDecoder *pDecoder, SVAlterTbReq *pReq) { if (tDecodeCStr(pDecoder, &pReq->tbName) < 0) return -1; if (tDecodeI8(pDecoder, &pReq->action) < 0) return -1; - if (tDecodeCStr(pDecoder, &pReq->colName) < 0) return -1; switch (pReq->action) { case TSDB_ALTER_TABLE_ADD_COLUMN: if (tDecodeCStr(pDecoder, &pReq->colName) < 0) return -1; diff --git a/source/libs/parser/inc/sql.y b/source/libs/parser/inc/sql.y index 9c83b600d2..836e97c4db 100644 --- a/source/libs/parser/inc/sql.y +++ b/source/libs/parser/inc/sql.y @@ -241,7 +241,7 @@ alter_table_clause(A) ::= alter_table_clause(A) ::= full_table_name(B) RENAME TAG column_name(C) column_name(D). { A = createAlterTableRenameCol(pCxt, B, TSDB_ALTER_TABLE_UPDATE_TAG_NAME, &C, &D); } alter_table_clause(A) ::= - full_table_name(B) SET TAG column_name(C) NK_EQ literal(D). { A = createAlterTableSetTag(pCxt, B, &C, D); } + full_table_name(B) SET TAG column_name(C) NK_EQ literal(D). { A = createAlterTableSetTag(pCxt, B, &C, releaseRawExprNode(pCxt, D)); } %type multi_create_clause { SNodeList* } %destructor multi_create_clause { nodesDestroyList($$); } diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index 3fa8225152..3983b53b6e 100644 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -3800,7 +3800,7 @@ static void destroyCreateTbReqBatch(SVgroupCreateTableBatch* pTbBatch) { taosArrayDestroy(pTbBatch->req.pArray); } -static int32_t rewriteToVnodeModifOpStmt(SQuery* pQuery, SArray* pBufArray) { +static int32_t rewriteToVnodeModifyOpStmt(SQuery* pQuery, SArray* pBufArray) { SVnodeModifOpStmt* pNewStmt = nodesMakeNode(QUERY_NODE_VNODE_MODIF_STMT); if (pNewStmt == NULL) { return TSDB_CODE_OUT_OF_MEMORY; @@ -3855,7 +3855,7 @@ static int32_t rewriteCreateTable(STranslateContext* pCxt, SQuery* pQuery) { code = buildCreateTableDataBlock(pCxt->pParseCxt->acctId, pStmt, &info, &pBufArray); } if (TSDB_CODE_SUCCESS == code) { - code = rewriteToVnodeModifOpStmt(pQuery, pBufArray); + code = rewriteToVnodeModifyOpStmt(pQuery, pBufArray); if (TSDB_CODE_SUCCESS != code) { destroyCreateTbReqArray(pBufArray); } @@ -4111,7 +4111,7 @@ static int32_t rewriteCreateMultiTable(STranslateContext* pCxt, SQuery* pQuery) return TSDB_CODE_OUT_OF_MEMORY; } - return rewriteToVnodeModifOpStmt(pQuery, pBufArray); + return rewriteToVnodeModifyOpStmt(pQuery, pBufArray); } typedef struct SVgroupDropTableBatch { @@ -4251,7 +4251,131 @@ static int32_t rewriteDropTable(STranslateContext* pCxt, SQuery* pQuery) { return TSDB_CODE_OUT_OF_MEMORY; } - return rewriteToVnodeModifOpStmt(pQuery, pBufArray); + return rewriteToVnodeModifyOpStmt(pQuery, pBufArray); +} + +static int32_t buildAlterTbReq(STranslateContext* pCxt, SAlterTableStmt* pStmt, SVAlterTbReq* pReq) { + pReq->tbName = strdup(pStmt->tableName); + if (NULL == pReq->tbName) { + return TSDB_CODE_OUT_OF_MEMORY; + } + pReq->action = pStmt->alterType; + + switch (pStmt->alterType) { + case TSDB_ALTER_TABLE_ADD_TAG: + case TSDB_ALTER_TABLE_DROP_TAG: + case TSDB_ALTER_TABLE_UPDATE_TAG_NAME: + case TSDB_ALTER_TABLE_UPDATE_TAG_BYTES: + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_ALTER_TABLE); + case TSDB_ALTER_TABLE_UPDATE_TAG_VAL: + pReq->tagName = strdup(pStmt->colName); + if (NULL == pReq->tagName) { + return TSDB_CODE_OUT_OF_MEMORY; + } + if (DEAL_RES_ERROR == translateValue(pCxt, pStmt->pVal)) { + return pCxt->errCode; + } + pReq->isNull = (TSDB_DATA_TYPE_NULL == pStmt->pVal->node.resType.type); + pReq->nTagVal = pStmt->pVal->node.resType.bytes; + char* pVal = nodesGetValueFromNode(pStmt->pVal); + pReq->pTagVal = IS_VAR_DATA_TYPE(pStmt->pVal->node.resType.type) ? pVal + VARSTR_HEADER_SIZE : pVal; + break; + case TSDB_ALTER_TABLE_ADD_COLUMN: + case TSDB_ALTER_TABLE_DROP_COLUMN: + pReq->colName = strdup(pStmt->colName); + if (NULL == pReq->colName) { + return TSDB_CODE_OUT_OF_MEMORY; + } + pReq->type = pStmt->dataType.type; + pReq->flags = COL_SMA_ON; + pReq->bytes = pStmt->dataType.bytes; + break; + case TSDB_ALTER_TABLE_UPDATE_COLUMN_BYTES: + pReq->colName = strdup(pStmt->colName); + if (NULL == pReq->colName) { + return TSDB_CODE_OUT_OF_MEMORY; + } + pReq->colModBytes = calcTypeBytes(pStmt->dataType); + break; + case TSDB_ALTER_TABLE_UPDATE_OPTIONS: + if (-1 != pStmt->pOptions->ttl) { + pReq->updateTTL = true; + pReq->newTTL = pStmt->pOptions->ttl; + } + if ('\0' != pStmt->pOptions->comment[0]) { + pReq->updateComment = true; + pReq->newComment = strdup(pStmt->pOptions->comment); + if (NULL == pReq->newComment) { + return TSDB_CODE_OUT_OF_MEMORY; + } + } + break; + case TSDB_ALTER_TABLE_UPDATE_COLUMN_NAME: + pReq->colName = strdup(pStmt->colName); + pReq->colNewName = strdup(pStmt->newColName); + if (NULL == pReq->colName || NULL == pReq->colNewName) { + return TSDB_CODE_OUT_OF_MEMORY; + } + break; + default: + break; + } + + return TSDB_CODE_SUCCESS; +} + +static int32_t serializeAlterTbReq(STranslateContext* pCxt, SAlterTableStmt* pStmt, SVAlterTbReq* pReq, + SArray* pArray) { + SVgroupInfo vg = {0}; + int32_t code = getTableHashVgroup(pCxt, pStmt->dbName, pStmt->tableName, &vg); + int tlen = 0; + if (TSDB_CODE_SUCCESS == code) { + tEncodeSize(tEncodeSVAlterTbReq, pReq, tlen, code); + } + if (TSDB_CODE_SUCCESS == code) { + tlen += sizeof(SMsgHead); + void* pMsg = taosMemoryMalloc(tlen); + if (NULL == pMsg) { + return TSDB_CODE_OUT_OF_MEMORY; + } + ((SMsgHead*)pMsg)->vgId = htonl(vg.vgId); + ((SMsgHead*)pMsg)->contLen = htonl(tlen); + void* pBuf = POINTER_SHIFT(pMsg, sizeof(SMsgHead)); + SEncoder coder = {0}; + tEncoderInit(&coder, pBuf, tlen - sizeof(SMsgHead)); + tEncodeSVAlterTbReq(&coder, pReq); + tEncoderClear(&coder); + + SVgDataBlocks* pVgData = taosMemoryCalloc(1, sizeof(SVgDataBlocks)); + if (NULL == pVgData) { + taosMemoryFree(pMsg); + return TSDB_CODE_OUT_OF_MEMORY; + } + pVgData->vg = vg; + pVgData->pData = pMsg; + pVgData->size = tlen; + pVgData->numOfTables = 1; + taosArrayPush(pArray, &pVgData); + } + + return code; +} + +static int32_t buildModifyVnodeArray(STranslateContext* pCxt, SAlterTableStmt* pStmt, SVAlterTbReq* pReq, + SArray** pArray) { + SArray* pTmpArray = taosArrayInit(1, sizeof(void*)); + if (NULL == pTmpArray) { + return TSDB_CODE_OUT_OF_MEMORY; + } + + int32_t code = serializeAlterTbReq(pCxt, pStmt, pReq, pTmpArray); + if (TSDB_CODE_SUCCESS == code) { + *pArray = pTmpArray; + } else { + taosArrayDestroy(pTmpArray); + } + + return code; } static int32_t rewriteAlterTable(STranslateContext* pCxt, SQuery* pQuery) { @@ -4266,10 +4390,21 @@ static int32_t rewriteAlterTable(STranslateContext* pCxt, SQuery* pQuery) { if (TSDB_SUPER_TABLE == pTableMeta->tableType) { return TSDB_CODE_SUCCESS; } else if (TSDB_CHILD_TABLE != pTableMeta->tableType && TSDB_NORMAL_TABLE != pTableMeta->tableType) { - return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_DROP_STABLE); + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_ALTER_TABLE); } - return TSDB_CODE_SUCCESS; + SVAlterTbReq req = {0}; + code = buildAlterTbReq(pCxt, pStmt, &req); + + SArray* pArray = NULL; + if (TSDB_CODE_SUCCESS == code) { + code = buildModifyVnodeArray(pCxt, pStmt, &req, &pArray); + } + if (TSDB_CODE_SUCCESS == code) { + code = rewriteToVnodeModifyOpStmt(pQuery, pArray); + } + + return code; } static int32_t rewriteQuery(STranslateContext* pCxt, SQuery* pQuery) { diff --git a/source/libs/parser/src/sql.c b/source/libs/parser/src/sql.c index 4293131338..ed812405e0 100644 --- a/source/libs/parser/src/sql.c +++ b/source/libs/parser/src/sql.c @@ -3500,7 +3500,7 @@ static YYACTIONTYPE yy_reduce( yymsp[-4].minor.yy172 = yylhsminor.yy172; break; case 121: /* alter_table_clause ::= full_table_name SET TAG column_name NK_EQ literal */ -{ yylhsminor.yy172 = createAlterTableSetTag(pCxt, yymsp[-5].minor.yy172, &yymsp[-2].minor.yy105, yymsp[0].minor.yy172); } +{ yylhsminor.yy172 = createAlterTableSetTag(pCxt, yymsp[-5].minor.yy172, &yymsp[-2].minor.yy105, releaseRawExprNode(pCxt, yymsp[0].minor.yy172)); } yymsp[-5].minor.yy172 = yylhsminor.yy172; break; case 123: /* multi_create_clause ::= multi_create_clause create_subtable_clause */ diff --git a/source/libs/parser/test/parInitialATest.cpp b/source/libs/parser/test/parInitialATest.cpp index 4ddb7736b2..e1fa8ffe8d 100644 --- a/source/libs/parser/test/parInitialATest.cpp +++ b/source/libs/parser/test/parInitialATest.cpp @@ -69,7 +69,7 @@ TEST_F(ParserInitialATest, alterDatabase) { * | COMMENT 'string_value' * } */ -TEST_F(ParserInitialATest, alterTable) { +TEST_F(ParserInitialATest, alterSTable) { useDb("root", "test"); SMAlterStbReq expect = {0}; @@ -119,7 +119,7 @@ TEST_F(ParserInitialATest, alterTable) { 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(tDeserializeSMAlterStbReq(pQuery->pCmdMsg->pMsg, pQuery->pCmdMsg->msgLen, &req), TSDB_CODE_SUCCESS); ASSERT_EQ(std::string(req.name), std::string(expect.name)); ASSERT_EQ(req.alterType, expect.alterType); ASSERT_EQ(req.numOfFields, expect.numOfFields); @@ -139,24 +139,24 @@ TEST_F(ParserInitialATest, alterTable) { } }); - setAlterStbReqFunc("t1", TSDB_ALTER_TABLE_UPDATE_OPTIONS, 0, nullptr, 0, 0, nullptr, nullptr, 10); - run("ALTER TABLE t1 TTL 10"); + setAlterStbReqFunc("st1", TSDB_ALTER_TABLE_UPDATE_OPTIONS, 0, nullptr, 0, 0, nullptr, nullptr, 10); + run("ALTER TABLE st1 TTL 10"); - setAlterStbReqFunc("t1", TSDB_ALTER_TABLE_UPDATE_OPTIONS, 0, nullptr, 0, 0, nullptr, "test"); - run("ALTER TABLE t1 COMMENT 'test'"); + setAlterStbReqFunc("st1", TSDB_ALTER_TABLE_UPDATE_OPTIONS, 0, nullptr, 0, 0, nullptr, "test"); + run("ALTER TABLE st1 COMMENT 'test'"); - setAlterStbReqFunc("t1", TSDB_ALTER_TABLE_ADD_COLUMN, 1, "cc1", TSDB_DATA_TYPE_BIGINT); - run("ALTER TABLE t1 ADD COLUMN cc1 BIGINT"); + setAlterStbReqFunc("st1", TSDB_ALTER_TABLE_ADD_COLUMN, 1, "cc1", TSDB_DATA_TYPE_BIGINT); + run("ALTER TABLE st1 ADD COLUMN cc1 BIGINT"); - setAlterStbReqFunc("t1", TSDB_ALTER_TABLE_DROP_COLUMN, 1, "c1"); - run("ALTER TABLE t1 DROP COLUMN c1"); + setAlterStbReqFunc("st1", TSDB_ALTER_TABLE_DROP_COLUMN, 1, "c1"); + run("ALTER TABLE st1 DROP COLUMN c1"); - setAlterStbReqFunc("t1", TSDB_ALTER_TABLE_UPDATE_COLUMN_BYTES, 1, "c1", TSDB_DATA_TYPE_VARCHAR, + setAlterStbReqFunc("st1", 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)"); + run("ALTER TABLE st1 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_UPDATE_COLUMN_NAME, 2, "c1", 0, 0, "cc1"); + run("ALTER TABLE st1 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"); @@ -171,7 +171,127 @@ TEST_F(ParserInitialATest, alterTable) { 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"); + // todo + // ADD {FULLTEXT | SMA} INDEX index_name (col_name [, col_name] ...) [index_option] +} + +TEST_F(ParserInitialATest, alterTable) { + useDb("root", "test"); + + SVAlterTbReq expect = {0}; + + auto setAlterColFunc = [&](const char* pTbname, int8_t alterType, const char* pColName, int8_t dataType = 0, + int32_t dataBytes = 0, const char* pNewColName = nullptr) { + memset(&expect, 0, sizeof(SVAlterTbReq)); + expect.tbName = strdup(pTbname); + expect.action = alterType; + expect.colName = strdup(pColName); + + switch (alterType) { + case TSDB_ALTER_TABLE_ADD_COLUMN: + expect.type = dataType; + expect.flags = COL_SMA_ON; + expect.bytes = dataBytes > 0 ? dataBytes : (dataType > 0 ? tDataTypes[dataType].bytes : 0); + break; + case TSDB_ALTER_TABLE_UPDATE_COLUMN_BYTES: + expect.colModBytes = dataBytes; + break; + case TSDB_ALTER_TABLE_UPDATE_COLUMN_NAME: + expect.colNewName = strdup(pNewColName); + break; + default: + break; + } + }; + + auto setAlterTagFunc = [&](const char* pTbname, const char* pTagName, const uint8_t* pNewVal, uint32_t bytes) { + memset(&expect, 0, sizeof(SVAlterTbReq)); + expect.tbName = strdup(pTbname); + expect.action = TSDB_ALTER_TABLE_UPDATE_TAG_VAL; + expect.tagName = strdup(pTagName); + + expect.isNull = (nullptr == pNewVal); + expect.nTagVal = bytes; + expect.pTagVal = pNewVal; + }; + + auto setAlterOptionsFunc = [&](const char* pTbname, int32_t ttl, const char* pComment = nullptr) { + memset(&expect, 0, sizeof(SVAlterTbReq)); + expect.tbName = strdup(pTbname); + expect.action = TSDB_ALTER_TABLE_UPDATE_OPTIONS; + if (-1 != ttl) { + expect.updateTTL = true; + expect.newTTL = ttl; + } + if (nullptr != pComment) { + expect.updateComment = true; + expect.newComment = pComment; + } + }; + + setCheckDdlFunc([&](const SQuery* pQuery, ParserStage stage) { + ASSERT_EQ(nodeType(pQuery->pRoot), QUERY_NODE_VNODE_MODIF_STMT); + SVnodeModifOpStmt* pStmt = (SVnodeModifOpStmt*)pQuery->pRoot; + + ASSERT_EQ(pStmt->sqlNodeType, QUERY_NODE_ALTER_TABLE_STMT); + ASSERT_NE(pStmt->pDataBlocks, nullptr); + ASSERT_EQ(taosArrayGetSize(pStmt->pDataBlocks), 1); + SVgDataBlocks* pVgData = (SVgDataBlocks*)taosArrayGetP(pStmt->pDataBlocks, 0); + void* pBuf = POINTER_SHIFT(pVgData->pData, sizeof(SMsgHead)); + SVAlterTbReq req = {0}; + SDecoder coder = {0}; + tDecoderInit(&coder, (const uint8_t*)pBuf, pVgData->size); + ASSERT_EQ(tDecodeSVAlterTbReq(&coder, &req), TSDB_CODE_SUCCESS); + + ASSERT_EQ(std::string(req.tbName), std::string(expect.tbName)); + ASSERT_EQ(req.action, expect.action); + if (nullptr != expect.colName) { + ASSERT_EQ(std::string(req.colName), std::string(expect.colName)); + } + ASSERT_EQ(req.type, expect.type); + ASSERT_EQ(req.flags, expect.flags); + ASSERT_EQ(req.bytes, expect.bytes); + ASSERT_EQ(req.colModBytes, expect.colModBytes); + if (nullptr != expect.colNewName) { + ASSERT_EQ(std::string(req.colNewName), std::string(expect.colNewName)); + } + if (nullptr != expect.tagName) { + ASSERT_EQ(std::string(req.tagName), std::string(expect.tagName)); + } + ASSERT_EQ(req.isNull, expect.isNull); + ASSERT_EQ(req.nTagVal, expect.nTagVal); + ASSERT_EQ(memcmp(req.pTagVal, expect.pTagVal, expect.nTagVal), 0); + ASSERT_EQ(req.updateTTL, expect.updateTTL); + ASSERT_EQ(req.newTTL, expect.newTTL); + ASSERT_EQ(req.updateComment, expect.updateComment); + if (nullptr != expect.newComment) { + ASSERT_EQ(std::string(req.newComment), std::string(expect.newComment)); + } + + tDecoderClear(&coder); + }); + + setAlterOptionsFunc("t1", 10, nullptr); + run("ALTER TABLE t1 TTL 10"); + + setAlterOptionsFunc("t1", -1, "test"); + run("ALTER TABLE t1 COMMENT 'test'"); + + setAlterColFunc("t1", TSDB_ALTER_TABLE_ADD_COLUMN, "cc1", TSDB_DATA_TYPE_BIGINT); + run("ALTER TABLE t1 ADD COLUMN cc1 BIGINT"); + + setAlterColFunc("t1", TSDB_ALTER_TABLE_DROP_COLUMN, "c1"); + run("ALTER TABLE t1 DROP COLUMN c1"); + + setAlterColFunc("t1", TSDB_ALTER_TABLE_UPDATE_COLUMN_BYTES, "c1", TSDB_DATA_TYPE_VARCHAR, 20 + VARSTR_HEADER_SIZE); + run("ALTER TABLE t1 MODIFY COLUMN c1 VARCHAR(20)"); + + setAlterColFunc("t1", TSDB_ALTER_TABLE_UPDATE_COLUMN_NAME, "c1", 0, 0, "cc1"); + run("ALTER TABLE t1 RENAME COLUMN c1 cc1"); + + int64_t val = 10; + setAlterTagFunc("st1s1", "tag1", (const uint8_t*)&val, sizeof(val)); + run("ALTER TABLE st1s1 SET TAG tag1=10"); // todo // ADD {FULLTEXT | SMA} INDEX index_name (col_name [, col_name] ...) [index_option] diff --git a/source/libs/planner/src/planLogicCreater.c b/source/libs/planner/src/planLogicCreater.c index d4b9f5b292..c2434e60f3 100644 --- a/source/libs/planner/src/planLogicCreater.c +++ b/source/libs/planner/src/planLogicCreater.c @@ -985,6 +985,8 @@ static int32_t getMsgType(ENodeType sqlType) { return TDMT_VND_CREATE_TABLE; case QUERY_NODE_DROP_TABLE_STMT: return TDMT_VND_DROP_TABLE; + case QUERY_NODE_ALTER_TABLE_STMT: + return TDMT_VND_ALTER_TABLE; default: break; } diff --git a/source/libs/scheduler/src/scheduler.c b/source/libs/scheduler/src/scheduler.c index 2710e54f95..5637539fea 100644 --- a/source/libs/scheduler/src/scheduler.c +++ b/source/libs/scheduler/src/scheduler.c @@ -256,6 +256,7 @@ int32_t schValidateTaskReceivedMsgType(SSchJob *pJob, SSchTask *pTask, int32_t m return TSDB_CODE_SUCCESS; case TDMT_VND_CREATE_TABLE_RSP: case TDMT_VND_DROP_TABLE_RSP: + case TDMT_VND_ALTER_TABLE_RSP: case TDMT_VND_SUBMIT_RSP: break; default: @@ -1131,6 +1132,24 @@ int32_t schHandleResponseMsg(SSchJob *pJob, SSchTask *pTask, int32_t msgType, ch SCH_ERR_RET(schProcessOnTaskSuccess(pJob, pTask)); break; } + case TDMT_VND_ALTER_TABLE_RSP: { + SVAlterTbRsp rsp = {0}; + if (msg) { + SDecoder coder = {0}; + tDecoderInit(&coder, msg, msgSize); + code = tDecodeSVAlterTbRsp(&coder, &rsp); + tDecoderClear(&coder); + SCH_ERR_JRET(code); + SCH_ERR_JRET(rsp.code); + } + + SCH_ERR_JRET(rspCode); + + if (NULL == msg) { + SCH_ERR_JRET(TSDB_CODE_QRY_INVALID_INPUT); + } + break; + } case TDMT_VND_SUBMIT_RSP: { SCH_ERR_JRET(rspCode); @@ -1391,6 +1410,10 @@ int32_t schHandleDropTableCallback(void *param, const SDataBuf *pMsg, int32_t co return schHandleCallback(param, pMsg, TDMT_VND_DROP_TABLE_RSP, code); } +int32_t schHandleAlterTableCallback(void *param, const SDataBuf *pMsg, int32_t code) { + return schHandleCallback(param, pMsg, TDMT_VND_ALTER_TABLE_RSP, code); +} + int32_t schHandleQueryCallback(void *param, const SDataBuf *pMsg, int32_t code) { return schHandleCallback(param, pMsg, TDMT_VND_QUERY_RSP, code); } @@ -1490,6 +1513,9 @@ int32_t schGetCallbackFp(int32_t msgType, __async_send_cb_fn_t *fp) { case TDMT_VND_DROP_TABLE: *fp = schHandleDropTableCallback; break; + case TDMT_VND_ALTER_TABLE: + *fp = schHandleAlterTableCallback; + break; case TDMT_VND_SUBMIT: *fp = schHandleSubmitCallback; break; @@ -2010,6 +2036,7 @@ int32_t schBuildAndSendMsg(SSchJob *pJob, SSchTask *pTask, SQueryNodeAddr *addr, switch (msgType) { case TDMT_VND_CREATE_TABLE: case TDMT_VND_DROP_TABLE: + case TDMT_VND_ALTER_TABLE: case TDMT_VND_SUBMIT: { msgSize = pTask->msgLen; msg = taosMemoryCalloc(1, msgSize);