diff --git a/docs/en/08-operation/14-user.md b/docs/en/08-operation/14-user.md index 95c00bd21f..3165f6ad32 100644 --- a/docs/en/08-operation/14-user.md +++ b/docs/en/08-operation/14-user.md @@ -12,7 +12,7 @@ TDengine is configured by default with only one root user, who has the highest p Only the root user can perform the operation of creating users, with the syntax as follows. ```sql -create user user_name pass'password' [sysinfo {1|0}] +create user user_name pass'password' [sysinfo {1|0}] [createdb {1|0}] ``` The parameters are explained as follows. @@ -20,6 +20,7 @@ The parameters are explained as follows. - user_name: Up to 23 B long. - password: Up to 128 B long, valid characters include letters and numbers as well as special characters other than single and double quotes, apostrophes, backslashes, and spaces, and it cannot be empty. - sysinfo: Whether the user can view system information. 1 means they can view it, 0 means they cannot. System information includes server configuration information, various node information such as dnode, query node (qnode), etc., as well as storage-related information, etc. The default is to view system information. +- createdb: Whether the user can create databases. 1 means they can create databases, 0 means they cannot. The default value is 0. // Supported starting from TDengine Enterprise version 3.3.2.0 The following SQL can create a user named test with the password 123456 who can view system information. @@ -51,6 +52,7 @@ alter_user_clause: { pass 'literal' | enable value | sysinfo value + | createdb value } ``` @@ -59,6 +61,7 @@ The parameters are explained as follows. - pass: Modify the user's password. - enable: Whether to enable the user. 1 means to enable this user, 0 means to disable this user. - sysinfo: Whether the user can view system information. 1 means they can view system information, 0 means they cannot. +- createdb: Whether the user can create databases. 1 means they can create databases, 0 means they cannot. // Supported starting from TDengine Enterprise version 3.3.2.0 The following SQL disables the user test. diff --git a/docs/en/14-reference/03-taos-sql/25-user.md b/docs/en/14-reference/03-taos-sql/25-user.md index 6eebf9513e..780fd92040 100644 --- a/docs/en/14-reference/03-taos-sql/25-user.md +++ b/docs/en/14-reference/03-taos-sql/25-user.md @@ -8,7 +8,7 @@ User and permission management is a feature of TDengine Enterprise Edition. This ## Create User ```sql -CREATE USER user_name PASS 'password' [SYSINFO {1|0}]; +CREATE USER user_name PASS 'password' [SYSINFO {1|0}] [CREATEDB {1|0}]; ``` The username can be up to 23 bytes long. @@ -17,6 +17,8 @@ The password can be up to 31 bytes long. The password can include letters, numbe `SYSINFO` indicates whether the user can view system information. `1` means they can view, `0` means they have no permission to view. System information includes service configuration, dnode, vnode, storage, etc. The default value is `1`. +`CREATEDB` indicates whether the user can create databases. `1` means they can create databases, `0` means they have no permission to create databases. The default value is `0`. // Supported starting from TDengine Enterprise version 3.3.2.0 + In the example below, we create a user with the password `123456` who can view system information. ```sql @@ -76,7 +78,7 @@ alter_user_clause: { - PASS: Change the password, followed by the new password - ENABLE: Enable or disable the user, `1` means enable, `0` means disable - SYSINFO: Allow or prohibit viewing system information, `1` means allow, `0` means prohibit -- CREATEDB: Allow or prohibit creating databases, `1` means allow, `0` means prohibit +- CREATEDB: Allow or prohibit creating databases, `1` means allow, `0` means prohibit. // Supported starting from TDengine Enterprise version 3.3.2.0 The following example disables the user named `test`: diff --git a/docs/zh/08-operation/14-user.md b/docs/zh/08-operation/14-user.md index 03a838462f..dd8f94892c 100644 --- a/docs/zh/08-operation/14-user.md +++ b/docs/zh/08-operation/14-user.md @@ -12,13 +12,14 @@ TDengine 默认仅配置了一个 root 用户,该用户拥有最高权限。TD 创建用户的操作只能由 root 用户进行,语法如下。 ```sql -create user user_name pass'password' [sysinfo {1|0}] +create user user_name pass'password' [sysinfo {1|0}] [createdb {1|0}] ``` 相关参数说明如下。 - user_name:最长为 23 B。 - password:最长为 128 B,合法字符包括字母和数字以及单双引号、撇号、反斜杠和空格以外的特殊字符,且不可以为空。 - sysinfo :用户是否可以查看系统信息。1 表示可以查看,0 表示不可以查看。系统信息包括服务端配置信息、服务端各种节点信息,如 dnode、查询节点(qnode)等,以及与存储相关的信息等。默认为可以查看系统信息。 +- createdb:用户是否可以创建数据库。1 表示可以创建,0 表示不可以创建。缺省值为 0。// 从 TDengine 企业版 3.3.2.0 开始支持 如下 SQL 可以创建密码为 123456 且可以查看系统信息的用户 test。 @@ -47,6 +48,7 @@ alter_user_clause: { pass 'literal' | enable value | sysinfo value + | createdb value } ``` @@ -54,6 +56,7 @@ alter_user_clause: { - pass:修改用户密码。 - enable:是否启用用户。1 表示启用此用户,0 表示禁用此用户。 - sysinfo :用户是否可查看系统信息。1 表示可以查看系统信息,0 表示不可以查看系统信息 +- createdb:用户是否可创建数据库。1 表示可以创建数据库,0 表示不可以创建数据库。// 从 TDengine 企业版 3.3.2.0 开始支持 如下 SQL 禁用 test 用户。 ```sql diff --git a/docs/zh/14-reference/03-taos-sql/25-user.md b/docs/zh/14-reference/03-taos-sql/25-user.md index a77a5d6a67..bb99bc94a2 100644 --- a/docs/zh/14-reference/03-taos-sql/25-user.md +++ b/docs/zh/14-reference/03-taos-sql/25-user.md @@ -9,7 +9,7 @@ description: 本节讲述基本的用户管理功能 ## 创建用户 ```sql -CREATE USER user_name PASS 'password' [SYSINFO {1|0}]; +CREATE USER user_name PASS 'password' [SYSINFO {1|0}] [CREATEDB {1|0}]; ``` 用户名最长不超过 23 个字节。 @@ -18,6 +18,8 @@ CREATE USER user_name PASS 'password' [SYSINFO {1|0}]; `SYSINFO` 表示该用户是否能够查看系统信息。`1` 表示可以查看,`0` 表示无权查看。系统信息包括服务配置、dnode、vnode、存储等信息。缺省值为 `1`。 +`CREATEDB` 表示该用户是否能够创建数据库。`1` 表示可以创建,`0` 表示无权创建。缺省值为 `0`。// 从 TDengine 企业版 3.3.2.0 开始支持 + 在下面的示例中,我们创建一个密码为 `123456` 且可以查看系统信息的用户。 ```sql @@ -77,7 +79,7 @@ alter_user_clause: { - PASS: 修改密码,后跟新密码 - ENABLE: 启用或禁用该用户,`1` 表示启用,`0` 表示禁用 - SYSINFO: 允许或禁止查看系统信息,`1` 表示允许,`0` 表示禁止 -- CREATEDB: 允许或禁止创建数据库,`1` 表示允许,`0` 表示禁止 +- CREATEDB: 允许或禁止创建数据库,`1` 表示允许,`0` 表示禁止。// 从 TDengine 企业版 3.3.2.0 开始支持 下面的示例禁用了名为 `test` 的用户: diff --git a/include/libs/qcom/query.h b/include/libs/qcom/query.h index d2f714f400..d62edb158d 100644 --- a/include/libs/qcom/query.h +++ b/include/libs/qcom/query.h @@ -194,6 +194,7 @@ typedef struct SBoundColInfo { int32_t numOfCols; int32_t numOfBound; bool hasBoundCols; + bool mixTagsCols; } SBoundColInfo; typedef struct STableColsData { diff --git a/source/client/src/clientStmt2.c b/source/client/src/clientStmt2.c index 2eedab2289..be883ba9f0 100644 --- a/source/client/src/clientStmt2.c +++ b/source/client/src/clientStmt2.c @@ -1094,6 +1094,13 @@ static int stmtFetchStbColFields2(STscStmt2* pStmt, int32_t* fieldNum, TAOS_FIEL } STMT_ERR_RET(qBuildStmtStbColFields(*pDataBlock, pStmt->bInfo.boundTags, pStmt->bInfo.preCtbname, fieldNum, fields)); + if (pStmt->bInfo.tbType == TSDB_SUPER_TABLE) { + pStmt->bInfo.needParse = true; + if (taosHashRemove(pStmt->exec.pBlockHash, pStmt->bInfo.tbFName, strlen(pStmt->bInfo.tbFName)) != 0) { + tscError("get fileds %s remove exec blockHash fail", pStmt->bInfo.tbFName); + STMT_ERR_RET(TSDB_CODE_APP_ERROR); + } + } return TSDB_CODE_SUCCESS; } diff --git a/source/dnode/mnode/impl/src/mndTrans.c b/source/dnode/mnode/impl/src/mndTrans.c index e51500bf34..4bc538531b 100644 --- a/source/dnode/mnode/impl/src/mndTrans.c +++ b/source/dnode/mnode/impl/src/mndTrans.c @@ -14,13 +14,13 @@ */ #define _DEFAULT_SOURCE -#include "mndTrans.h" #include "mndDb.h" #include "mndPrivilege.h" #include "mndShow.h" #include "mndStb.h" #include "mndSubscribe.h" #include "mndSync.h" +#include "mndTrans.h" #include "mndUser.h" #define TRANS_VER1_NUMBER 1 @@ -216,7 +216,7 @@ SSdbRaw *mndTransEncode(STrans *pTrans) { SDB_SET_RESERVE(pRaw, dataPos, TRANS_RESERVE_SIZE, _OVER) SDB_SET_DATALEN(pRaw, dataPos, _OVER) - terrno = 0; + terrno = 0; _OVER: if (terrno != 0) { @@ -287,8 +287,8 @@ _OVER: SSdbRow *mndTransDecode(SSdbRaw *pRaw) { terrno = TSDB_CODE_INVALID_MSG; - int32_t code = 0; - int32_t lino = 0; + int32_t code = 0; + int32_t lino = 0; SSdbRow *pRow = NULL; STrans *pTrans = NULL; char *pData = NULL; @@ -890,7 +890,7 @@ static bool mndCheckTransConflict(SMnode *pMnode, STrans *pNew) { if (pNew->conflict == TRN_CONFLICT_ARBGROUP) { if (pTrans->conflict == TRN_CONFLICT_GLOBAL) conflict = true; if (pTrans->conflict == TRN_CONFLICT_ARBGROUP) { - void* pGidIter = taosHashIterate(pNew->arbGroupIds, NULL); + void *pGidIter = taosHashIterate(pNew->arbGroupIds, NULL); while (pGidIter != NULL) { int32_t groupId = *(int32_t *)pGidIter; if (taosHashGet(pTrans->arbGroupIds, &groupId, sizeof(int32_t)) != NULL) { @@ -1033,7 +1033,7 @@ static int32_t mndTransCheckCommitActions(SMnode *pMnode, STrans *pTrans) { int32_t mndTransPrepare(SMnode *pMnode, STrans *pTrans) { int32_t code = 0; if (pTrans == NULL) { - return TSDB_CODE_INVALID_PARA; + return TSDB_CODE_INVALID_PARA; } TAOS_CHECK_RETURN(mndTransCheckConflict(pMnode, pTrans)); @@ -1305,6 +1305,14 @@ static int32_t mndTransWriteSingleLog(SMnode *pMnode, STrans *pTrans, STransActi TAOS_RETURN(TSDB_CODE_MND_TRANS_CTX_SWITCH); } + if (pAction->pRaw->type >= SDB_MAX) { + pAction->rawWritten = true; + pAction->errCode = 0; + mndSetTransLastAction(pTrans, pAction); + mInfo("skip sdb raw type:%d since it is not supported", pAction->pRaw->type); + TAOS_RETURN(TSDB_CODE_SUCCESS); + } + int32_t code = sdbWriteWithoutFree(pMnode->pSdb, pAction->pRaw); if (code == 0 || terrno == TSDB_CODE_SDB_OBJ_NOT_THERE) { pAction->rawWritten = true; @@ -1348,10 +1356,10 @@ static int32_t mndTransSendSingleMsg(SMnode *pMnode, STrans *pTrans, STransActio char detail[1024] = {0}; int32_t len = tsnprintf(detail, sizeof(detail), "msgType:%s numOfEps:%d inUse:%d", TMSG_INFO(pAction->msgType), - pAction->epSet.numOfEps, pAction->epSet.inUse); + pAction->epSet.numOfEps, pAction->epSet.inUse); for (int32_t i = 0; i < pAction->epSet.numOfEps; ++i) { len += tsnprintf(detail + len, sizeof(detail) - len, " ep:%d-%s:%u", i, pAction->epSet.eps[i].fqdn, - pAction->epSet.eps[i].port); + pAction->epSet.eps[i].port); } int32_t code = tmsgSendReq(&pAction->epSet, &rpcMsg); @@ -1454,9 +1462,9 @@ static int32_t mndTransExecuteActions(SMnode *pMnode, STrans *pTrans, SArray *pA for (int32_t action = 0; action < numOfActions; ++action) { STransAction *pAction = taosArrayGet(pArray, action); - mDebug("trans:%d, %s:%d Sent:%d, Received:%d, errCode:0x%x, acceptableCode:0x%x, retryCode:0x%x", - pTrans->id, mndTransStr(pAction->stage), pAction->id, pAction->msgSent, pAction->msgReceived, - pAction->errCode, pAction->acceptableCode, pAction->retryCode); + mDebug("trans:%d, %s:%d Sent:%d, Received:%d, errCode:0x%x, acceptableCode:0x%x, retryCode:0x%x", pTrans->id, + mndTransStr(pAction->stage), pAction->id, pAction->msgSent, pAction->msgReceived, pAction->errCode, + pAction->acceptableCode, pAction->retryCode); if (pAction->msgSent) { if (pAction->msgReceived) { if (pAction->errCode != 0 && pAction->errCode != pAction->acceptableCode) { @@ -2038,11 +2046,11 @@ static int32_t mndRetrieveTrans(SRpcMsg *pReq, SShowObj *pShow, SSDataBlock *pBl char lastInfo[TSDB_TRANS_ERROR_LEN + VARSTR_HEADER_SIZE] = {0}; char detail[TSDB_TRANS_ERROR_LEN + 1] = {0}; int32_t len = tsnprintf(detail, sizeof(detail), "action:%d code:0x%x(%s) ", pTrans->lastAction, - pTrans->lastErrorNo & 0xFFFF, tstrerror(pTrans->lastErrorNo)); + pTrans->lastErrorNo & 0xFFFF, tstrerror(pTrans->lastErrorNo)); SEpSet epset = pTrans->lastEpset; if (epset.numOfEps > 0) { len += tsnprintf(detail + len, sizeof(detail) - len, "msgType:%s numOfEps:%d inUse:%d ", - TMSG_INFO(pTrans->lastMsgType), epset.numOfEps, epset.inUse); + TMSG_INFO(pTrans->lastMsgType), epset.numOfEps, epset.inUse); for (int32_t i = 0; i < pTrans->lastEpset.numOfEps; ++i) { len += tsnprintf(detail + len, sizeof(detail) - len, "ep:%d-%s:%u ", i, epset.eps[i].fqdn, epset.eps[i].port); } diff --git a/source/dnode/mnode/sdb/src/sdbFile.c b/source/dnode/mnode/sdb/src/sdbFile.c index 474b22cca0..6122b08a0b 100644 --- a/source/dnode/mnode/sdb/src/sdbFile.c +++ b/source/dnode/mnode/sdb/src/sdbFile.c @@ -388,6 +388,11 @@ static int32_t sdbReadFileImp(SSdb *pSdb) { goto _OVER; } + if (pRaw->type >= SDB_MAX) { + mInfo("skip sdb raw type:%d since it is not supported", pRaw->type); + continue; + } + code = sdbWriteWithoutFree(pSdb, pRaw); if (code != 0) { mError("failed to read sdb file:%s since %s", file, terrstr()); diff --git a/source/libs/parser/src/parInsertSql.c b/source/libs/parser/src/parInsertSql.c index 65ee0de80e..5d34809c12 100644 --- a/source/libs/parser/src/parInsertSql.c +++ b/source/libs/parser/src/parInsertSql.c @@ -247,8 +247,8 @@ static int32_t parseBoundColumns(SInsertParseContext* pCxt, const char** pSql, E return code; } -static int32_t parseTimestampOrInterval(const char** end, SToken* pToken, int16_t timePrec, int64_t* ts, int64_t* interval, - SMsgBuf* pMsgBuf, bool* isTs) { +static int32_t parseTimestampOrInterval(const char** end, SToken* pToken, int16_t timePrec, int64_t* ts, + int64_t* interval, SMsgBuf* pMsgBuf, bool* isTs) { if (pToken->type == TK_NOW) { *isTs = true; *ts = taosGetTimestamp(timePrec); @@ -1387,7 +1387,16 @@ static int32_t getTableDataCxt(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pS } char tbFName[TSDB_TABLE_FNAME_LEN]; - int32_t code = tNameExtractFullName(&pStmt->targetTableName, tbFName); + int32_t code = 0; + if (pCxt->preCtbname) { + tstrncpy(pStmt->targetTableName.tname, pStmt->usingTableName.tname, sizeof(pStmt->targetTableName.tname)); + tstrncpy(pStmt->targetTableName.dbname, pStmt->usingTableName.dbname, sizeof(pStmt->targetTableName.dbname)); + pStmt->targetTableName.type = TSDB_SUPER_TABLE; + pStmt->pTableMeta->tableType = TSDB_SUPER_TABLE; + } + + code = tNameExtractFullName(&pStmt->targetTableName, tbFName); + if (TSDB_CODE_SUCCESS != code) { return code; } @@ -1812,8 +1821,10 @@ static int32_t doGetStbRowValues(SInsertParseContext* pCxt, SVnodeModifyOpStmt* SArray* pTagVals = pStbRowsCxt->aTagVals; bool canParseTagsAfter = !pStbRowsCxt->pTagCond && !pStbRowsCxt->hasTimestampTag; int32_t numOfCols = getNumOfColumns(pStbRowsCxt->pStbMeta); + int32_t numOfTags = getNumOfTags(pStbRowsCxt->pStbMeta); int32_t tbnameIdx = getTbnameSchemaIndex(pStbRowsCxt->pStbMeta); uint8_t precision = getTableInfo(pStbRowsCxt->pStbMeta).precision; + int idx = 0; for (int i = 0; i < pCols->numOfBound && (code) == TSDB_CODE_SUCCESS; ++i) { const char* pTmpSql = *ppSql; bool ignoreComma = false; @@ -1831,13 +1842,37 @@ static int32_t doGetStbRowValues(SInsertParseContext* pCxt, SVnodeModifyOpStmt* if (TK_NK_QUESTION == pToken->type) { pCxt->isStmtBind = true; + pStmt->usingTableProcessing = true; if (pCols->pColIndex[i] == tbnameIdx) { - pCxt->preCtbname = false; - *bFoundTbName = true; - } - if (NULL == pCxt->pComCxt->pStmtCb) { - code = buildSyntaxErrMsg(&pCxt->msg, "? only used in stmt", pToken->z); - break; + char* tbName = NULL; + if ((*pCxt->pComCxt->pStmtCb->getTbNameFn)(pCxt->pComCxt->pStmtCb->pStmt, &tbName) == TSDB_CODE_SUCCESS) { + tstrncpy(pStbRowsCxt->ctbName.tname, tbName, sizeof(pStbRowsCxt->ctbName.tname)); + tstrncpy(pStmt->usingTableName.tname, pStmt->targetTableName.tname, sizeof(pStmt->usingTableName.tname)); + tstrncpy(pStmt->targetTableName.tname, tbName, sizeof(pStmt->targetTableName.tname)); + + tstrncpy(pStmt->usingTableName.dbname, pStmt->targetTableName.dbname, sizeof(pStmt->usingTableName.dbname)); + pStmt->usingTableName.type = 1; + + *bFoundTbName = true; + } + } else if (pCols->pColIndex[i] < numOfCols) { + // bind column + } else if (pCols->pColIndex[i] < tbnameIdx) { + if (pCxt->tags.pColIndex == NULL) { + pCxt->tags.pColIndex = taosMemoryCalloc(numOfTags, sizeof(int16_t)); + if (NULL == pCxt->tags.pColIndex) { + return terrno; + } + } + if (!(idx < numOfTags)) { + return buildInvalidOperationMsg(&pCxt->msg, "not expected numOfTags"); + } + pCxt->tags.pColIndex[idx++] = pCols->pColIndex[i] - numOfCols; + pCxt->tags.mixTagsCols = true; + pCxt->tags.numOfBound++; + pCxt->tags.numOfCols++; + } else { + return buildInvalidOperationMsg(&pCxt->msg, "not expected numOfBound"); } } else { if (pCols->pColIndex[i] < numOfCols) { @@ -1882,6 +1917,7 @@ static int32_t doGetStbRowValues(SInsertParseContext* pCxt, SVnodeModifyOpStmt* } } } + return code; } @@ -1901,13 +1937,17 @@ static int32_t getStbRowValues(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pS code = doGetStbRowValues(pCxt, pStmt, ppSql, pStbRowsCxt, pToken, pCols, pSchemas, tagTokens, tagSchemas, &numOfTagTokens, &bFoundTbName); - if (code == TSDB_CODE_SUCCESS && !bFoundTbName) { - code = buildSyntaxErrMsg(&pCxt->msg, "tbname value expected", pOrigSql); + if (code != TSDB_CODE_SUCCESS) { + return code; } - if (code == TSDB_CODE_SUCCESS && pStbRowsCxt->ctbName.tname[0] == '\0') { - *pGotRow = true; - return TSDB_CODE_TSC_STMT_TBNAME_ERROR; + if (!bFoundTbName) { + if (!pCxt->isStmtBind) { + code = buildSyntaxErrMsg(&pCxt->msg, "tbname value expected", pOrigSql); + } else { + *pGotRow = true; + return TSDB_CODE_TSC_STMT_TBNAME_ERROR; + } } bool ctbFirst = true; @@ -2050,14 +2090,24 @@ static int32_t parseOneStbRow(SInsertParseContext* pCxt, SVnodeModifyOpStmt* pSt code = processCtbAutoCreationAndCtbMeta(pCxt, pStmt, pStbRowsCxt); } if (code == TSDB_CODE_SUCCESS) { - code = - insGetTableDataCxt(pStmt->pTableBlockHashObj, &pStbRowsCxt->pCtbMeta->uid, sizeof(pStbRowsCxt->pCtbMeta->uid), - pStbRowsCxt->pCtbMeta, &pStbRowsCxt->pCreateCtbReq, ppTableDataCxt, false, true); + if (pCxt->isStmtBind) { + char ctbFName[TSDB_TABLE_FNAME_LEN]; + code = tNameExtractFullName(&pStbRowsCxt->ctbName, ctbFName); + if (code != TSDB_CODE_SUCCESS) { + return code; + } + code = insGetTableDataCxt(pStmt->pTableBlockHashObj, ctbFName, strlen(ctbFName), pStbRowsCxt->pCtbMeta, + &pStbRowsCxt->pCreateCtbReq, ppTableDataCxt, true, true); + } else { + code = + insGetTableDataCxt(pStmt->pTableBlockHashObj, &pStbRowsCxt->pCtbMeta->uid, sizeof(pStbRowsCxt->pCtbMeta->uid), + pStbRowsCxt->pCtbMeta, &pStbRowsCxt->pCreateCtbReq, ppTableDataCxt, false, true); + } } if (code == TSDB_CODE_SUCCESS) { code = initTableColSubmitData(*ppTableDataCxt); } - if (code == TSDB_CODE_SUCCESS) { + if (code == TSDB_CODE_SUCCESS && !pCxt->isStmtBind) { SRow** pRow = taosArrayReserve((*ppTableDataCxt)->pData->aRowP, 1); code = tRowBuild(pStbRowsCxt->aColVals, (*ppTableDataCxt)->pSchema, pRow); if (TSDB_CODE_SUCCESS == code) { diff --git a/source/libs/parser/src/parInsertStmt.c b/source/libs/parser/src/parInsertStmt.c index 22b84e09dd..8a161b2118 100644 --- a/source/libs/parser/src/parInsertStmt.c +++ b/source/libs/parser/src/parInsertStmt.c @@ -941,8 +941,8 @@ int32_t buildBoundFields(int32_t numOfBound, int16_t* boundColumns, SSchema* pSc int32_t buildStbBoundFields(SBoundColInfo boundColsInfo, SSchema* pSchema, int32_t* fieldNum, TAOS_FIELD_STB** fields, STableMeta* pMeta, void* boundTags, bool preCtbname) { SBoundColInfo* tags = (SBoundColInfo*)boundTags; - int32_t numOfBound = boundColsInfo.numOfBound + tags->numOfBound + (preCtbname ? 1 : 0); - int32_t idx = 0; + int32_t numOfBound = boundColsInfo.numOfBound + (tags->mixTagsCols ? 0 : tags->numOfBound) + (preCtbname ? 1 : 0); + int32_t idx = 0; if (fields != NULL) { *fields = taosMemoryCalloc(numOfBound, sizeof(TAOS_FIELD_STB)); if (NULL == *fields) { @@ -957,13 +957,13 @@ int32_t buildStbBoundFields(SBoundColInfo boundColsInfo, SSchema* pSchema, int32 idx++; } - if (tags->numOfBound > 0) { - SSchema* pSchema = getTableTagSchema(pMeta); + if (tags->numOfBound > 0 && !tags->mixTagsCols) { + SSchema* tagSchema = getTableTagSchema(pMeta); for (int32_t i = 0; i < tags->numOfBound; ++i) { (*fields)[idx].field_type = TAOS_FIELD_TAG; - SSchema* schema = &pSchema[tags->pColIndex[i]]; + SSchema* schema = &tagSchema[tags->pColIndex[i]]; tstrncpy((*fields)[idx].name, schema->name, sizeof((*fields)[i].name)); (*fields)[idx].type = schema->type; (*fields)[idx].bytes = schema->bytes; diff --git a/source/libs/parser/src/parInsertUtil.c b/source/libs/parser/src/parInsertUtil.c index bcb560ab5e..502dbb57dd 100644 --- a/source/libs/parser/src/parInsertUtil.c +++ b/source/libs/parser/src/parInsertUtil.c @@ -191,6 +191,7 @@ int32_t insInitBoundColsInfo(int32_t numOfBound, SBoundColInfo* pInfo) { pInfo->numOfCols = numOfBound; pInfo->numOfBound = numOfBound; pInfo->hasBoundCols = false; + pInfo->mixTagsCols = false; pInfo->pColIndex = taosMemoryCalloc(numOfBound, sizeof(int16_t)); if (NULL == pInfo->pColIndex) { return terrno; @@ -204,6 +205,7 @@ int32_t insInitBoundColsInfo(int32_t numOfBound, SBoundColInfo* pInfo) { void insResetBoundColsInfo(SBoundColInfo* pInfo) { pInfo->numOfBound = pInfo->numOfCols; pInfo->hasBoundCols = false; + pInfo->mixTagsCols = false; for (int32_t i = 0; i < pInfo->numOfCols; ++i) { pInfo->pColIndex[i] = i; } @@ -739,7 +741,7 @@ int32_t insMergeTableDataCxt(SHashObj* pTableHash, SArray** pVgDataBlocks, bool STableDataCxt* pTableCxt = *(STableDataCxt**)p; if (colFormat) { SColData* pCol = taosArrayGet(pTableCxt->pData->aCol, 0); - if (pCol->nVal <= 0) { + if (pCol && pCol->nVal <= 0) { p = taosHashIterate(pTableHash, p); continue; } diff --git a/tests/script/api/stmt2-example.c b/tests/script/api/stmt2-example.c index 803e54c156..692ff90a06 100644 --- a/tests/script/api/stmt2-example.c +++ b/tests/script/api/stmt2-example.c @@ -33,30 +33,47 @@ void do_stmt(TAOS* taos) { char* tbs[2] = {"tb", "tb2"}; int t1_val[2] = {0, 1}; - int t2_len[2] = {3, 3}; - TAOS_STMT2_BIND tags[2][2] = {{{0, &t1_val[0], NULL, NULL, 0}, {0, "a1", &t2_len[0], NULL, 0}}, - {{0, &t1_val[1], NULL, NULL, 0}, {0, "a2", &t2_len[1], NULL, 0}}}; + int t2_len[2] = {10, 10}; + int t3_len[2] = {sizeof(int), sizeof(int)}; + TAOS_STMT2_BIND tags[2][2] = {{{0, &t1_val[0], &t3_len[0], NULL, 0}, {0, "after1", &t2_len[0], NULL, 0}}, + {{0, &t1_val[1], &t3_len[1], NULL, 0}, {0, "after2", &t2_len[1], NULL, 0}}}; TAOS_STMT2_BIND params[2][2] = { - {{TSDB_DATA_TYPE_TIMESTAMP, v.ts, NULL, is_null, 2}, {TSDB_DATA_TYPE_BINARY, v.b, b_len, is_null2, 2}}, - {{TSDB_DATA_TYPE_TIMESTAMP, v.ts, NULL, is_null, 2}, {TSDB_DATA_TYPE_BINARY, v.b, b_len, is_null2, 2}}}; + {{TSDB_DATA_TYPE_TIMESTAMP, v.ts, t64_len, is_null, 2}, {TSDB_DATA_TYPE_BINARY, v.b, b_len, NULL, 2}}, + {{TSDB_DATA_TYPE_TIMESTAMP, v.ts, t64_len, is_null, 2}, {TSDB_DATA_TYPE_BINARY, v.b, b_len, NULL, 2}}}; TAOS_STMT2_BIND* tagv[2] = {&tags[0][0], &tags[1][0]}; TAOS_STMT2_BIND* paramv[2] = {¶ms[0][0], ¶ms[1][0]}; TAOS_STMT2_BINDV bindv = {2, &tbs[0], &tagv[0], ¶mv[0]}; TAOS_STMT2* stmt = taos_stmt2_init(taos, &option); - const char* sql = "insert into db.? using db.stb tags(?, ?) values(?,?)"; - int code = taos_stmt2_prepare(stmt, sql, 0); + + // Equivalent to : + // const char* sql = "insert into db.? using db.stb tags(?, ?) values(?,?)"; + const char* sql = "insert into db.stb(tbname,ts,b,t1,t2) values(?,?,?,?,?)"; + + int code = taos_stmt2_prepare(stmt, sql, 0); if (code != 0) { printf("failed to execute taos_stmt2_prepare. error:%s\n", taos_stmt2_error(stmt)); taos_stmt2_close(stmt); return; } + int fieldNum = 0; + TAOS_FIELD_STB* pFields = NULL; + code = taos_stmt2_get_stb_fields(stmt, &fieldNum, &pFields); + if (code != 0) { + printf("failed get col,ErrCode: 0x%x, ErrMessage: %s.\n", code, taos_stmt2_error(stmt)); + } else { + printf("col nums:%d\n", fieldNum); + for (int i = 0; i < fieldNum; i++) { + printf("field[%d]: %s, data_type:%d, field_type:%d\n", i, pFields[i].name, pFields[i].type, + pFields[i].field_type); + } + } + int64_t ts = 1591060628000; for (int i = 0; i < 2; ++i) { - // v.ts[i] = ts++; - v.ts[i] = ts; - // t64_len[i] = sizeof(int64_t); + v.ts[i] = ts++; + t64_len[i] = sizeof(int64_t); } strcpy(v.b, "abcdefg"); b_len[0] = (int)strlen(v.b);