From 42903d3d1f7473d9b0f50fa1db26cc08587e7dec Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Thu, 23 Dec 2021 10:33:11 +0800 Subject: [PATCH] [td-11818] support use db/create stable. --- include/common/taosmsg.h | 50 +++++-- include/common/tmsgtype.h | 8 - include/common/tname.h | 2 - include/libs/parser/parser.h | 11 +- source/client/inc/clientInt.h | 7 +- source/client/src/clientImpl.c | 27 +++- source/client/src/clientMain.c | 6 + source/client/src/clientMsgHandler.c | 29 +++- source/client/test/clientTests.cpp | 26 +++- source/common/src/tname.c | 35 +---- source/libs/parser/inc/astToMsg.h | 1 + source/libs/parser/inc/parserInt.h | 10 +- source/libs/parser/inc/parserUtil.h | 1 + source/libs/parser/src/astGenerator.c | 5 +- source/libs/parser/src/astToMsg.c | 124 ++++++++++++++++ source/libs/parser/src/astValidate.c | 187 +++++++++++++++++++++++- source/libs/parser/src/parser.c | 8 +- source/libs/parser/src/parserUtil.c | 6 +- source/libs/parser/src/sql.c | 1 + source/libs/parser/test/parserTests.cpp | 9 +- 20 files changed, 468 insertions(+), 85 deletions(-) diff --git a/include/common/taosmsg.h b/include/common/taosmsg.h index 8229cae281..8be43bd8e3 100644 --- a/include/common/taosmsg.h +++ b/include/common/taosmsg.h @@ -95,15 +95,15 @@ TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_NETWORK_TEST, "nettest" ) // message from mnode to vnode TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_CREATE_STB_IN, "create-stb-internal" ) -TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_ALTER_STB_IN, "alter-stb-internal" ) +TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_ALTER_STB_IN, "alter-stb-internal" ) TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_DROP_STB_IN, "drop-stb-internal" ) // message from mnode to mnode // message from mnode to qnode // message from mnode to dnode TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_CREATE_VNODE_IN, "create-vnode-internal" ) TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_ALTER_VNODE_IN, "alter-vnode-internal" ) -TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_DROP_VNODE_IN, "drop-vnode-internal" ) -TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_AUTH_VNODE_IN, "auth-vnode-internal" ) +TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_DROP_VNODE_IN, "drop-vnode-internal" ) +TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_AUTH_VNODE_IN, "auth-vnode-internal" ) TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_SYNC_VNODE_IN, "sync-vnode-internal" ) TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_COMPACT_VNODE_IN, "compact-vnode-internal" ) TAOS_DEFINE_MESSAGE_TYPE( TSDB_MSG_TYPE_CREATE_MNODE_IN, "create-mnode-internal" ) @@ -290,6 +290,37 @@ typedef struct SSchema { char name[TSDB_COL_NAME_LEN]; } SSchema; +typedef struct { + int32_t contLen; + int32_t vgId; + int8_t tableType; + int16_t numOfColumns; + int16_t numOfTags; + int32_t tid; + int32_t sversion; + int32_t tversion; + int32_t tagDataLen; + int32_t sqlDataLen; + uint64_t uid; + uint64_t superTableUid; + uint64_t createdTime; + char tableFname[TSDB_TABLE_FNAME_LEN]; + char stbFname[TSDB_TABLE_FNAME_LEN]; + char data[]; +} SMDCreateTableMsg; + +typedef struct { + int32_t len; // one create table message + char tableName[TSDB_TABLE_FNAME_LEN]; + int16_t numOfTags; + int16_t numOfColumns; + int16_t sqlLen; // the length of SQL, it starts after schema , sql is a null-terminated string + int8_t igExists; + int8_t rspMeta; + int8_t reserved[16]; + char schema[]; +} SCreateTableMsg; + typedef struct { char name[TSDB_TABLE_FNAME_LEN]; int8_t igExists; @@ -327,19 +358,6 @@ typedef struct { uint64_t suid; } SDropStbInternalMsg; -typedef struct { - SMsgHead head; - char name[TSDB_TABLE_FNAME_LEN]; - char stbFname[TSDB_TABLE_FNAME_LEN]; - int8_t tableType; - uint64_t suid; - int32_t sversion; - int32_t numOfTags; - int32_t numOfColumns; - int32_t tagDataLen; - char data[]; -} SCreateTableMsg; - typedef struct { SMsgHead head; char name[TSDB_TABLE_FNAME_LEN]; diff --git a/include/common/tmsgtype.h b/include/common/tmsgtype.h index 0976503115..8e7ad87a0a 100644 --- a/include/common/tmsgtype.h +++ b/include/common/tmsgtype.h @@ -102,14 +102,6 @@ enum { TSDB_DEFINE_SQL_TYPE( TSDB_SQL_MAX, "max" ) }; -// create table operation type -enum TSQL_CREATE_TABLE_TYPE { - TSQL_CREATE_TABLE = 0x1, - TSQL_CREATE_STABLE = 0x2, - TSQL_CREATE_CTABLE = 0x3, - TSQL_CREATE_STREAM = 0x4, -}; - #ifdef __cplusplus } #endif diff --git a/include/common/tname.h b/include/common/tname.h index e31bfd38a6..de9e309b55 100644 --- a/include/common/tname.h +++ b/include/common/tname.h @@ -16,8 +16,6 @@ #ifndef TDENGINE_TNAME_H #define TDENGINE_TNAME_H -//#include "taosmsg.h" - #define TSDB_DB_NAME_T 1 #define TSDB_TABLE_NAME_T 2 diff --git a/include/libs/parser/parser.h b/include/libs/parser/parser.h index 8e26fa98c9..a92398602b 100644 --- a/include/libs/parser/parser.h +++ b/include/libs/parser/parser.h @@ -29,7 +29,7 @@ extern "C" { typedef struct SField { char name[TSDB_COL_NAME_LEN]; uint8_t type; - int16_t bytes; + int32_t bytes; } SField; typedef struct SFieldInfo { @@ -38,6 +38,13 @@ typedef struct SFieldInfo { SArray *internalField; // SArray } SFieldInfo; +// TODO merged with SParseContext +typedef struct SParseCtx { + char *db; + int32_t acctId; + uint64_t requestId; +} SParseCtx; + typedef struct SCond { uint64_t uid; int32_t len; // length of tag query condition data @@ -153,7 +160,7 @@ typedef struct SParseContext { * @param msg extended error message if exists. * @return error code */ -int32_t qParseQuerySql(const char* pStr, size_t length, int64_t id, int32_t* type, void** pOutput, int32_t* outputLen, char* msg, int32_t msgLen); +int32_t qParseQuerySql(const char* pStr, size_t length, SParseCtx* pParseCtx, int32_t* type, void** pOutput, int32_t* outputLen, char* msg, int32_t msgLen); typedef enum { PAYLOAD_TYPE_KV = 0, diff --git a/source/client/inc/clientInt.h b/source/client/inc/clientInt.h index c1fd113da7..83ff0d29fb 100644 --- a/source/client/inc/clientInt.h +++ b/source/client/inc/clientInt.h @@ -148,8 +148,11 @@ int taos_init(); void* createTscObj(const char* user, const char* auth, const char *ip, uint32_t port, SAppInstInfo* pAppInfo); void destroyTscObj(void*pObj); -void* createRequest(STscObj* pObj, __taos_async_fn_t fp, void* param, int32_t type); -void destroyRequest(SRequestObj* pRequest); +void *createRequest(STscObj* pObj, __taos_async_fn_t fp, void* param, int32_t type); +void destroyRequest(SRequestObj* pRequest); + +char *getConnectionDB(STscObj* pObj); +void setConnectionDB(STscObj* pTscObj, const char* db); void taos_init_imp(void); int taos_options_imp(TSDB_OPTION option, const char *str); diff --git a/source/client/src/clientImpl.c b/source/client/src/clientImpl.c index 0acb74d4a9..0deaf5ad8e 100644 --- a/source/client/src/clientImpl.c +++ b/source/client/src/clientImpl.c @@ -151,8 +151,12 @@ TAOS_RES *taos_query_l(TAOS *taos, const char *sql, int sqlLen) { int32_t type = 0; void* output = NULL; int32_t outputLen = 0; - code = qParseQuerySql(pRequest->sqlstr, sqlLen, pRequest->requestId, &type, &output, &outputLen, pRequest->msgBuf, ERROR_MSG_BUF_DEFAULT_SIZE); - if (type == TSDB_SQL_CREATE_USER || type == TSDB_SQL_SHOW || type == TSDB_SQL_DROP_USER || type == TSDB_SQL_DROP_ACCT || type == TSDB_SQL_CREATE_DB || type == TSDB_SQL_CREATE_ACCT) { + + SParseCtx c = {.requestId = pRequest->requestId, .acctId = pTscObj->acctId, .db = getConnectionDB(pTscObj)}; + code = qParseQuerySql(pRequest->sqlstr, sqlLen, &c, &type, &output, &outputLen, pRequest->msgBuf, ERROR_MSG_BUF_DEFAULT_SIZE); + if (type == TSDB_SQL_CREATE_USER || type == TSDB_SQL_SHOW || type == TSDB_SQL_DROP_USER || + type == TSDB_SQL_DROP_ACCT || type == TSDB_SQL_CREATE_DB || type == TSDB_SQL_CREATE_ACCT || + type == TSDB_SQL_CREATE_TABLE || type == TSDB_SQL_USE_DB) { pRequest->type = type; pRequest->body.requestMsg = (SReqMsgInfo){.pMsg = output, .len = outputLen}; @@ -169,6 +173,8 @@ TAOS_RES *taos_query_l(TAOS *taos, const char *sql, int sqlLen) { } else { assert(0); } + + tfree(c.db); } if (code != TSDB_CODE_SUCCESS) { @@ -436,8 +442,19 @@ void setResultDataPtr(SReqResultInfo* pResultInfo, TAOS_FIELD* pFields, int32_t } } -const char *taos_get_client_info() { return version; } +char* getConnectionDB(STscObj* pObj) { + char *p = NULL; + pthread_mutex_lock(&pObj->mutex); + p = strndup(pObj->db, tListLen(pObj->db)); + pthread_mutex_unlock(&pObj->mutex); -int taos_affected_rows(TAOS_RES *res) { return 1; } + return p; +} + +void setConnectionDB(STscObj* pTscObj, const char* db) { + assert(db != NULL && pTscObj != NULL); + pthread_mutex_lock(&pTscObj->mutex); + tstrncpy(pTscObj->db, db, tListLen(pTscObj->db)); + pthread_mutex_unlock(&pTscObj->mutex); +} -int taos_result_precision(TAOS_RES *res) { return TSDB_TIME_PRECISION_MILLI; } diff --git a/source/client/src/clientMain.c b/source/client/src/clientMain.c index dce04a869b..f50765d37a 100644 --- a/source/client/src/clientMain.c +++ b/source/client/src/clientMain.c @@ -255,3 +255,9 @@ const char *taos_data_type(int type) { default: return "UNKNOWN"; } } + +const char *taos_get_client_info() { return version; } + +int taos_affected_rows(TAOS_RES *res) { return 1; } + +int taos_result_precision(TAOS_RES *res) { return TSDB_TIME_PRECISION_MILLI; } diff --git a/source/client/src/clientMsgHandler.c b/source/client/src/clientMsgHandler.c index e70dcc63b3..074841c175 100644 --- a/source/client/src/clientMsgHandler.c +++ b/source/client/src/clientMsgHandler.c @@ -2891,7 +2891,14 @@ int32_t doBuildMsgSupp(SRequestObj *pRequest, SRequestMsgBody* pMsgBody) { } tNameGetFullDbName(&name, pCreateMsg->db); - + break; + } + case TSDB_SQL_USE_DB: { + pMsgBody->msgType = TSDB_MSG_TYPE_USE_DB; + break; + } + case TSDB_SQL_CREATE_TABLE: { + pMsgBody->msgType = TSDB_MSG_TYPE_CREATE_STB; break; } case TSDB_SQL_SHOW: @@ -2973,6 +2980,20 @@ int32_t processCreateDbRsp(SRequestObj *pRequest, const char* pMsg, int32_t msgL // todo rsp with the vnode id list } +int32_t processUseDbRsp(SRequestObj *pRequest, const char* pMsg, int32_t msgLen) { + SUseDbRsp* pUseDbRsp = (SUseDbRsp*) pMsg; + SName name = {0}; + tNameFromString(&name, pUseDbRsp->db, T_NAME_ACCT|T_NAME_DB); + + char db[TSDB_DB_NAME_LEN] = {0}; + tNameGetDbName(&name, db); + setConnectionDB(pRequest->pTscObj, db); +} + +int32_t processCreateTableRsp(SRequestObj *pRequest, const char* pMsg, int32_t msgLen) { + assert(pMsg != NULL); +} + void initMsgHandleFp() { #if 0 tscBuildMsg[TSDB_SQL_SELECT] = tscBuildQueryMsg; @@ -3066,4 +3087,10 @@ void initMsgHandleFp() { buildRequestMsgFp[TSDB_SQL_CREATE_DB] = doBuildMsgSupp; handleRequestRspFp[TSDB_SQL_CREATE_DB] = processCreateDbRsp; + + buildRequestMsgFp[TSDB_SQL_USE_DB] = doBuildMsgSupp; + handleRequestRspFp[TSDB_SQL_USE_DB] = processUseDbRsp; + + buildRequestMsgFp[TSDB_SQL_CREATE_TABLE] = doBuildMsgSupp; + handleRequestRspFp[TSDB_SQL_CREATE_TABLE] = processCreateTableRsp; } \ No newline at end of file diff --git a/source/client/test/clientTests.cpp b/source/client/test/clientTests.cpp index 2e89bb45fa..0ef305d3b6 100644 --- a/source/client/test/clientTests.cpp +++ b/source/client/test/clientTests.cpp @@ -16,15 +16,15 @@ #include #include #include -#include "tglobal.h" #pragma GCC diagnostic ignored "-Wwrite-strings" #pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wsign-compare" -#include "../inc/clientInt.h" #include "taos.h" +#include "tglobal.h" +#include "../inc/clientInt.h" namespace { } // namespace @@ -149,11 +149,29 @@ TEST(testCase, create_db_Test) { taos_close(pConn); } -TEST(testCase, create_stable_Test) { +TEST(testCase, use_db_test) { TAOS* pConn = taos_connect("ubuntu", "root", "taosdata", NULL, 0); assert(pConn != NULL); - TAOS_RES* pRes = taos_query(pConn, "create stable st1(ts timestamp, k int) tags(a int)"); + TAOS_RES* pRes = taos_query(pConn, "use abc1"); + + TAOS_FIELD* pFields = taos_fetch_fields(pRes); + ASSERT_TRUE(pFields == NULL); + + int32_t numOfFields = taos_num_fields(pRes); + ASSERT_EQ(numOfFields, 0); + + taos_close(pConn); +} + +TEST(testCase, create_stable_Test) { + TAOS* pConn = taos_connect("ubuntu", "root", "taosdata", NULL, 0); + assert(pConn != NULL); + + TAOS_RES* pRes = taos_query(pConn, "use abc1"); + taos_free_result(pRes); + + pRes = taos_query(pConn, "create stable st1(ts timestamp, k int) tags(a int)"); TAOS_FIELD* pFields = taos_fetch_fields(pRes); ASSERT_TRUE(pFields == NULL); diff --git a/source/common/src/tname.c b/source/common/src/tname.c index fa303fe4e9..9661016483 100644 --- a/source/common/src/tname.c +++ b/source/common/src/tname.c @@ -6,21 +6,6 @@ #define VALID_NAME_TYPE(x) ((x) == TSDB_DB_NAME_T || (x) == TSDB_TABLE_NAME_T) -char* extractDBName(const char* tableId, char* name) { - size_t offset1 = strcspn(tableId, &TS_PATH_DELIMITER[0]); - size_t len = strcspn(&tableId[offset1 + 1], &TS_PATH_DELIMITER[0]); - - return strncpy(name, &tableId[offset1 + 1], len); -} - -// todo remove it -size_t tableIdPrefix(const char* name, char* prefix, int32_t len) { - tstrncpy(prefix, name, len); - strcat(prefix, TS_PATH_DELIMITER); - - return strlen(prefix); -} - bool tscValidateTableNameLength(size_t len) { return len < TSDB_TABLE_NAME_LEN; } @@ -125,7 +110,7 @@ int32_t tNameExtractFullName(const SName* name, char* dst) { return -1; } - int32_t len = snprintf(dst, TSDB_FULL_DB_NAME_LEN, "%s.%s", name->acctId, name->dbname); + int32_t len = snprintf(dst, TSDB_FULL_DB_NAME_LEN, "%d.%s", name->acctId, name->dbname); size_t tnameLen = strlen(name->tname); if (tnameLen > 0) { @@ -141,7 +126,9 @@ int32_t tNameExtractFullName(const SName* name, char* dst) { int32_t tNameLen(const SName* name) { assert(name != NULL); - int32_t len = (int32_t) strlen(name->acctId); + + char tmp[12] = {0}; + int32_t len = sprintf(tmp, "%d", name->acctId); int32_t len1 = (int32_t) strlen(name->dbname); int32_t len2 = (int32_t) strlen(name->tname); @@ -161,10 +148,6 @@ bool tNameIsValid(const SName* name) { return false; } - if (strlen(name->acctId) <= 0) { - return false; - } - if (name->type == TSDB_DB_NAME_T) { return strlen(name->dbname) > 0; } else { @@ -237,13 +220,6 @@ int32_t tNameFromString(SName* dst, const char* str, uint32_t type) { return -1; } - int32_t len = (int32_t)(p - str); - - // too long account id or too long db name -// if ((len >= tListLen(dst->acctId)) || (len <= 0)) { -// return -1; -// } -// memcpy (dst->acctId, str, len); dst->acctId = strtoll(str, NULL, 10); } @@ -272,9 +248,8 @@ int32_t tNameFromString(SName* dst, const char* str, uint32_t type) { dst->type = TSDB_TABLE_NAME_T; char* start = (char*) ((p == NULL)? str: (p+1)); - int32_t len = (int32_t) strlen(start); - // too long account id or too long db name + int32_t len = (int32_t) strlen(start); if ((len >= tListLen(dst->tname)) || (len <= 0)) { return -1; } diff --git a/source/libs/parser/inc/astToMsg.h b/source/libs/parser/inc/astToMsg.h index 1771bdc0ed..63328cb263 100644 --- a/source/libs/parser/inc/astToMsg.h +++ b/source/libs/parser/inc/astToMsg.h @@ -9,5 +9,6 @@ SCreateAcctMsg* buildAcctManipulationMsg(SSqlInfo* pInfo, int32_t* outputLen, in SDropUserMsg* buildDropUserMsg(SSqlInfo* pInfo, int32_t* outputLen, int64_t id, char* msgBuf, int32_t msgLen); SShowMsg* buildShowMsg(SShowInfo* pShowInfo, int64_t id, char* msgBuf, int32_t msgLen); SCreateDbMsg* buildCreateDbMsg(SCreateDbInfo* pCreateDbInfo, char* msgBuf, int32_t msgLen); +SCreateStbMsg* buildCreateTableMsg(SCreateTableSql* pCreateTableSql, int32_t* len, SParseCtx* pParseCtx, SMsgBuf* pMsgBuf); #endif // TDENGINE_ASTTOMSG_H diff --git a/source/libs/parser/inc/parserInt.h b/source/libs/parser/inc/parserInt.h index 4f506e631f..bf9e53e8d4 100644 --- a/source/libs/parser/inc/parserInt.h +++ b/source/libs/parser/inc/parserInt.h @@ -38,6 +38,14 @@ typedef struct SMsgBuf { char *buf; } SMsgBuf; +// create table operation type +enum TSQL_CREATE_TABLE_TYPE { + TSQL_CREATE_TABLE = 0x1, + TSQL_CREATE_STABLE = 0x2, + TSQL_CREATE_CTABLE = 0x3, + TSQL_CREATE_STREAM = 0x4, +}; + void clearTableMetaInfo(STableMetaInfo* pTableMetaInfo); void clearAllTableMetaInfo(SQueryStmtInfo* pQueryInfo, bool removeMeta, uint64_t id); @@ -60,7 +68,7 @@ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pSqlInfo, SQ * @param type * @return */ -int32_t qParserValidateDclSqlNode(SSqlInfo* pInfo, int64_t id, void** output, int32_t* outputLen, int32_t* type, char* msgBuf, int32_t msgBufLen); +int32_t qParserValidateDclSqlNode(SSqlInfo* pInfo, SParseCtx* pCtx, void** output, int32_t* outputLen, int32_t* type, char* msgBuf, int32_t msgBufLen); /** * Evaluate the numeric and timestamp arithmetic expression in the WHERE clause. diff --git a/source/libs/parser/inc/parserUtil.h b/source/libs/parser/inc/parserUtil.h index ad43b9876a..3d8729e72d 100644 --- a/source/libs/parser/inc/parserUtil.h +++ b/source/libs/parser/inc/parserUtil.h @@ -68,6 +68,7 @@ STableMeta* tableMetaDup(const STableMeta* pTableMeta); bool isDclSqlStatement(SSqlInfo* pSqlInfo); bool isDdlSqlStatement(SSqlInfo* pSqlInfo); +bool isDqlSqlStatement(SSqlInfo* pSqlInfo); #ifdef __cplusplus } diff --git a/source/libs/parser/src/astGenerator.c b/source/libs/parser/src/astGenerator.c index dda30c56fc..b6a6b73ccc 100644 --- a/source/libs/parser/src/astGenerator.c +++ b/source/libs/parser/src/astGenerator.c @@ -13,9 +13,10 @@ * along with this program. If not, see . */ -#include "taos.h" -#include "os.h" #include "astGenerator.h" +#include +#include "os.h" +#include "taos.h" #include "tmsgtype.h" SArray *tListItemAppend(SArray *pList, SVariant *pVar, uint8_t sortOrder) { diff --git a/source/libs/parser/src/astToMsg.c b/source/libs/parser/src/astToMsg.c index c41ba97e39..780ff8b0e8 100644 --- a/source/libs/parser/src/astToMsg.c +++ b/source/libs/parser/src/astToMsg.c @@ -1,3 +1,4 @@ +#include #include "parserInt.h" #include "parserUtil.h" @@ -219,3 +220,126 @@ SCreateDbMsg* buildCreateDbMsg(SCreateDbInfo* pCreateDbInfo, char* msgBuf, int32 return pCreateMsg; } + +int32_t createSName(SName* pName, SToken* pTableName, SParseCtx* pParseCtx, SMsgBuf* pMsgBuf) { + const char* msg1 = "name too long"; + const char* msg2 = "acctId too long"; + + int32_t code = TSDB_CODE_SUCCESS; + char* p = strnchr(pTableName->z, TS_PATH_DELIMITER[0], pTableName->n, false); + + if (p != NULL) { // db has been specified in sql string so we ignore current db path + code = tNameSetAcctId(pName, pParseCtx->acctId); + if (code != 0) { + return buildInvalidOperationMsg(pMsgBuf, msg2); + } + + char name[TSDB_TABLE_FNAME_LEN] = {0}; + strncpy(name, pTableName->z, pTableName->n); + + code = tNameFromString(pName, name, T_NAME_DB|T_NAME_TABLE); + if (code != 0) { + return buildInvalidOperationMsg(pMsgBuf, msg1); + } + } else { // get current DB name first, and then set it into path + if (pTableName->n >= TSDB_TABLE_NAME_LEN) { + return buildInvalidOperationMsg(pMsgBuf, msg1); + } + + tNameSetDbName(pName, pParseCtx->acctId, pParseCtx->db, strlen(pParseCtx->db)); + + char name[TSDB_TABLE_FNAME_LEN] = {0}; + strncpy(name, pTableName->z, pTableName->n); + + code = tNameFromString(pName, name, T_NAME_TABLE); + if (code != 0) { + code = buildInvalidOperationMsg(pMsgBuf, msg1); + } + } + + return code; +} + +SCreateStbMsg* buildCreateTableMsg(SCreateTableSql* pCreateTableSql, int32_t* len, SParseCtx* pParseCtx, SMsgBuf* pMsgBuf) { + SSchema* pSchema; + + int32_t numOfCols = (int32_t) taosArrayGetSize(pCreateTableSql->colInfo.pColumns); + int32_t numOfTags = (int32_t) taosArrayGetSize(pCreateTableSql->colInfo.pTagColumns); + + SCreateStbMsg* pCreateTableMsg = (SCreateStbMsg*)calloc(1, sizeof(SCreateStbMsg) + (numOfCols + numOfTags) * sizeof(SSchema)); + + char* pMsg = NULL; + int8_t type = pCreateTableSql->type; + if (type == TSQL_CREATE_TABLE) { // create by using super table, tags value +#if 0 + SArray* list = pInfo->pCreateTableInfo->childTableInfo; + + int32_t numOfTables = (int32_t)taosArrayGetSize(list); + pCreateTableMsg->numOfTables = htonl(numOfTables); + + pMsg = (char*)pCreateMsg; + for (int32_t i = 0; i < numOfTables; ++i) { + SCreateTableMsg* pCreate = (SCreateTableMsg*)pMsg; + + pCreate->numOfColumns = htons(pCmd->numOfCols); + pCreate->numOfTags = htons(pCmd->count); + pMsg += sizeof(SCreateTableMsg); + + SCreatedTableInfo* p = taosArrayGet(list, i); + strcpy(pCreate->tableName, p->fullname); + pCreate->igExists = (p->igExist) ? 1 : 0; + + // use dbinfo from table id without modifying current db info + pMsg = serializeTagData(&p->tagdata, pMsg); + + int32_t len = (int32_t)(pMsg - (char*)pCreate); + pCreate->len = htonl(len); + } +#endif + } else { // create (super) table + SName n = {0}; + int32_t code = createSName(&n, &pCreateTableSql->name, pParseCtx, pMsgBuf); + if (code != 0) { + return NULL; + } + + code = tNameExtractFullName(&n, pCreateTableMsg->name); + if (code != 0) { + buildInvalidOperationMsg(pMsgBuf, "invalid table name or database not specified"); + return NULL; + } + + pCreateTableMsg->igExists = pCreateTableSql->existCheck ? 1 : 0; + + pCreateTableMsg->numOfColumns = htonl(numOfCols); + pCreateTableMsg->numOfTags = htonl(numOfTags); + + pSchema = (SSchema*) pCreateTableMsg->pSchema; + for (int i = 0; i < numOfCols; ++i) { + TAOS_FIELD* pField = taosArrayGet(pCreateTableSql->colInfo.pColumns, i); + + pSchema->type = pField->type; + pSchema->bytes = htonl(pField->bytes); + strcpy(pSchema->name, pField->name); + + pSchema++; + } + + for(int32_t i = 0; i < numOfTags; ++i) { + TAOS_FIELD* pField = taosArrayGet(pCreateTableSql->colInfo.pTagColumns, i); + + pSchema->type = pField->type; + pSchema->bytes = htonl(pField->bytes); + strcpy(pSchema->name, pField->name); + + pSchema++; + } + + pMsg = (char*)pSchema; + } + + int32_t msgLen = (int32_t)(pMsg - (char*)pCreateTableMsg); + *len = msgLen; + + return pCreateTableMsg; +} diff --git a/source/libs/parser/src/astValidate.c b/source/libs/parser/src/astValidate.c index accc786bf6..3b9a33af02 100644 --- a/source/libs/parser/src/astValidate.c +++ b/source/libs/parser/src/astValidate.c @@ -4171,7 +4171,144 @@ static int32_t doCheckDbOptions(SCreateDbMsg* pCreate, SMsgBuf* pMsgBuf) { return TSDB_CODE_SUCCESS; } -int32_t qParserValidateDclSqlNode(SSqlInfo* pInfo, int64_t id, void** output, int32_t* outputLen, int32_t* type, char* msgBuf, int32_t msgBufLen) { +/* is contained in pFieldList or not */ +static bool has(SArray* pFieldList, int32_t startIndex, const char* name) { + size_t numOfCols = taosArrayGetSize(pFieldList); + for (int32_t j = startIndex; j < numOfCols; ++j) { + TAOS_FIELD* field = taosArrayGet(pFieldList, j); + if (strncasecmp(name, field->name, sizeof(field->name) - 1) == 0) return true; + } + + return false; +} + +static int32_t validateTableColumns(SArray* pFieldList, int32_t maxRowLength, int32_t maxColumns, SMsgBuf* pMsgBuf) { + const char* msg2 = "row length exceeds max length"; + const char* msg3 = "duplicated column names"; + const char* msg4 = "invalid data type"; + const char* msg5 = "invalid binary/nchar column length"; + const char* msg6 = "invalid column name"; + const char* msg7 = "too many columns"; + const char* msg8 = "illegal number of columns"; + + size_t numOfCols = taosArrayGetSize(pFieldList); + if (numOfCols > maxColumns) { + return buildInvalidOperationMsg(pMsgBuf, msg7); + } + + int32_t rowLen = 0; + for (int32_t i = 0; i < numOfCols; ++i) { + TAOS_FIELD* pField = taosArrayGet(pFieldList, i); + if (!isValidDataType(pField->type)) { + return buildInvalidOperationMsg(pMsgBuf, msg4); + } + + if (pField->bytes == 0) { + return buildInvalidOperationMsg(pMsgBuf, msg5); + } + + if ((pField->type == TSDB_DATA_TYPE_BINARY && (pField->bytes <= 0 || pField->bytes > TSDB_MAX_BINARY_LEN)) || + (pField->type == TSDB_DATA_TYPE_NCHAR && (pField->bytes <= 0 || pField->bytes > TSDB_MAX_NCHAR_LEN))) { + return buildInvalidOperationMsg(pMsgBuf, msg5); + } + + SToken nameToken = {.z = pField->name, .n = strlen(pField->name), .type = TK_ID}; + if (parserValidateNameToken(&nameToken) != TSDB_CODE_SUCCESS) { + return buildInvalidOperationMsg(pMsgBuf, msg6); + } + + // field name must be unique + if (has(pFieldList, i + 1, pField->name) == true) { + return buildInvalidOperationMsg(pMsgBuf, msg3); + } + + rowLen += pField->bytes; + } + + // max row length must be less than TSDB_MAX_BYTES_PER_ROW + if (rowLen > maxRowLength) { + return buildInvalidOperationMsg(pMsgBuf, msg2); + } + + return TSDB_CODE_SUCCESS; +} + +static int32_t validateTableColumnInfo(SArray* pFieldList, SMsgBuf* pMsgBuf) { + assert(pFieldList != NULL); + + const char* msg1 = "first column must be timestamp"; + const char* msg2 = "row length exceeds max length"; + const char* msg3 = "duplicated column names"; + const char* msg4 = "invalid data type"; + const char* msg5 = "invalid binary/nchar column length"; + const char* msg6 = "invalid column name"; + const char* msg7 = "too many columns"; + const char* msg8 = "illegal number of columns"; + + // first column must be timestamp + TAOS_FIELD* pField = taosArrayGet(pFieldList, 0); + if (pField->type != TSDB_DATA_TYPE_TIMESTAMP) { + return buildInvalidOperationMsg(pMsgBuf, msg1); + } + + // number of fields no less than 2 + size_t numOfCols = taosArrayGetSize(pFieldList); + if (numOfCols <= 1) { + return buildInvalidOperationMsg(pMsgBuf, msg8); + } + + return validateTableColumns(pFieldList, TSDB_MAX_BYTES_PER_ROW, TSDB_MAX_COLUMNS, pMsgBuf); +} + +static int32_t validateTagParams(SArray* pTagsList, SArray* pFieldList, SMsgBuf* pMsgBuf) { + assert(pTagsList != NULL); + + const char* msg1 = "invalid number of tag columns"; + const char* msg3 = "duplicated column names"; + + // number of fields at least 1 + size_t numOfTags = taosArrayGetSize(pTagsList); + if (numOfTags < 1) { + return buildInvalidOperationMsg(pMsgBuf, msg1); + } + + // field name must be unique + for (int32_t i = 0; i < numOfTags; ++i) { + TAOS_FIELD* p = taosArrayGet(pTagsList, i); + if (has(pFieldList, 0, p->name) == true) { + return buildInvalidOperationMsg(pMsgBuf, msg3); + } + } + + return validateTableColumns(pFieldList, TSDB_MAX_TAGS_LEN, TSDB_MAX_TAGS, pMsgBuf); +} + +int32_t doCheckForCreateTable(SSqlInfo* pInfo, SMsgBuf* pMsgBuf) { + const char* msg1 = "invalid table name"; + + SCreateTableSql* pCreateTable = pInfo->pCreateTableInfo; + + SArray* pFieldList = pCreateTable->colInfo.pColumns; + SArray* pTagList = pCreateTable->colInfo.pTagColumns; + assert(pFieldList != NULL); + + // if sql specifies db, use it, otherwise use default db + SToken* pzTableName = &(pCreateTable->name); + + bool dbIncluded = false; + if (parserValidateNameToken(pzTableName) != TSDB_CODE_SUCCESS) { + return buildInvalidOperationMsg(pMsgBuf, msg1); + } + + if (validateTableColumnInfo(pFieldList, pMsgBuf) != TSDB_CODE_SUCCESS || + (pTagList != NULL && validateTagParams(pTagList, pFieldList, pMsgBuf) != TSDB_CODE_SUCCESS)) { + return TSDB_CODE_TSC_INVALID_OPERATION; + } + + return TSDB_CODE_SUCCESS; +} + +int32_t qParserValidateDclSqlNode(SSqlInfo* pInfo, SParseCtx* pCtx, void** output, int32_t* outputLen, int32_t* type, char* msgBuf, int32_t msgBufLen) { int32_t code = 0; SMsgBuf m = {.buf = msgBuf, .len = msgBufLen}; @@ -4224,7 +4361,7 @@ int32_t qParserValidateDclSqlNode(SSqlInfo* pInfo, int64_t id, void** output, in } } - *output = buildUserManipulationMsg(pInfo, outputLen, id, msgBuf, msgBufLen); + *output = buildUserManipulationMsg(pInfo, outputLen, pCtx->requestId, msgBuf, msgBufLen); break; } @@ -4260,13 +4397,13 @@ int32_t qParserValidateDclSqlNode(SSqlInfo* pInfo, int64_t id, void** output, in } } - *output = buildAcctManipulationMsg(pInfo, outputLen, id, msgBuf, msgBufLen); + *output = buildAcctManipulationMsg(pInfo, outputLen, pCtx->requestId, msgBuf, msgBufLen); break; } case TSDB_SQL_DROP_ACCT: case TSDB_SQL_DROP_USER: { - *output = buildDropUserMsg(pInfo, outputLen, id, msgBuf, msgBufLen); + *output = buildDropUserMsg(pInfo, outputLen, pCtx->requestId, msgBuf, msgBufLen); break; } @@ -4275,6 +4412,28 @@ int32_t qParserValidateDclSqlNode(SSqlInfo* pInfo, int64_t id, void** output, in break; } + case TSDB_SQL_USE_DB: { + const char* msg = "invalid db name"; + + SToken* pToken = taosArrayGet(pInfo->pMiscInfo->a, 0); + if (parserValidateNameToken(pToken) != TSDB_CODE_SUCCESS) { + return buildInvalidOperationMsg(pMsgBuf, msg); + } + + SName n = {0}; + int32_t ret = tNameSetDbName(&n, pCtx->acctId, pToken->z, pToken->n); + if (ret != TSDB_CODE_SUCCESS) { + return buildInvalidOperationMsg(pMsgBuf, msg); + } + + SUseDbMsg *pUseDbMsg = (SUseDbMsg *) calloc(1, sizeof(SUseDbMsg)); + tNameExtractFullName(&n, pUseDbMsg->db); + + *output = pUseDbMsg; + *outputLen = sizeof(SUseDbMsg); + break; + } + case TSDB_SQL_ALTER_DB: case TSDB_SQL_CREATE_DB: { const char* msg1 = "invalid db name"; @@ -4304,6 +4463,26 @@ int32_t qParserValidateDclSqlNode(SSqlInfo* pInfo, int64_t id, void** output, in break; } + case TSDB_SQL_CREATE_TABLE: { + SCreateTableSql* pCreateTable = pInfo->pCreateTableInfo; + + if (pCreateTable->type == TSQL_CREATE_TABLE || pCreateTable->type == TSQL_CREATE_STABLE) { + if ((code = doCheckForCreateTable(pInfo, pMsgBuf)) != TSDB_CODE_SUCCESS) { + return code; + } + *output = buildCreateTableMsg(pCreateTable, outputLen, pCtx, pMsgBuf); + } else if (pCreateTable->type == TSQL_CREATE_CTABLE) { + // if ((code = doCheckForCreateFromStable(pSql, pInfo)) != TSDB_CODE_SUCCESS) { + // return code; + // } + + } else if (pCreateTable->type == TSQL_CREATE_STREAM) { + // if ((code = doCheckForStream(pSql, pInfo)) != TSDB_CODE_SUCCESS) { + // return code; + } + + break; + } default: break; } diff --git a/source/libs/parser/src/parser.c b/source/libs/parser/src/parser.c index e0ac7c295b..1e61be15dd 100644 --- a/source/libs/parser/src/parser.c +++ b/source/libs/parser/src/parser.c @@ -31,7 +31,7 @@ bool qIsInsertSql(const char* pStr, size_t length) { } while (1); } -int32_t qParseQuerySql(const char* pStr, size_t length, int64_t id, int32_t *type, void** pOutput, int32_t* outputLen, char* msg, int32_t msgLen) { +int32_t qParseQuerySql(const char* pStr, size_t length, SParseCtx* pParseCtx, int32_t *type, void** pOutput, int32_t* outputLen, char* msg, int32_t msgLen) { SSqlInfo info = doGenerateAST(pStr); if (!info.valid) { strncpy(msg, info.msg, msgLen); @@ -39,8 +39,8 @@ int32_t qParseQuerySql(const char* pStr, size_t length, int64_t id, int32_t *typ return terrno; } - if (isDclSqlStatement(&info)) { - int32_t code = qParserValidateDclSqlNode(&info, id, pOutput, outputLen, type, msg, msgLen); + if (!isDqlSqlStatement(&info)) { + int32_t code = qParserValidateDclSqlNode(&info, pParseCtx, pOutput, outputLen, type, msg, msgLen); if (code == TSDB_CODE_SUCCESS) { // do nothing } @@ -53,7 +53,7 @@ int32_t qParseQuerySql(const char* pStr, size_t length, int64_t id, int32_t *typ struct SCatalog* pCatalog = NULL; int32_t code = catalogGetHandle(NULL, &pCatalog); - code = qParserValidateSqlNode(pCatalog, &info, pQueryInfo, id, msg, msgLen); + code = qParserValidateSqlNode(pCatalog, &info, pQueryInfo, pParseCtx->requestId, msg, msgLen); if (code == TSDB_CODE_SUCCESS) { *pOutput = pQueryInfo; } diff --git a/source/libs/parser/src/parserUtil.c b/source/libs/parser/src/parserUtil.c index 13434da057..3abdaa1036 100644 --- a/source/libs/parser/src/parserUtil.c +++ b/source/libs/parser/src/parserUtil.c @@ -1620,7 +1620,11 @@ bool isDclSqlStatement(SSqlInfo* pSqlInfo) { bool isDdlSqlStatement(SSqlInfo* pSqlInfo) { int32_t type = pSqlInfo->type; - return (type == TSDB_SQL_CREATE_TABLE || type == TSDB_SQL_CREATE_DB); + return (type == TSDB_SQL_CREATE_TABLE || type == TSDB_SQL_CREATE_DB || type == TSDB_SQL_DROP_DB); +} + +bool isDqlSqlStatement(SSqlInfo* pSqlInfo) { + return pSqlInfo->type == TSDB_SQL_SELECT; } #if 0 diff --git a/source/libs/parser/src/sql.c b/source/libs/parser/src/sql.c index d674462fc0..9922ff1be0 100644 --- a/source/libs/parser/src/sql.c +++ b/source/libs/parser/src/sql.c @@ -31,6 +31,7 @@ #include #include #include "astGenerator.h" +#include "parserInt.h" #include "tmsgtype.h" #include "ttoken.h" #include "ttokendef.h" diff --git a/source/libs/parser/test/parserTests.cpp b/source/libs/parser/test/parserTests.cpp index 396e8a12fe..7e289d5158 100644 --- a/source/libs/parser/test/parserTests.cpp +++ b/source/libs/parser/test/parserTests.cpp @@ -717,7 +717,9 @@ TEST(testCase, show_user_Test) { void* output = NULL; int32_t type = 0; int32_t len = 0; - int32_t code = qParserValidateDclSqlNode(&info1, 1, &output, &len, &type, msg, buf.len); + + SParseCtx ct= {.db= "abc", .acctId = 1, .requestId = 1}; + int32_t code = qParserValidateDclSqlNode(&info1, &ct, &output, &len, &type, msg, buf.len); ASSERT_EQ(code, 0); // convert the show command to be the select query @@ -734,13 +736,14 @@ TEST(testCase, create_user_Test) { SSqlInfo info1 = doGenerateAST(sql); ASSERT_EQ(info1.valid, true); - ASSERT_EQ(isDclSqlStatement(&info1), true); void* output = NULL; int32_t type = 0; int32_t len = 0; - int32_t code = qParserValidateDclSqlNode(&info1, 1, &output, &len, &type, msg, buf.len); + + SParseCtx ct= {.db= "abc", .acctId = 1, .requestId = 1}; + int32_t code = qParserValidateDclSqlNode(&info1, &ct, &output, &len, &type, msg, buf.len); ASSERT_EQ(code, 0); destroySqlInfo(&info1);