diff --git a/source/dnode/mnode/impl/src/mndStb.c b/source/dnode/mnode/impl/src/mndStb.c index eb2f9dcbe3..1ddd2f34e6 100644 --- a/source/dnode/mnode/impl/src/mndStb.c +++ b/source/dnode/mnode/impl/src/mndStb.c @@ -1014,6 +1014,20 @@ static int32_t mndFindSuperTableColumnIndex(const SStbObj *pStb, const char *col return -1; } +static bool mndValidateSchema(SSchema *pSchemas, int32_t nSchema, SArray *pFields, int32_t maxLen) { + int32_t rowLen = 0; + for (int32_t i = 0; i < nSchema; ++i) { + rowLen += (pSchemas + i)->bytes; + } + + int32_t nField = taosArrayGetSize(pFields); + for (int32_t i = 0; i < nField; ++i) { + rowLen += ((SField *)TARRAY_GET_ELEM(pFields, i))->bytes; + } + + return rowLen <= maxLen; +} + static int32_t mndBuildStbFromAlter(SStbObj *pStb, SStbObj *pDst, SMCreateStbReq *createReq) { taosRLockLatch(&pStb->lock); memcpy(pDst, pStb, sizeof(SStbObj)); @@ -1269,6 +1283,11 @@ static int32_t mndAddSuperTableTag(const SStbObj *pOld, SStbObj *pNew, SArray *p return -1; } + if (!mndValidateSchema(pOld->pTags, pOld->numOfTags, pFields, TSDB_MAX_TAGS_LEN)) { + terrno = TSDB_CODE_PAR_INVALID_TAGS_LENGTH; + return -1; + } + pNew->numOfTags = pNew->numOfTags + ntags; if (mndAllocStbSchemas(pOld, pNew) != 0) { return -1; @@ -1558,6 +1577,16 @@ static int32_t mndAlterStbTagBytes(SMnode *pMnode, const SStbObj *pOld, SStbObj return -1; } + uint32_t nLen = 0; + for (int32_t i = 0; i < pOld->numOfTags; ++i) { + nLen += (pOld->pTags[i].colId == colId) ? pField->bytes : pOld->pTags[i].bytes; + } + + if (nLen > TSDB_MAX_TAGS_LEN) { + terrno = TSDB_CODE_PAR_INVALID_TAGS_LENGTH; + return -1; + } + if (mndAllocStbSchemas(pOld, pNew) != 0) { return -1; } @@ -1592,6 +1621,11 @@ static int32_t mndAddSuperTableColumn(const SStbObj *pOld, SStbObj *pNew, SArray return -1; } + if (!mndValidateSchema(pOld->pColumns, pOld->numOfColumns, pFields, TSDB_MAX_BYTES_PER_ROW)) { + terrno = TSDB_CODE_PAR_INVALID_ROW_LENGTH; + return -1; + } + pNew->numOfColumns = pNew->numOfColumns + ncols; if (mndAllocStbSchemas(pOld, pNew) != 0) { return -1; diff --git a/tests/script/api/alterTableTest.c b/tests/script/api/alterTableTest.c new file mode 100644 index 0000000000..14605f4b8b --- /dev/null +++ b/tests/script/api/alterTableTest.c @@ -0,0 +1,175 @@ +/* + * 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 . + */ + +// TAOS standard API example. The same syntax as MySQL, but only a subset +// to compile: gcc -o demo demo.c -ltaos + +/** + * passwdTest.c + * - Run the test case in clear TDengine environment with default root passwd 'taosdata' + */ + +#include +#include +#include +#include +#include +#include "taos.h" // TAOS header file + +#define nDup 3 +#define USER_LEN 24 +#define BUF_LEN 1024 +#define DB "d0" +#define DB_BUFFER 32 +#define STB "stb" +#define CTB "ctb" +#define COL "c" + +#if 0 +#define STB_NUM 125 +#define CTB_NUM 960 +#define COL_NUM 52 +#define COL_NCHAR_LEN 320 +#else +#define STB_NUM 5 +#define CTB_NUM 1 +#define COL_NUM 505 +#define COL_NCHAR_LEN 32 +#endif +typedef uint16_t VarDataLenT; + +int32_t isDropDb = 0; + +#define TSDB_NCHAR_SIZE sizeof(int32_t) +#define VARSTR_HEADER_SIZE sizeof(VarDataLenT) + +#define GET_FLOAT_VAL(x) (*(float *)(x)) +#define GET_DOUBLE_VAL(x) (*(double *)(x)) + +#define varDataLen(v) ((VarDataLenT *)(v))[0] + +static int32_t queryDB(TAOS *taos, char *command, bool skipError) { + int i; + TAOS_RES *pSql = NULL; + int32_t code = -1; + + for (i = 0; i < nDup; ++i) { + if (NULL != pSql) { + taos_free_result(pSql); + pSql = NULL; + } + + pSql = taos_query(taos, command); + code = taos_errno(pSql); + if (0 == code) { + break; + } + } + + if (code != 0) { + fprintf(stderr, "failed to run: %s, reason: %s\n", command, taos_errstr(pSql)); + if (!skipError) { + taos_free_result(pSql); + taos_close(taos); + exit(EXIT_FAILURE); + } + } else { + fprintf(stderr, "success to run: %s\n", command); + } + + taos_free_result(pSql); +} + +static void createDatabaseAlterStbColumns(TAOS *taos, const char *host, char *qstr, int32_t addColMode) { + if (isDropDb) { + sprintf(qstr, "drop database if exists %s", DB); + queryDB(taos, qstr, false); + sprintf(qstr, "create database if not exists %s vgroups 2 buffer %d", DB, DB_BUFFER); + queryDB(taos, qstr, false); + } + sprintf(qstr, "use %s", DB); + queryDB(taos, qstr, false); + + // create stb + if (isDropDb) { + for (int i = 0; i < STB_NUM; ++i) { + sprintf(qstr, "CREATE table if not exists %s_%d (ts timestamp, %s_%d NCHAR(32)) tags(t0 nchar(16));", STB, i, COL, + 0); + queryDB(taos, qstr, false); + // create ctb + for (int j = 0; j < CTB_NUM; ++j) { + sprintf(qstr, "CREATE table %s_%d_%s_%d using %s_%d tags('%d_%d');", STB, i, CTB, j, STB, i, i, j); + queryDB(taos, qstr, false); + } + } + } + + if (isDropDb) { + printf("sleep 86400s to wait other terminal\n"); + sleep(86400); + } + + // alter stb cols + if (addColMode == 0) { + for (int i = 0; i < STB_NUM; ++i) { + for (int c = 1; c < COL_NUM; ++c) { + sprintf(qstr, "alter table %s_%d add column c_%d NCHAR(%d);", STB, i, c, COL_NCHAR_LEN); + queryDB(taos, qstr, true); + } + sprintf(qstr, "desc %s_%d;", STB, i); + queryDB(taos, qstr, false); + } + } else if (addColMode == 1) { + for (int c = 1; c < COL_NUM; ++c) { + for (int i = 0; i < STB_NUM; ++i) { + sprintf(qstr, "alter table %s_%d add column c_%d NCHAR(%d);", STB, i, c, COL_NCHAR_LEN); + queryDB(taos, qstr, true); + } + } + } + + // check + for (int i = 0; i < STB_NUM; ++i) { + sprintf(qstr, "desc %s_%d;", STB, i); + queryDB(taos, qstr, false); + } +} + +int main(int argc, char *argv[]) { + char qstr[1024]; + + // connect to server + if (argc < 2) { + printf("please input server-ip \n"); + return 0; + } + + if (argc < 3) { + printf("please specify if drop DB\n"); + return 0; + } + + isDropDb = atoi(argv[2]); + + TAOS *taos = taos_connect(argv[1], "root", "taosdata", NULL, 0); + if (taos == NULL) { + printf("failed to connect to server, reason:%s\n", "null taos" /*taos_errstr(taos)*/); + exit(1); + } + createDatabaseAlterStbColumns(taos, argv[1], qstr, 0); + + taos_close(taos); + taos_cleanup(); +} \ No newline at end of file