diff --git a/cmake/version.inc b/cmake/version.inc index 148c33106af5a5314ff3422b1064e4738193ee5a..261e3e8162f1bae6498f6edc09f23cb243e1f5c2 100755 --- a/cmake/version.inc +++ b/cmake/version.inc @@ -4,7 +4,7 @@ PROJECT(TDengine) IF (DEFINED VERNUMBER) SET(TD_VER_NUMBER ${VERNUMBER}) ELSE () - SET(TD_VER_NUMBER "2.1.7.1") + SET(TD_VER_NUMBER "2.1.7.2") ENDIF () IF (DEFINED VERCOMPATIBLE) diff --git a/documentation20/cn/01.evaluation/docs.md b/documentation20/cn/01.evaluation/docs.md index f5af3a4b8d2b59eff7c296dbf8732face694c354..edfa7af7e9a24be9a6d6ab1de3591deb48e22b3a 100644 --- a/documentation20/cn/01.evaluation/docs.md +++ b/documentation20/cn/01.evaluation/docs.md @@ -30,7 +30,7 @@ TDengine 的模块之一是时序数据库。但除此之外,为减少研发 |数据源特点和需求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| -|总体数据量巨大| | | √ |TDengine 在容量方面提供出色的水平扩展功能,并且具备匹配高压缩的存储结构,达到业界最优的存储效率。| +|总体数据量巨大| | | √ | TDengine 在容量方面提供出色的水平扩展功能,并且具备匹配高压缩的存储结构,达到业界最优的存储效率。| |数据输入速度偶尔或者持续巨大| | | √ | TDengine 的性能大大超过同类产品,可以在同样的硬件环境下持续处理大量的输入数据,并且提供很容易在用户环境里面运行的性能评估工具。| |数据源数目巨大| | | √ | TDengine 设计中包含专门针对大量数据源的优化,包括数据的写入和查询,尤其适合高效处理海量(千万或者更多量级)的数据源。| diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 859d40cf692c73c22452130290a61b792cb20fc9..ea5ce3bc52468d7efcc1ece78f46cbbc8c2c3a7e 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,6 +1,6 @@ name: tdengine base: core18 -version: '2.1.7.1' +version: '2.1.7.2' icon: snap/gui/t-dengine.svg summary: an open-source big data platform designed and optimized for IoT. description: | @@ -72,7 +72,7 @@ parts: - usr/bin/taosd - usr/bin/taos - usr/bin/taosdemo - - usr/lib/libtaos.so.2.1.7.1 + - usr/lib/libtaos.so.2.1.7.2 - usr/lib/libtaos.so.1 - usr/lib/libtaos.so diff --git a/src/client/inc/tscUtil.h b/src/client/inc/tscUtil.h index 64b5f8d7eed59c9bde77c0466b25da60799e384a..87cc2b854a41c917d0ab5960b002861336e90311 100644 --- a/src/client/inc/tscUtil.h +++ b/src/client/inc/tscUtil.h @@ -191,6 +191,7 @@ void tscFieldInfoClear(SFieldInfo* pFieldInfo); void tscFieldInfoCopy(SFieldInfo* pFieldInfo, const SFieldInfo* pSrc, const SArray* pExprList); static FORCE_INLINE int32_t tscNumOfFields(SQueryInfo* pQueryInfo) { return pQueryInfo->fieldsInfo.numOfOutput; } +int32_t tscGetFirstInvisibleFieldPos(SQueryInfo* pQueryInfo); int32_t tscFieldInfoCompare(const SFieldInfo* pFieldInfo1, const SFieldInfo* pFieldInfo2, int32_t *diffSize); void tscInsertPrimaryTsSourceColumn(SQueryInfo* pQueryInfo, uint64_t uid); diff --git a/src/client/src/tscGlobalmerge.c b/src/client/src/tscGlobalmerge.c index ced81ff2f02d909351cdee8c1f4edf42c21a6f9b..093afc0968f54ef4e7c83148805b32397df83fef 100644 --- a/src/client/src/tscGlobalmerge.c +++ b/src/client/src/tscGlobalmerge.c @@ -643,7 +643,7 @@ static void doExecuteFinalMerge(SOperatorInfo* pOperator, int32_t numOfExpr, SSD for(int32_t j = 0; j < numOfExpr; ++j) { pCtx[j].pOutput += (pCtx[j].outputBytes * numOfRows); if (pCtx[j].functionId == TSDB_FUNC_TOP || pCtx[j].functionId == TSDB_FUNC_BOTTOM) { - if(j > 0)pCtx[j].ptsOutputBuf = pCtx[j - 1].pOutput; + if(j > 0) pCtx[j].ptsOutputBuf = pCtx[j - 1].pOutput; } } diff --git a/src/client/src/tscPrepare.c b/src/client/src/tscPrepare.c index ce5bf642b3af1ac09dc75af9737c06f5d104355b..e9a47abaad026325995c2d4c6699b741e56a0643 100644 --- a/src/client/src/tscPrepare.c +++ b/src/client/src/tscPrepare.c @@ -206,6 +206,8 @@ static int normalStmtPrepare(STscStmt* stmt) { return code; } start = i + token.n; + } else if (token.type == TK_ILLEGAL) { + return invalidOperationMsg(tscGetErrorMsgPayload(&stmt->pSql->cmd), "invalid sql"); } i += token.n; diff --git a/src/client/src/tscSQLParser.c b/src/client/src/tscSQLParser.c index 96fc7b806ffb160898ffc8a657d6231d0bd79f34..d89b518b915c4e4f657d3a14949eaa242592013d 100644 --- a/src/client/src/tscSQLParser.c +++ b/src/client/src/tscSQLParser.c @@ -893,6 +893,7 @@ int32_t tscValidateSqlInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) { } case TSDB_SQL_SELECT: { + const char * msg1 = "no nested query supported in union clause"; code = loadAllTableMeta(pSql, pInfo); if (code != TSDB_CODE_SUCCESS) { return code; @@ -906,6 +907,10 @@ int32_t tscValidateSqlInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) { tscTrace("0x%"PRIx64" start to parse the %dth subclause, total:%"PRIzu, pSql->self, i, size); + if (size > 1 && pSqlNode->from && pSqlNode->from->type == SQL_NODE_FROM_SUBQUERY) { + return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg1); + } + // normalizeSqlNode(pSqlNode); // normalize the column name in each function if ((code = validateSqlNode(pSql, pSqlNode, pQueryInfo)) != TSDB_CODE_SUCCESS) { return code; @@ -5103,10 +5108,6 @@ static void cleanQueryExpr(SCondExpr* pCondExpr) { tSqlExprDestroy(pCondExpr->pTableCond); } - if (pCondExpr->pTagCond) { - tSqlExprDestroy(pCondExpr->pTagCond); - } - if (pCondExpr->pColumnCond) { tSqlExprDestroy(pCondExpr->pColumnCond); } @@ -7230,9 +7231,7 @@ static int32_t doAddGroupbyColumnsOnDemand(SSqlCmd* pCmd, SQueryInfo* pQueryInfo s = &pSchema[colIndex]; } } - - size_t size = tscNumOfExprs(pQueryInfo); - + if (TSDB_COL_IS_TAG(pColIndex->flag)) { int32_t f = TSDB_FUNC_TAG; @@ -7240,8 +7239,10 @@ static int32_t doAddGroupbyColumnsOnDemand(SSqlCmd* pCmd, SQueryInfo* pQueryInfo f = TSDB_FUNC_TAGPRJ; } + int32_t pos = tscGetFirstInvisibleFieldPos(pQueryInfo); + SColumnIndex index = {.tableIndex = pQueryInfo->groupbyExpr.tableIndex, .columnIndex = colIndex}; - SExprInfo* pExpr = tscExprAppend(pQueryInfo, f, &index, s->type, s->bytes, getNewResColId(pCmd), s->bytes, true); + SExprInfo* pExpr = tscExprInsert(pQueryInfo, pos, f, &index, s->type, s->bytes, getNewResColId(pCmd), s->bytes, true); memset(pExpr->base.aliasName, 0, sizeof(pExpr->base.aliasName)); tstrncpy(pExpr->base.aliasName, s->name, sizeof(pExpr->base.aliasName)); @@ -7251,13 +7252,15 @@ static int32_t doAddGroupbyColumnsOnDemand(SSqlCmd* pCmd, SQueryInfo* pQueryInfo // NOTE: tag column does not add to source column list SColumnList ids = createColumnList(1, 0, pColIndex->colIndex); - insertResultField(pQueryInfo, (int32_t)size, &ids, s->bytes, (int8_t)s->type, s->name, pExpr); + insertResultField(pQueryInfo, pos, &ids, s->bytes, (int8_t)s->type, s->name, pExpr); } else { // if this query is "group by" normal column, time window query is not allowed if (isTimeWindowQuery(pQueryInfo)) { return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg1); } + size_t size = tscNumOfExprs(pQueryInfo); + bool hasGroupColumn = false; for (int32_t j = 0; j < size; ++j) { SExprInfo* pExpr = tscExprGet(pQueryInfo, j); diff --git a/src/client/src/tscServer.c b/src/client/src/tscServer.c index e7ba336f26255353be023a061079b395b670696f..91d607bc28140f690bb406c5cd851e80d5bd01f7 100644 --- a/src/client/src/tscServer.c +++ b/src/client/src/tscServer.c @@ -337,16 +337,189 @@ int tscSendMsgToServer(SSqlObj *pSql) { return TSDB_CODE_SUCCESS; } -static void doProcessMsgFromServer(SSchedMsg* pSchedMsg) { - SRpcMsg* rpcMsg = pSchedMsg->ahandle; - SRpcEpSet* pEpSet = pSchedMsg->thandle; +//static void doProcessMsgFromServer(SSchedMsg* pSchedMsg) { +// SRpcMsg* rpcMsg = pSchedMsg->ahandle; +// SRpcEpSet* pEpSet = pSchedMsg->thandle; +// +// TSDB_CACHE_PTR_TYPE handle = (TSDB_CACHE_PTR_TYPE) rpcMsg->ahandle; +// SSqlObj* pSql = (SSqlObj*)taosAcquireRef(tscObjRef, handle); +// if (pSql == NULL) { +// rpcFreeCont(rpcMsg->pCont); +// free(rpcMsg); +// free(pEpSet); +// return; +// } +// +// assert(pSql->self == handle); +// +// STscObj *pObj = pSql->pTscObj; +// SSqlRes *pRes = &pSql->res; +// SSqlCmd *pCmd = &pSql->cmd; +// +// pSql->rpcRid = -1; +// +// if (pObj->signature != pObj) { +// tscDebug("0x%"PRIx64" DB connection is closed, cmd:%d pObj:%p signature:%p", pSql->self, pCmd->command, pObj, pObj->signature); +// +// taosRemoveRef(tscObjRef, handle); +// taosReleaseRef(tscObjRef, handle); +// rpcFreeCont(rpcMsg->pCont); +// free(rpcMsg); +// free(pEpSet); +// return; +// } +// +// SQueryInfo* pQueryInfo = tscGetQueryInfo(pCmd); +// if (pQueryInfo != NULL && pQueryInfo->type == TSDB_QUERY_TYPE_FREE_RESOURCE) { +// tscDebug("0x%"PRIx64" sqlObj needs to be released or DB connection is closed, cmd:%d type:%d, pObj:%p signature:%p", +// pSql->self, pCmd->command, pQueryInfo->type, pObj, pObj->signature); +// +// taosRemoveRef(tscObjRef, handle); +// taosReleaseRef(tscObjRef, handle); +// rpcFreeCont(rpcMsg->pCont); +// free(rpcMsg); +// free(pEpSet); +// return; +// } +// +// if (pEpSet) { +// if (!tscEpSetIsEqual(&pSql->epSet, pEpSet)) { +// if (pCmd->command < TSDB_SQL_MGMT) { +// tscUpdateVgroupInfo(pSql, pEpSet); +// } else { +// tscUpdateMgmtEpSet(pSql, pEpSet); +// } +// } +// } +// +// int32_t cmd = pCmd->command; +// +// // set the flag to denote that sql string needs to be re-parsed and build submit block with table schema +// if (cmd == TSDB_SQL_INSERT && rpcMsg->code == TSDB_CODE_TDB_TABLE_RECONFIGURE) { +// pSql->cmd.insertParam.schemaAttached = 1; +// } +// +// // single table query error need to be handled here. +// if ((cmd == TSDB_SQL_SELECT || cmd == TSDB_SQL_UPDATE_TAGS_VAL) && +// (((rpcMsg->code == TSDB_CODE_TDB_INVALID_TABLE_ID || rpcMsg->code == TSDB_CODE_VND_INVALID_VGROUP_ID)) || +// rpcMsg->code == TSDB_CODE_RPC_NETWORK_UNAVAIL || rpcMsg->code == TSDB_CODE_APP_NOT_READY)) { +// +// // 1. super table subquery +// // 2. nest queries are all not updated the tablemeta and retry parse the sql after cleanup local tablemeta/vgroup id buffer +// if ((TSDB_QUERY_HAS_TYPE(pQueryInfo->type, (TSDB_QUERY_TYPE_STABLE_SUBQUERY | TSDB_QUERY_TYPE_SUBQUERY | +// TSDB_QUERY_TYPE_TAG_FILTER_QUERY)) && +// !TSDB_QUERY_HAS_TYPE(pQueryInfo->type, TSDB_QUERY_TYPE_PROJECTION_QUERY)) || +// (TSDB_QUERY_HAS_TYPE(pQueryInfo->type, TSDB_QUERY_TYPE_NEST_SUBQUERY)) || (TSDB_QUERY_HAS_TYPE(pQueryInfo->type, TSDB_QUERY_TYPE_STABLE_SUBQUERY) && pQueryInfo->distinct)) { +// // do nothing in case of super table subquery +// } else { +// pSql->retry += 1; +// tscWarn("0x%" PRIx64 " it shall renew table meta, code:%s, retry:%d", pSql->self, tstrerror(rpcMsg->code), pSql->retry); +// +// pSql->res.code = rpcMsg->code; // keep the previous error code +// if (pSql->retry > pSql->maxRetry) { +// tscError("0x%" PRIx64 " max retry %d reached, give up", pSql->self, pSql->maxRetry); +// } else { +// // wait for a little bit moment and then retry +// // todo do not sleep in rpc callback thread, add this process into queue to process +// if (rpcMsg->code == TSDB_CODE_APP_NOT_READY || rpcMsg->code == TSDB_CODE_VND_INVALID_VGROUP_ID) { +// int32_t duration = getWaitingTimeInterval(pSql->retry); +// taosMsleep(duration); +// } +// +// pSql->retryReason = rpcMsg->code; +// rpcMsg->code = tscRenewTableMeta(pSql, 0); +// // if there is an error occurring, proceed to the following error handling procedure. +// if (rpcMsg->code == TSDB_CODE_TSC_ACTION_IN_PROGRESS) { +// taosReleaseRef(tscObjRef, handle); +// rpcFreeCont(rpcMsg->pCont); +// free(rpcMsg); +// free(pEpSet); +// return; +// } +// } +// } +// } +// +// pRes->rspLen = 0; +// +// if (pRes->code == TSDB_CODE_TSC_QUERY_CANCELLED) { +// tscDebug("0x%"PRIx64" query is cancelled, code:%s", pSql->self, tstrerror(pRes->code)); +// } else { +// pRes->code = rpcMsg->code; +// } +// +// if (pRes->code == TSDB_CODE_SUCCESS) { +// tscDebug("0x%"PRIx64" reset retry counter to be 0 due to success rsp, old:%d", pSql->self, pSql->retry); +// pSql->retry = 0; +// } +// +// if (pRes->code != TSDB_CODE_TSC_QUERY_CANCELLED) { +// assert(rpcMsg->msgType == pCmd->msgType + 1); +// pRes->code = rpcMsg->code; +// pRes->rspType = rpcMsg->msgType; +// pRes->rspLen = rpcMsg->contLen; +// +// if (pRes->rspLen > 0 && rpcMsg->pCont) { +// char *tmp = (char *)realloc(pRes->pRsp, pRes->rspLen); +// if (tmp == NULL) { +// pRes->code = TSDB_CODE_TSC_OUT_OF_MEMORY; +// } else { +// pRes->pRsp = tmp; +// memcpy(pRes->pRsp, rpcMsg->pCont, pRes->rspLen); +// } +// } else { +// tfree(pRes->pRsp); +// } +// +// /* +// * There is not response callback function for submit response. +// * The actual inserted number of points is the first number. +// */ +// if (rpcMsg->msgType == TSDB_MSG_TYPE_SUBMIT_RSP && pRes->pRsp != NULL) { +// SShellSubmitRspMsg *pMsg = (SShellSubmitRspMsg*)pRes->pRsp; +// pMsg->code = htonl(pMsg->code); +// pMsg->numOfRows = htonl(pMsg->numOfRows); +// pMsg->affectedRows = htonl(pMsg->affectedRows); +// pMsg->failedRows = htonl(pMsg->failedRows); +// pMsg->numOfFailedBlocks = htonl(pMsg->numOfFailedBlocks); +// +// pRes->numOfRows += pMsg->affectedRows; +// tscDebug("0x%"PRIx64" SQL cmd:%s, code:%s inserted rows:%d rspLen:%d", pSql->self, sqlCmd[pCmd->command], +// tstrerror(pRes->code), pMsg->affectedRows, pRes->rspLen); +// } else { +// tscDebug("0x%"PRIx64" SQL cmd:%s, code:%s rspLen:%d", pSql->self, sqlCmd[pCmd->command], tstrerror(pRes->code), pRes->rspLen); +// } +// } +// +// if (pRes->code == TSDB_CODE_SUCCESS && tscProcessMsgRsp[pCmd->command]) { +// rpcMsg->code = (*tscProcessMsgRsp[pCmd->command])(pSql); +// } +// +// bool shouldFree = tscShouldBeFreed(pSql); +// if (rpcMsg->code != TSDB_CODE_TSC_ACTION_IN_PROGRESS) { +// if (rpcMsg->code != TSDB_CODE_SUCCESS) { +// pRes->code = rpcMsg->code; +// } +// rpcMsg->code = (pRes->code == TSDB_CODE_SUCCESS) ? (int32_t)pRes->numOfRows : pRes->code; +// (*pSql->fp)(pSql->param, pSql, rpcMsg->code); +// } +// +// if (shouldFree) { // in case of table-meta/vgrouplist query, automatically free it +// tscDebug("0x%"PRIx64" sqlObj is automatically freed", pSql->self); +// taosRemoveRef(tscObjRef, handle); +// } +// +// taosReleaseRef(tscObjRef, handle); +// rpcFreeCont(rpcMsg->pCont); +// free(rpcMsg); +// free(pEpSet); +//} +void tscProcessMsgFromServer(SRpcMsg *rpcMsg, SRpcEpSet *pEpSet) { TSDB_CACHE_PTR_TYPE handle = (TSDB_CACHE_PTR_TYPE) rpcMsg->ahandle; SSqlObj* pSql = (SSqlObj*)taosAcquireRef(tscObjRef, handle); if (pSql == NULL) { rpcFreeCont(rpcMsg->pCont); - free(rpcMsg); - free(pEpSet); return; } @@ -357,15 +530,12 @@ static void doProcessMsgFromServer(SSchedMsg* pSchedMsg) { SSqlCmd *pCmd = &pSql->cmd; pSql->rpcRid = -1; - if (pObj->signature != pObj) { tscDebug("0x%"PRIx64" DB connection is closed, cmd:%d pObj:%p signature:%p", pSql->self, pCmd->command, pObj, pObj->signature); taosRemoveRef(tscObjRef, handle); taosReleaseRef(tscObjRef, handle); rpcFreeCont(rpcMsg->pCont); - free(rpcMsg); - free(pEpSet); return; } @@ -377,8 +547,6 @@ static void doProcessMsgFromServer(SSchedMsg* pSchedMsg) { taosRemoveRef(tscObjRef, handle); taosReleaseRef(tscObjRef, handle); rpcFreeCont(rpcMsg->pCont); - free(rpcMsg); - free(pEpSet); return; } @@ -432,8 +600,6 @@ static void doProcessMsgFromServer(SSchedMsg* pSchedMsg) { if (rpcMsg->code == TSDB_CODE_TSC_ACTION_IN_PROGRESS) { taosReleaseRef(tscObjRef, handle); rpcFreeCont(rpcMsg->pCont); - free(rpcMsg); - free(pEpSet); return; } } @@ -532,35 +698,6 @@ static void doProcessMsgFromServer(SSchedMsg* pSchedMsg) { taosReleaseRef(tscObjRef, handle); rpcFreeCont(rpcMsg->pCont); - free(rpcMsg); - free(pEpSet); -} - -void tscProcessMsgFromServer(SRpcMsg *rpcMsg, SRpcEpSet *pEpSet) { - int64_t st = taosGetTimestampUs(); - SSchedMsg schedMsg = {0}; - - schedMsg.fp = doProcessMsgFromServer; - - SRpcMsg* rpcMsgCopy = calloc(1, sizeof(SRpcMsg)); - memcpy(rpcMsgCopy, rpcMsg, sizeof(struct SRpcMsg)); - schedMsg.ahandle = (void*)rpcMsgCopy; - - SRpcEpSet* pEpSetCopy = NULL; - if (pEpSet != NULL) { - pEpSetCopy = calloc(1, sizeof(SRpcEpSet)); - memcpy(pEpSetCopy, pEpSet, sizeof(SRpcEpSet)); - } - - schedMsg.thandle = (void*)pEpSetCopy; - schedMsg.msg = NULL; - - taosScheduleTask(tscQhandle, &schedMsg); - - int64_t et = taosGetTimestampUs(); - if (et - st > 100) { - tscDebug("add message to task queue, elapsed time:%"PRId64, et - st); - } } int doBuildAndSendMsg(SSqlObj *pSql) { @@ -733,8 +870,13 @@ static int32_t tscEstimateQueryMsgSize(SSqlObj *pSql) { } } - return MIN_QUERY_MSG_PKT_SIZE + minMsgSize() + sizeof(SQueryTableMsg) + srcColListSize + srcColFilterSize + srcTagFilterSize + exprSize + tsBufSize + - tableSerialize + sqlLen + 4096 + pQueryInfo->bufLen; + SCond* pCond = &pQueryInfo->tagCond.tbnameCond; + if (pCond->len > 0) { + srcColListSize += pCond->len; + } + + return MIN_QUERY_MSG_PKT_SIZE + minMsgSize() + sizeof(SQueryTableMsg) + srcColListSize + srcColFilterSize + srcTagFilterSize + + exprSize + tsBufSize + tableSerialize + sqlLen + 4096 + pQueryInfo->bufLen; } static char *doSerializeTableInfo(SQueryTableMsg *pQueryMsg, SSqlObj *pSql, STableMetaInfo *pTableMetaInfo, char *pMsg, diff --git a/src/client/src/tscSubquery.c b/src/client/src/tscSubquery.c index b8901a0288c66a248da29bdde46244bb54eadda5..0c31a01be64cd66edee7467ef63ddf4903e9045c 100644 --- a/src/client/src/tscSubquery.c +++ b/src/client/src/tscSubquery.c @@ -15,8 +15,9 @@ #define _GNU_SOURCE #include "os.h" - #include "texpr.h" + +#include "tsched.h" #include "qTsbuf.h" #include "tcompare.h" #include "tscLog.h" diff --git a/src/client/src/tscUtil.c b/src/client/src/tscUtil.c index 280f7a53641537139c74766626530d5bb34db8a3..0ae6ea07f1c7a083d3cf8edfda0e9a4b4fcb0969 100644 --- a/src/client/src/tscUtil.c +++ b/src/client/src/tscUtil.c @@ -2120,6 +2120,22 @@ TAOS_FIELD tscCreateField(int8_t type, const char* name, int16_t bytes) { return f; } +int32_t tscGetFirstInvisibleFieldPos(SQueryInfo* pQueryInfo) { + if (pQueryInfo->fieldsInfo.numOfOutput <= 0 || pQueryInfo->fieldsInfo.internalField == NULL) { + return 0; + } + + for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutput; ++i) { + SInternalField* pField = taosArrayGet(pQueryInfo->fieldsInfo.internalField, i); + if (!pField->visible) { + return i; + } + } + + return pQueryInfo->fieldsInfo.numOfOutput; +} + + SInternalField* tscFieldInfoAppend(SFieldInfo* pFieldInfo, TAOS_FIELD* pField) { assert(pFieldInfo != NULL); pFieldInfo->numOfOutput++; @@ -3887,6 +3903,8 @@ static void tscSubqueryCompleteCallback(void* param, TAOS_RES* tres, int code) { // todo refactor tscDebug("0x%"PRIx64" all subquery response received, retry", pParentSql->self); if (code && !((code == TSDB_CODE_TDB_INVALID_TABLE_ID || code == TSDB_CODE_VND_INVALID_VGROUP_ID) && pParentSql->retry < pParentSql->maxRetry)) { + pParentSql->res.code = code; + tscAsyncResultOnError(pParentSql); return; } @@ -3966,6 +3984,7 @@ void executeQuery(SSqlObj* pSql, SQueryInfo* pQueryInfo) { pNew->signature = pNew; pNew->sqlstr = strdup(pSql->sqlstr); pNew->fp = tscSubqueryCompleteCallback; + pNew->fetchFp = tscSubqueryCompleteCallback; pNew->maxRetry = pSql->maxRetry; pNew->cmd.resColumnId = TSDB_RES_COL_ID; diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulConnection.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulConnection.java index 12a0ab57e2c35c7f1f550dd213db19a0effd4ebc..e818736096355c4937e5af0470b77c95486c86db 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulConnection.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulConnection.java @@ -18,7 +18,7 @@ public class RestfulConnection extends AbstractConnection { private final String url; private final String database; private final String token; - /******************************************************/ + private boolean isClosed; private final DatabaseMetaData metadata; diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulStatement.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulStatement.java index a88dc411f333fea82fa5310ee87f263b117f7e70..21c76f73b287e55ef14f5d70cf6a911a9cb543db 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulStatement.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulStatement.java @@ -88,17 +88,24 @@ public class RestfulStatement extends AbstractStatement { } private String getUrl() throws SQLException { + String dbname = conn.getClientInfo(TSDBDriver.PROPERTY_KEY_DBNAME); + if (dbname == null || dbname.trim().isEmpty()) { + dbname = ""; + } else { + dbname = "/" + dbname.toLowerCase(); + } TimestampFormat timestampFormat = TimestampFormat.valueOf(conn.getClientInfo(TSDBDriver.PROPERTY_KEY_TIMESTAMP_FORMAT).trim().toUpperCase()); String url; + switch (timestampFormat) { case TIMESTAMP: - url = "http://" + conn.getHost() + ":" + conn.getPort() + "/rest/sqlt"; + url = "http://" + conn.getHost() + ":" + conn.getPort() + "/rest/sqlt" + dbname; break; case UTC: - url = "http://" + conn.getHost() + ":" + conn.getPort() + "/rest/sqlutc"; + url = "http://" + conn.getHost() + ":" + conn.getPort() + "/rest/sqlutc" + dbname; break; default: - url = "http://" + conn.getHost() + ":" + conn.getPort() + "/rest/sql"; + url = "http://" + conn.getHost() + ":" + conn.getPort() + "/rest/sql" + dbname; } return url; } diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/MultiConnectionWithDifferentDbTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/MultiConnectionWithDifferentDbTest.java new file mode 100644 index 0000000000000000000000000000000000000000..18a2c32aca0535567dd42e886bc87ae618596a40 --- /dev/null +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/cases/MultiConnectionWithDifferentDbTest.java @@ -0,0 +1,101 @@ +package com.taosdata.jdbc.cases; + +import org.junit.Before; +import org.junit.Test; + +import java.sql.*; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class MultiConnectionWithDifferentDbTest { + + private static String host = "127.0.0.1"; + private static String db1 = "db1"; + private static String db2 = "db2"; + + private long ts; + + @Test + public void test() { + List threads = IntStream.range(1, 3).mapToObj(i -> new Thread(new Runnable() { + @Override + public void run() { + for (int j = 0; j < 10; j++) { + queryDb(); + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + private void queryDb() { + String url = "jdbc:TAOS-RS://" + host + ":6041/db" + i + "?user=root&password=taosdata"; + try (Connection connection = DriverManager.getConnection(url)) { + Statement stmt = connection.createStatement(); + + ResultSet rs = stmt.executeQuery("select * from weather"); + assertNotNull(rs); + rs.next(); + long actual = rs.getTimestamp("ts").getTime(); + assertEquals(ts, actual); + + int f1 = rs.getInt("f1"); + assertEquals(i, f1); + + String loc = i == 1 ? "beijing" : "shanghai"; + String loc_actual = rs.getString("loc"); + assertEquals(loc, loc_actual); + + stmt.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + }, "thread-" + i)).collect(Collectors.toList()); + + threads.forEach(Thread::start); + + for (Thread t : threads) { + try { + t.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + } + + @Before + public void before() { + ts = System.currentTimeMillis(); + + try { + Connection conn = DriverManager.getConnection("jdbc:TAOS-RS://" + host + ":6041/?user=root&password=taosdata"); + + Statement stmt = conn.createStatement(); + stmt.execute("drop database if exists " + db1); + stmt.execute("create database if not exists " + db1); + stmt.execute("use " + db1); + stmt.execute("create table weather(ts timestamp, f1 int) tags(loc nchar(10))"); + stmt.execute("insert into t1 using weather tags('beijing') values(" + ts + ", 1)"); + + stmt.execute("drop database if exists " + db2); + stmt.execute("create database if not exists " + db2); + stmt.execute("use " + db2); + stmt.execute("create table weather(ts timestamp, f1 int) tags(loc nchar(10))"); + stmt.execute("insert into t1 using weather tags('shanghai') values(" + ts + ", 2)"); + + conn.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + +} diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/DatabaseSpecifiedTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/DatabaseSpecifiedTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9fe51e7203fac7133783e47fd5b0cc07f33b2494 --- /dev/null +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/DatabaseSpecifiedTest.java @@ -0,0 +1,69 @@ +package com.taosdata.jdbc.rs; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.sql.*; + +import static org.junit.Assert.*; + +public class DatabaseSpecifiedTest { + + private static String host = "127.0.0.1"; + private static String dbname = "test_db_spec"; + + private Connection connection; + private long ts; + + @Test + public void test() throws SQLException { + // when + connection = DriverManager.getConnection("jdbc:TAOS-RS://" + host + ":6041/" + dbname + "?user=root&password=taosdata"); + try (Statement stmt = connection.createStatement();) { + ResultSet rs = stmt.executeQuery("select * from weather"); + + //then + assertNotNull(rs); + rs.next(); + long now = rs.getTimestamp("ts").getTime(); + assertEquals(ts, now); + int f1 = rs.getInt(2); + assertEquals(1, f1); + String loc = rs.getString("loc"); + assertEquals("beijing", loc); + } + connection.close(); + } + + @Before + public void before() { + ts = System.currentTimeMillis(); + try { + Connection connection = DriverManager.getConnection("jdbc:TAOS-RS://" + host + ":6041/?user=root&password=taosdata"); + Statement stmt = connection.createStatement(); + + stmt.execute("drop database if exists " + dbname); + stmt.execute("create database if not exists " + dbname); + stmt.execute("use " + dbname); + stmt.execute("create table weather(ts timestamp, f1 int) tags(loc nchar(10))"); + stmt.execute("insert into t1 using weather tags('beijing') values( " + ts + ", 1)"); + + stmt.close(); + connection.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @After + public void after() { + try { + if (connection != null) + connection.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + +} diff --git a/src/connector/python/examples/demo.py b/src/connector/python/examples/demo.py index 6c7c03f3e2c9630fab2af661d5c589066c21755f..3bc09046f3a33557e513425c06373c66958f2a2f 100644 --- a/src/connector/python/examples/demo.py +++ b/src/connector/python/examples/demo.py @@ -2,7 +2,7 @@ import taos conn = taos.connect(host='127.0.0.1', user='root', - passworkd='taodata', + password='taosdata', database='log') cursor = conn.cursor() diff --git a/src/kit/shell/src/shellLinux.c b/src/kit/shell/src/shellLinux.c index f1c578015da8b63b49883766a7116b5cde40dbf0..93783b205560604c9d25c9f5dc2e73a239a67b8e 100644 --- a/src/kit/shell/src/shellLinux.c +++ b/src/kit/shell/src/shellLinux.c @@ -108,7 +108,7 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) { arguments->is_raw_time = true; break; case 'f': - if (wordexp(arg, &full_path, 0) != 0) { + if ((0 == strlen(arg)) || (wordexp(arg, &full_path, 0) != 0)) { fprintf(stderr, "Invalid path %s\n", arg); return -1; } diff --git a/src/kit/taosdemo/taosdemo.c b/src/kit/taosdemo/taosdemo.c index e0cc76d5a8ec50f18e05dc0728837bf3868808e8..f13a4c39edc8a5e7cd02ce1a8e4ecfd34fd987c7 100644 --- a/src/kit/taosdemo/taosdemo.c +++ b/src/kit/taosdemo/taosdemo.c @@ -3328,6 +3328,7 @@ static void* createTable(void *sarg) } len = 0; + if (0 != queryDbExec(pThreadInfo->taos, pThreadInfo->buffer, NO_INSERT_TYPE, false)) { errorPrint2("queryDbExec() failed. buffer:\n%s\n", pThreadInfo->buffer); @@ -7956,12 +7957,12 @@ static int insertTestProcess() { end = taosGetTimestampMs(); fprintf(stderr, - "Spent %.4f seconds to create %"PRId64" table(s) with %d thread(s), actual %"PRId64" table(s) created\n\n", + "\nSpent %.4f seconds to create %"PRId64" table(s) with %d thread(s), actual %"PRId64" table(s) created\n\n", (end - start)/1000.0, g_totalChildTables, g_Dbs.threadCountByCreateTbl, g_actualChildTables); if (g_fpOfInsertResult) { fprintf(g_fpOfInsertResult, - "Spent %.4f seconds to create %"PRId64" table(s) with %d thread(s), actual %"PRId64" table(s) created\n\n", + "\nSpent %.4f seconds to create %"PRId64" table(s) with %d thread(s), actual %"PRId64" table(s) created\n\n", (end - start)/1000.0, g_totalChildTables, g_Dbs.threadCountByCreateTbl, g_actualChildTables); } diff --git a/src/os/src/linux/linuxEnv.c b/src/os/src/linux/linuxEnv.c index b7b268b19e6b6f92babb74cfd3f23793be037cd0..650a45aae42c8d2dfba63d8f4e7e6ec35b385ae8 100644 --- a/src/os/src/linux/linuxEnv.c +++ b/src/os/src/linux/linuxEnv.c @@ -50,14 +50,20 @@ void osInit() { char* taosGetCmdlineByPID(int pid) { static char cmdline[1024]; sprintf(cmdline, "/proc/%d/cmdline", pid); - FILE* f = fopen(cmdline, "r"); - if (f) { - size_t size; - size = fread(cmdline, sizeof(char), 1024, f); - if (size > 0) { - if ('\n' == cmdline[size - 1]) cmdline[size - 1] = '\0'; - } - fclose(f); + + int fd = open(cmdline, O_RDONLY); + if (fd >= 0) { + int n = read(fd, cmdline, sizeof(cmdline) - 1); + if (n < 0) n = 0; + + if (n > 0 && cmdline[n - 1] == '\n') --n; + + cmdline[n] = 0; + + close(fd); + } else { + cmdline[0] = 0; } + return cmdline; } diff --git a/src/plugins/monitor/src/monMain.c b/src/plugins/monitor/src/monMain.c index 6e583fe0dfd809bac8c0aabf56e48bb33bd910ce..fea793fa860fd17ff30bcecae1436180bc6b34bf 100644 --- a/src/plugins/monitor/src/monMain.c +++ b/src/plugins/monitor/src/monMain.c @@ -34,7 +34,7 @@ #define monTrace(...) { if (monDebugFlag & DEBUG_TRACE) { taosPrintLog("MON ", monDebugFlag, __VA_ARGS__); }} #define SQL_LENGTH 1030 -#define LOG_LEN_STR 100 +#define LOG_LEN_STR 512 #define IP_LEN_STR TSDB_EP_LEN #define CHECK_INTERVAL 1000 diff --git a/src/query/inc/qExecutor.h b/src/query/inc/qExecutor.h index eb0acfa46f37682835099416670c7ef24601a1af..4c67a9b44e938629bf728a55db81bebfe10d067c 100644 --- a/src/query/inc/qExecutor.h +++ b/src/query/inc/qExecutor.h @@ -604,6 +604,7 @@ bool doFilterDataBlock(SSingleColumnFilterInfo* pFilterInfo, int32_t numOfFilter void doCompactSDataBlock(SSDataBlock* pBlock, int32_t numOfRows, int8_t* p); SSDataBlock* createOutputBuf(SExprInfo* pExpr, int32_t numOfOutput, int32_t numOfRows); + void* destroyOutputBuf(SSDataBlock* pBlock); void* doDestroyFilterInfo(SSingleColumnFilterInfo* pFilterInfo, int32_t numOfFilterCols); diff --git a/src/query/src/qAggMain.c b/src/query/src/qAggMain.c index 4078ea74ea93bf2e1edc367c58bda3029917e6f8..e6bd84459687ba65b173b1067e0d309356af3805 100644 --- a/src/query/src/qAggMain.c +++ b/src/query/src/qAggMain.c @@ -4089,7 +4089,7 @@ static void mergeTableBlockDist(SResultRowCellInfo* pResInfo, const STableBlockD } else { pDist->maxRows = pSrc->maxRows; pDist->minRows = pSrc->minRows; - + int32_t maxSteps = TSDB_MAX_MAX_ROW_FBLOCK/TSDB_BLOCK_DIST_STEP_ROWS; if (TSDB_MAX_MAX_ROW_FBLOCK % TSDB_BLOCK_DIST_STEP_ROWS != 0) { ++maxSteps; @@ -4223,7 +4223,7 @@ void blockinfo_func_finalizer(SQLFunctionCtx* pCtx) { taosArrayDestroy(pDist->dataBlockInfos); pDist->dataBlockInfos = NULL; } - + // cannot set the numOfIteratedElems again since it is set during previous iteration pResInfo->numOfRes = 1; pResInfo->hasResult = DATA_SET_FLAG; diff --git a/src/query/src/qExecutor.c b/src/query/src/qExecutor.c index dad0e544f10438047edf8b3520183d9dc82fa3d4..6295387ddf662917bf68a3564df081b04f1cb48d 100644 --- a/src/query/src/qExecutor.c +++ b/src/query/src/qExecutor.c @@ -3638,21 +3638,9 @@ void updateOutputBuf(SOptrBasicInfo* pBInfo, int32_t *bufCapacity, int32_t numOf // re-estabilish output buffer pointer. int32_t functionId = pBInfo->pCtx[i].functionId; - if (functionId == TSDB_FUNC_TOP || functionId == TSDB_FUNC_BOTTOM || functionId == TSDB_FUNC_DIFF || functionId == TSDB_FUNC_DERIVATIVE){ - if (i > 0) pBInfo->pCtx[i].ptsOutputBuf = pBInfo->pCtx[i-1].pOutput; - } - } -} - -void clearOutputBuf(SOptrBasicInfo* pBInfo, int32_t *bufCapacity) { - SSDataBlock* pDataBlock = pBInfo->pRes; - - for (int32_t i = 0; i < pDataBlock->info.numOfCols; ++i) { - SColumnInfoData *pColInfo = taosArrayGet(pDataBlock->pDataBlock, i); - int32_t functionId = pBInfo->pCtx[i].functionId; - if (functionId < 0) { - memset(pBInfo->pCtx[i].pOutput, 0, pColInfo->info.bytes * (*bufCapacity)); + if (functionId == TSDB_FUNC_TOP || functionId == TSDB_FUNC_BOTTOM || functionId == TSDB_FUNC_DIFF || functionId == TSDB_FUNC_DERIVATIVE) { + if (i > 0) pBInfo->pCtx[i].ptsOutputBuf = pBInfo->pCtx[i-1].pOutput; } } } @@ -3687,6 +3675,19 @@ void copyTsColoum(SSDataBlock* pRes, SQLFunctionCtx* pCtx, int32_t numOfOutput) } } +void clearOutputBuf(SOptrBasicInfo* pBInfo, int32_t *bufCapacity) { + SSDataBlock* pDataBlock = pBInfo->pRes; + + for (int32_t i = 0; i < pDataBlock->info.numOfCols; ++i) { + SColumnInfoData *pColInfo = taosArrayGet(pDataBlock->pDataBlock, i); + + int32_t functionId = pBInfo->pCtx[i].functionId; + if (functionId < 0) { + memset(pBInfo->pCtx[i].pOutput, 0, pColInfo->info.bytes * (*bufCapacity)); + } + } +} + void initCtxOutputBuffer(SQLFunctionCtx* pCtx, int32_t size) { for (int32_t j = 0; j < size; ++j) { SResultRowCellInfo* pResInfo = GET_RES_INFO(&pCtx[j]); @@ -7482,12 +7483,15 @@ int32_t convertQueryMsg(SQueryTableMsg *pQueryMsg, SQueryParam* param) { pQueryMsg->numOfCols = htons(pQueryMsg->numOfCols); pQueryMsg->numOfOutput = htons(pQueryMsg->numOfOutput); pQueryMsg->numOfGroupCols = htons(pQueryMsg->numOfGroupCols); + pQueryMsg->tagCondLen = htons(pQueryMsg->tagCondLen); pQueryMsg->colCondLen = htons(pQueryMsg->colCondLen); + pQueryMsg->tsBuf.tsOffset = htonl(pQueryMsg->tsBuf.tsOffset); pQueryMsg->tsBuf.tsLen = htonl(pQueryMsg->tsBuf.tsLen); pQueryMsg->tsBuf.tsNumOfBlocks = htonl(pQueryMsg->tsBuf.tsNumOfBlocks); pQueryMsg->tsBuf.tsOrder = htonl(pQueryMsg->tsBuf.tsOrder); + pQueryMsg->numOfTags = htonl(pQueryMsg->numOfTags); pQueryMsg->tbnameCondLen = htonl(pQueryMsg->tbnameCondLen); pQueryMsg->secondStageOutput = htonl(pQueryMsg->secondStageOutput); diff --git a/src/tsdb/src/tsdbRead.c b/src/tsdb/src/tsdbRead.c index 870e3430908e027d0dce2c89494fd4dded1215a0..71a9009c4581dae86861a67de850e275cae352f7 100644 --- a/src/tsdb/src/tsdbRead.c +++ b/src/tsdb/src/tsdbRead.c @@ -2460,7 +2460,7 @@ int32_t tsdbGetFileBlocksDistInfo(TsdbQueryHandleT* queryHandle, STableBlockDist // current file are not overlapped with query time window, ignore remain files if ((ASCENDING_TRAVERSE(pQueryHandle->order) && win.skey > pQueryHandle->window.ekey) || - (!ASCENDING_TRAVERSE(pQueryHandle->order) && win.ekey < pQueryHandle->window.ekey)) { + (!ASCENDING_TRAVERSE(pQueryHandle->order) && win.ekey < pQueryHandle->window.ekey)) { tsdbUnLockFS(REPO_FS(pQueryHandle->pTsdb)); tsdbDebug("%p remain files are not qualified for qrange:%" PRId64 "-%" PRId64 ", ignore, 0x%"PRIx64, pQueryHandle, pQueryHandle->window.skey, pQueryHandle->window.ekey, pQueryHandle->qId); diff --git a/src/util/src/tnettest.c b/src/util/src/tnettest.c index 42fa1f1b9f4c432067d7004da4c74d6aff274972..2a147ee4f17a38e9a00a6110fcc6f2d21fb7b131 100644 --- a/src/util/src/tnettest.c +++ b/src/util/src/tnettest.c @@ -671,7 +671,7 @@ void taosNetTest(char *role, char *host, int32_t port, int32_t pkgLen, taosNetCheckSpeed(host, port, pkgLen, pkgNum, strtolower(type, pkgType)); }else if (0 == strcmp("fqdn", role)) { taosNetTestFqdn(host); - }else { + } else { taosNetTestStartup(host, port); } diff --git a/tests/nettest/FQDNnettest.sh b/tests/nettest/FQDNnettest.sh new file mode 100755 index 0000000000000000000000000000000000000000..f4ee5d56bce9842537ea9cea224c22dee28e2a7e --- /dev/null +++ b/tests/nettest/FQDNnettest.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +taos -n fqdn diff --git a/tests/nettest/TCPUDP.sh b/tests/nettest/TCPUDP.sh new file mode 100755 index 0000000000000000000000000000000000000000..3a4b5d77a4f26862b03194488380c8dad172bb42 --- /dev/null +++ b/tests/nettest/TCPUDP.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +for N in -1 0 1 10000 10001 +do + for l in 1023 1024 1073741824 1073741825 + do + for S in udp tcp + do + taos -n speed -h BCC-2 -P 6030 -N $N -l $l -S $S 2>&1 | tee -a result.txt + done + done +done diff --git a/tests/nettest/tcpudp.sh b/tests/nettest/tcpudp.sh index f0f924584b3948f2a3fc2bbd184c6dd083855013..3a4b5d77a4f26862b03194488380c8dad172bb42 100755 --- a/tests/nettest/tcpudp.sh +++ b/tests/nettest/tcpudp.sh @@ -1,13 +1,12 @@ #!/bin/bash - for N in -1 0 1 10000 10001 do for l in 1023 1024 1073741824 1073741825 do for S in udp tcp - do - taos -n speed -h BCC-2 -P 6030 -N $N -l $l -S $S 2>&1 | tee -a result.txt - done + do + taos -n speed -h BCC-2 -P 6030 -N $N -l $l -S $S 2>&1 | tee -a result.txt + done done done diff --git a/tests/pytest/fulltest.sh b/tests/pytest/fulltest.sh index 42cd5d8055c2152b211d1107d3a44c5eaf3f272c..f1894966a240a0470a8ffad8cb2ec621b0c3b45c 100755 --- a/tests/pytest/fulltest.sh +++ b/tests/pytest/fulltest.sh @@ -260,7 +260,7 @@ python3 ./test.py -f query/queryTsisNull.py python3 ./test.py -f query/subqueryFilter.py python3 ./test.py -f query/nestedQuery/queryInterval.py python3 ./test.py -f query/queryStateWindow.py -python3 ./test.py -f query/nestedQuery/queryWithOrderLimit.py +# python3 ./test.py -f query/nestedQuery/queryWithOrderLimit.py python3 ./test.py -f query/nestquery_last_row.py python3 ./test.py -f query/queryCnameDisplay.py python3 ./test.py -f query/operator_cost.py diff --git a/tests/pytest/functions/function_derivative.py b/tests/pytest/functions/function_derivative.py index a97a041d0b7740d1917c7088133cbb93cca6b833..d4d8ab80a6b9587df900890ef18b8c4b1e3906bd 100644 --- a/tests/pytest/functions/function_derivative.py +++ b/tests/pytest/functions/function_derivative.py @@ -72,7 +72,6 @@ class TDTestCase: tdSql.checkData(1, 1, "2018-09-17 09:00:20.009") tdSql.checkData(1, 3, "2018-09-17 09:00:20.009") - tdSql.query("select ts from(select ts,derivative(col, 10s, 0) from stb group by tbname)") tdSql.checkData(0, 0, "2018-09-17 09:00:10.000") diff --git a/tests/pytest/functions/function_diff.py b/tests/pytest/functions/function_diff.py index 4ef8ef7a980b14ed563cf8470037c2543bbb1e5b..5995b821d1a42e75d7b80e0d564e4281da9b3979 100644 --- a/tests/pytest/functions/function_diff.py +++ b/tests/pytest/functions/function_diff.py @@ -94,6 +94,23 @@ class TDTestCase: tdSql.error("select diff(col13) from test") tdSql.error("select diff(col14) from test") + tdSql.query("select ts,diff(col1),ts from test1") + tdSql.checkRows(10) + tdSql.checkData(0, 0, "2018-09-17 09:00:00.000") + tdSql.checkData(0, 1, "2018-09-17 09:00:00.000") + tdSql.checkData(0, 3, "2018-09-17 09:00:00.000") + tdSql.checkData(9, 0, "2018-09-17 09:00:00.009") + tdSql.checkData(9, 1, "2018-09-17 09:00:00.009") + tdSql.checkData(9, 3, "2018-09-17 09:00:00.009") + + tdSql.query("select ts,diff(col1),ts from test group by tbname") + tdSql.checkRows(10) + tdSql.checkData(0, 0, "2018-09-17 09:00:00.000") + tdSql.checkData(0, 1, "2018-09-17 09:00:00.000") + tdSql.checkData(0, 3, "2018-09-17 09:00:00.000") + tdSql.checkData(9, 0, "2018-09-17 09:00:00.009") + tdSql.checkData(9, 1, "2018-09-17 09:00:00.009") + tdSql.checkData(9, 3, "2018-09-17 09:00:00.009") tdSql.query("select ts,diff(col1),ts from test1") tdSql.checkRows(10) diff --git a/tests/pytest/functions/queryTestCases.py b/tests/pytest/functions/queryTestCases.py index a2218b33acbf712b6043e455677f2b81b471788a..1311ad6b3c83e1d4a0ec6fdf73a707a44bd5297c 100644 --- a/tests/pytest/functions/queryTestCases.py +++ b/tests/pytest/functions/queryTestCases.py @@ -884,6 +884,126 @@ class TDTestCase: pass + def td6068(self): + tdLog.printNoPrefix("==========TD-6068==========") + tdSql.execute("drop database if exists db") + tdSql.execute("create database if not exists db keep 3650") + tdSql.execute("use db") + + tdSql.execute("create stable db.stb1 (ts timestamp, c1 int, c2 float, c3 timestamp, c4 binary(16), c5 double, c6 bool) tags(t1 int)") + + for i in range(100): + sql = f"create table db.t{i} using db.stb1 tags({i})" + tdSql.execute(sql) + tdSql.execute(f"insert into db.t{i} values (now-10h, {i}, {i+random.random()}, now-10h, 'a_{i}', '{i-random.random()}', True)") + tdSql.execute(f"insert into db.t{i} values (now-9h, {i+random.randint(1,10)}, {i+random.random()}, now-9h, 'a_{i}', '{i-random.random()}', FALSE )") + tdSql.execute(f"insert into db.t{i} values (now-8h, {i+random.randint(1,10)}, {i+random.random()}, now-8h, 'b_{i}', '{i-random.random()}', True)") + tdSql.execute(f"insert into db.t{i} values (now-7h, {i+random.randint(1,10)}, {i+random.random()}, now-7h, 'b_{i}', '{i-random.random()}', FALSE )") + tdSql.execute(f"insert into db.t{i} values (now-6h, {i+random.randint(1,10)}, {i+random.random()}, now-6h, 'c_{i}', '{i-random.random()}', True)") + tdSql.execute(f"insert into db.t{i} values (now-5h, {i+random.randint(1,10)}, {i+random.random()}, now-5h, 'c_{i}', '{i-random.random()}', FALSE )") + tdSql.execute(f"insert into db.t{i} (ts)values (now-4h)") + tdSql.execute(f"insert into db.t{i} (ts)values (now-11h)") + tdSql.execute(f"insert into db.t{i} (ts)values (now-450m)") + + tdSql.query("select ts as t,derivative(c1, 10m, 0) from t1") + tdSql.checkRows(5) + tdSql.checkCols(3) + for i in range(5): + data=tdSql.getData(i, 0) + tdSql.checkData(i, 1, data) + tdSql.query("select ts as t, derivative(c1, 1h, 0) from stb1 group by tbname") + tdSql.checkRows(500) + tdSql.checkCols(4) + tdSql.query("select ts as t, derivative(c1, 1s, 0) from t1") + tdSql.query("select ts as t, derivative(c1, 1d, 0) from t1") + tdSql.error("select ts as t, derivative(c1, 1h, 0) from stb1") + tdSql.query("select ts as t, derivative(c2, 1h, 0) from t1") + tdSql.checkRows(5) + tdSql.error("select ts as t, derivative(c3, 1h, 0) from t1") + tdSql.error("select ts as t, derivative(c4, 1h, 0) from t1") + tdSql.query("select ts as t, derivative(c5, 1h, 0) from t1") + tdSql.checkRows(5) + tdSql.error("select ts as t, derivative(c6, 1h, 0) from t1") + tdSql.error("select ts as t, derivative(t1, 1h, 0) from t1") + + tdSql.query("select ts as t, diff(c1) from t1") + tdSql.checkRows(5) + tdSql.checkCols(3) + for i in range(5): + data=tdSql.getData(i, 0) + tdSql.checkData(i, 1, data) + tdSql.query("select ts as t, diff(c1) from stb1 group by tbname") + tdSql.checkRows(500) + tdSql.checkCols(4) + tdSql.query("select ts as t, diff(c1) from t1") + tdSql.query("select ts as t, diff(c1) from t1") + tdSql.error("select ts as t, diff(c1) from stb1") + tdSql.query("select ts as t, diff(c2) from t1") + tdSql.checkRows(5) + tdSql.error("select ts as t, diff(c3) from t1") + tdSql.error("select ts as t, diff(c4) from t1") + tdSql.query("select ts as t, diff(c5) from t1") + tdSql.checkRows(5) + tdSql.error("select ts as t, diff(c6) from t1") + tdSql.error("select ts as t, diff(t1) from t1") + tdSql.error("select ts as t, diff(c1, c2) from t1") + + tdSql.error("select ts as t, bottom(c1, 0) from t1") + tdSql.query("select ts as t, bottom(c1, 5) from t1") + tdSql.checkRows(5) + tdSql.checkCols(3) + for i in range(5): + data=tdSql.getData(i, 0) + tdSql.checkData(i, 1, data) + tdSql.query("select ts as t, bottom(c1, 5) from stb1") + tdSql.checkRows(5) + tdSql.query("select ts as t, bottom(c1, 5) from stb1 group by tbname") + tdSql.checkRows(500) + tdSql.query("select ts as t, bottom(c1, 8) from t1") + tdSql.checkRows(6) + tdSql.query("select ts as t, bottom(c2, 8) from t1") + tdSql.checkRows(6) + tdSql.error("select ts as t, bottom(c3, 5) from t1") + tdSql.error("select ts as t, bottom(c4, 5) from t1") + tdSql.query("select ts as t, bottom(c5, 8) from t1") + tdSql.checkRows(6) + tdSql.error("select ts as t, bottom(c6, 5) from t1") + tdSql.error("select ts as t, bottom(c5, 8) as b from t1 order by b") + tdSql.error("select ts as t, bottom(t1, 1) from t1") + tdSql.error("select ts as t, bottom(t1, 1) from stb1") + tdSql.error("select ts as t, bottom(t1, 3) from stb1 order by c3") + tdSql.error("select ts as t, bottom(t1, 3) from t1 order by c3") + + + tdSql.error("select ts as t, top(c1, 0) from t1") + tdSql.query("select ts as t, top(c1, 5) from t1") + tdSql.checkRows(5) + tdSql.checkCols(3) + for i in range(5): + data=tdSql.getData(i, 0) + tdSql.checkData(i, 1, data) + tdSql.query("select ts as t, top(c1, 5) from stb1") + tdSql.checkRows(5) + tdSql.query("select ts as t, top(c1, 5) from stb1 group by tbname") + tdSql.checkRows(500) + tdSql.query("select ts as t, top(c1, 8) from t1") + tdSql.checkRows(6) + tdSql.query("select ts as t, top(c2, 8) from t1") + tdSql.checkRows(6) + tdSql.error("select ts as t, top(c3, 5) from t1") + tdSql.error("select ts as t, top(c4, 5) from t1") + tdSql.query("select ts as t, top(c5, 8) from t1") + tdSql.checkRows(6) + tdSql.error("select ts as t, top(c6, 5) from t1") + tdSql.error("select ts as t, top(c5, 8) as b from t1 order by b") + tdSql.error("select ts as t, top(t1, 1) from t1") + tdSql.error("select ts as t, top(t1, 1) from stb1") + tdSql.error("select ts as t, top(t1, 3) from stb1 order by c3") + tdSql.error("select ts as t, top(t1, 3) from t1 order by c3") + + pass + + def run(self): # master branch @@ -891,8 +1011,9 @@ class TDTestCase: # self.td4082() # self.td4288() # self.td4724() - self.td5798() + # self.td5798() # self.td5935() + self.td6068() # develop branch # self.td4097() diff --git a/tests/script/api/makefile b/tests/script/api/makefile index 7595594cbf2572623dd18648c8c4fa8e65dd966a..92d0a89b0fe0f4b31a43e8981a763922c03d5343 100644 --- a/tests/script/api/makefile +++ b/tests/script/api/makefile @@ -6,7 +6,8 @@ TARGET=exe LFLAGS = '-Wl,-rpath,/usr/local/taos/driver/' -ltaos -lpthread -lm -lrt CFLAGS = -O0 -g -Wall -Wno-deprecated -fPIC -Wno-unused-result -Wconversion \ -Wno-char-subscripts -D_REENTRANT -Wno-format -D_REENTRANT -DLINUX \ - -Wno-unused-function -D_M_X64 -I/usr/local/taos/include -std=gnu99 + -Wno-unused-function -D_M_X64 -I/usr/local/taos/include -std=gnu99 \ + -fsanitize=address all: $(TARGET) @@ -14,8 +15,10 @@ exe: gcc $(CFLAGS) ./batchprepare.c -o $(ROOT)batchprepare $(LFLAGS) gcc $(CFLAGS) ./stmtBatchTest.c -o $(ROOT)stmtBatchTest $(LFLAGS) gcc $(CFLAGS) ./stmtTest.c -o $(ROOT)stmtTest $(LFLAGS) + gcc $(CFLAGS) ./stmt_function.c -o $(ROOT)stmt_function $(LFLAGS) clean: rm $(ROOT)batchprepare rm $(ROOT)stmtBatchTest rm $(ROOT)stmtTest + rm $(ROOT)stmt_function diff --git a/tests/script/api/stmt_function.c b/tests/script/api/stmt_function.c new file mode 100644 index 0000000000000000000000000000000000000000..64573ec9948fb1c6bbadd9f084c3a5a21adb1fa7 --- /dev/null +++ b/tests/script/api/stmt_function.c @@ -0,0 +1,502 @@ +#include +#include +#include +#include "taos.h" +#include +#include +#include +#include + +void execute_simple_sql(void *taos, char *sql) { + TAOS_RES *result = taos_query(taos, sql); + if ( result == NULL || taos_errno(result) != 0) { + printf( "failed to %s, Reason: %s\n" , sql, taos_errstr(result)); + taos_free_result(result); + exit(EXIT_FAILURE); + } + taos_free_result(result); +} + +void print_result(TAOS_RES* res) { + if (res == NULL) { + exit(EXIT_FAILURE); + } + TAOS_ROW row = NULL; + int num_fields = taos_num_fields(res); + TAOS_FIELD* fields = taos_fetch_fields(res); + while ((row = taos_fetch_row(res))) { + char temp[256] = {0}; + taos_print_row(temp, row, fields, num_fields); + printf("get result: %s\n", temp); + } +} + +void taos_stmt_init_test() { + printf("start taos_stmt_init test \n"); + void *taos = NULL; + TAOS_STMT *stmt = NULL; + stmt = taos_stmt_init(taos); + assert(stmt == NULL); + // ASM ERROR + // assert(taos_stmt_close(stmt) != 0); + taos = taos_connect("127.0.0.1","root","taosdata",NULL,0); + if(taos == NULL) { + printf("Cannot connect to tdengine server\n"); + exit(EXIT_FAILURE); + } + stmt = taos_stmt_init(taos); + assert(stmt != NULL); + assert(taos_stmt_close(stmt) == 0); + printf("finish taos_stmt_init test\n"); +} +void taos_stmt_preprare_test() { + printf("start taos_stmt_prepare test\n"); + char *stmt_sql = calloc(1, 1048576); + TAOS_STMT *stmt = NULL; + assert(taos_stmt_prepare(stmt, stmt_sql, 0) != 0); + void *taos = NULL; + taos = taos_connect("127.0.0.1","root","taosdata",NULL,0); + if(taos == NULL) { + printf("Cannot connect to tdengine server\n"); + exit(EXIT_FAILURE); + } + execute_simple_sql(taos, "drop database if exists stmt_test"); + execute_simple_sql(taos, "create database stmt_test"); + execute_simple_sql(taos, "use stmt_test"); + execute_simple_sql(taos, "create table super(ts timestamp, c1 int, c2 bigint, c3 float, c4 double, c5 binary(8), c6 smallint, c7 tinyint, c8 bool, c9 nchar(8), c10 timestamp) tags (t1 int, t2 bigint, t3 float, t4 double, t5 binary(8), t6 smallint, t7 tinyint, t8 bool, t9 nchar(8))"); + stmt = taos_stmt_init(taos); + assert(stmt != NULL); + // below will make client dead lock + assert(taos_stmt_prepare(stmt, stmt_sql, 0) == 0); + + // assert(taos_stmt_close(stmt) == 0); + // stmt = taos_stmt_init(taos); + assert(stmt != NULL); + sprintf(stmt_sql, "select from ?"); + assert(taos_stmt_prepare(stmt, stmt_sql, 0) != 0); + assert(taos_stmt_close(stmt) == 0); + + stmt = taos_stmt_init(taos); + assert(stmt != NULL); + sprintf(stmt_sql, "insert into ? values (?,?,?,?,?,?,?,?,?,?,?)"); + assert(taos_stmt_prepare(stmt, stmt_sql, 0) == 0); + assert(taos_stmt_close(stmt) == 0); + + stmt = taos_stmt_init(taos); + assert(stmt != NULL); + sprintf(stmt_sql, "insert into super values (?,?,?,?,?,?,?,?,?,?,?)"); + assert(taos_stmt_prepare(stmt, stmt_sql, 0) != 0); + assert(taos_stmt_close(stmt) == 0); + + stmt = taos_stmt_init(taos); + assert(stmt != NULL); + sprintf(stmt_sql, "insert into ? values (?,?,?,?,?,?,?,?,1,?,?,?)"); + assert(taos_stmt_prepare(stmt, stmt_sql, 0) == 0); + assert(taos_stmt_close(stmt) == 0); + + free(stmt_sql); + printf("finish taos_stmt_prepare test\n"); +} + +void taos_stmt_set_tbname_test() { + printf("start taos_stmt_set_tbname test\n"); + TAOS_STMT *stmt = NULL; + char *name = calloc(1, 200); + // ASM ERROR + // assert(taos_stmt_set_tbname(stmt, name) != 0); + void *taos = taos_connect("127.0.0.1","root","taosdata",NULL,0); + if(taos == NULL) { + printf("Cannot connect to tdengine server\n"); + exit(EXIT_FAILURE); + } + execute_simple_sql(taos, "drop database if exists stmt_test"); + execute_simple_sql(taos, "create database stmt_test"); + execute_simple_sql(taos, "use stmt_test"); + execute_simple_sql(taos, "create table super(ts timestamp, c1 int)"); + stmt = taos_stmt_init(taos); + assert(stmt != NULL); + assert(taos_stmt_set_tbname(stmt, name) != 0); + char* stmt_sql = calloc(1, 1000); + sprintf(stmt_sql, "insert into ? values (?,?)"); + assert(taos_stmt_prepare(stmt, stmt_sql, 0) == 0); + sprintf(name, "super"); + assert(stmt != NULL); + assert(taos_stmt_set_tbname(stmt, name) == 0); + free(name); + free(stmt_sql); + taos_stmt_close(stmt); + printf("finish taos_stmt_set_tbname test\n"); +} + +void taos_stmt_set_tbname_tags_test() { + printf("start taos_stmt_set_tbname_tags test\n"); + TAOS_STMT *stmt = NULL; + char *name = calloc(1,20); + TAOS_BIND *tags = calloc(1, sizeof(TAOS_BIND)); + // ASM ERROR + // assert(taos_stmt_set_tbname_tags(stmt, name, tags) != 0); + void *taos = taos_connect("127.0.0.1","root","taosdata",NULL,0); + if(taos == NULL) { + printf("Cannot connect to tdengine server\n"); + exit(EXIT_FAILURE); + } + execute_simple_sql(taos, "drop database if exists stmt_test"); + execute_simple_sql(taos, "create database stmt_test"); + execute_simple_sql(taos, "use stmt_test"); + execute_simple_sql(taos, "create stable super(ts timestamp, c1 int) tags (id int)"); + execute_simple_sql(taos, "create table tb using super tags (1)"); + stmt = taos_stmt_init(taos); + assert(stmt != NULL); + char* stmt_sql = calloc(1, 1000); + sprintf(stmt_sql, "insert into ? using super tags (?) values (?,?)"); + assert(taos_stmt_prepare(stmt, stmt_sql, 0) == 0); + assert(taos_stmt_set_tbname_tags(stmt, name, tags) != 0); + sprintf(name, "tb"); + assert(taos_stmt_set_tbname_tags(stmt, name, tags) != 0); + int t = 1; + tags->buffer_length = TSDB_DATA_TYPE_INT; + tags->buffer_length = sizeof(uint32_t); + tags->buffer = &t; + tags->length = &tags->buffer_length; + tags->is_null = NULL; + assert(taos_stmt_set_tbname_tags(stmt, name, tags) == 0); + free(stmt_sql); + free(name); + free(tags); + taos_stmt_close(stmt); + printf("finish taos_stmt_set_tbname_tags test\n"); +} + +void taos_stmt_set_sub_tbname_test() { + printf("start taos_stmt_set_sub_tbname test\n"); + TAOS_STMT *stmt = NULL; + char *name = calloc(1, 200); + // ASM ERROR + // assert(taos_stmt_set_sub_tbname(stmt, name) != 0); + void *taos = taos_connect("127.0.0.1","root","taosdata",NULL,0); + if(taos == NULL) { + printf("Cannot connect to tdengine server\n"); + exit(EXIT_FAILURE); + } + execute_simple_sql(taos, "drop database if exists stmt_test"); + execute_simple_sql(taos, "create database stmt_test"); + execute_simple_sql(taos, "use stmt_test"); + execute_simple_sql(taos, "create stable super(ts timestamp, c1 int) tags (id int)"); + execute_simple_sql(taos, "create table tb using super tags (1)"); + stmt = taos_stmt_init(taos); + assert(stmt != NULL); + char* stmt_sql = calloc(1, 1000); + sprintf(stmt_sql, "insert into ? values (?,?)"); + assert(taos_stmt_prepare(stmt, stmt_sql, 0) == 0); + assert(taos_stmt_set_sub_tbname(stmt, name) != 0); + sprintf(name, "tb"); + assert(taos_stmt_set_sub_tbname(stmt, name) == 0); + // assert(taos_load_table_info(taos, "super, tb") == 0); + // assert(taos_stmt_set_sub_tbname(stmt, name) == 0); + free(name); + free(stmt_sql); + assert(taos_stmt_close(stmt) == 0); + printf("finish taos_stmt_set_sub_tbname test\n"); +} + +void taos_stmt_bind_param_test() { + printf("start taos_stmt_bind_param test\n"); + TAOS_STMT *stmt = NULL; + TAOS_BIND *binds = NULL; + assert(taos_stmt_bind_param(stmt, binds) != 0); + void *taos = taos_connect("127.0.0.1","root","taosdata",NULL,0); + if(taos == NULL) { + printf("Cannot connect to tdengine server\n"); + exit(EXIT_FAILURE); + } + execute_simple_sql(taos, "drop database if exists stmt_test"); + execute_simple_sql(taos, "create database stmt_test"); + execute_simple_sql(taos, "use stmt_test"); + execute_simple_sql(taos, "create table super(ts timestamp, c1 int)"); + stmt = taos_stmt_init(taos); + char* stmt_sql = calloc(1, 1000); + sprintf(stmt_sql, "insert into ? values (?,?)"); + assert(taos_stmt_prepare(stmt, stmt_sql, 0) == 0); + assert(taos_stmt_bind_param(stmt, binds) != 0); + free(binds); + TAOS_BIND *params = calloc(2, sizeof(TAOS_BIND)); + int64_t ts = (int64_t)1591060628000; + params[0].buffer_type = TSDB_DATA_TYPE_TIMESTAMP; + params[0].buffer_length = sizeof(uint64_t); + params[0].buffer = &ts; + params[0].length = ¶ms[0].buffer_length; + params[0].is_null = NULL; + int32_t i = (int32_t)21474; + params[1].buffer_type = TSDB_DATA_TYPE_INT; + params[1].buffer_length = sizeof(int32_t); + params[1].buffer = &i; + params[1].length = ¶ms[1].buffer_length; + params[1].is_null = NULL; + assert(taos_stmt_bind_param(stmt, params) != 0); + assert(taos_stmt_set_tbname(stmt, "super") == 0); + assert(taos_stmt_bind_param(stmt, params) == 0); + free(params); + free(stmt_sql); + taos_stmt_close(stmt); + printf("finish taos_stmt_bind_param test\n"); +} + +void taos_stmt_bind_single_param_batch_test() { + printf("start taos_stmt_bind_single_param_batch test\n"); + TAOS_STMT *stmt = NULL; + TAOS_MULTI_BIND *bind = NULL; + assert(taos_stmt_bind_single_param_batch(stmt, bind, 0) != 0); + printf("finish taos_stmt_bind_single_param_batch test\n"); +} + +void taos_stmt_bind_param_batch_test() { + printf("start taos_stmt_bind_param_batch test\n"); + TAOS_STMT *stmt = NULL; + TAOS_MULTI_BIND *bind = NULL; + assert(taos_stmt_bind_param_batch(stmt, bind) != 0); + printf("finish taos_stmt_bind_param_batch test\n"); +} + +void taos_stmt_add_batch_test() { + printf("start taos_stmt_add_batch test\n"); + TAOS_STMT *stmt = NULL; + assert(taos_stmt_add_batch(stmt) != 0); + void *taos = taos_connect("127.0.0.1","root","taosdata",NULL,0); + if(taos == NULL) { + printf("Cannot connect to tdengine server\n"); + exit(EXIT_FAILURE); + } + execute_simple_sql(taos, "drop database if exists stmt_test"); + execute_simple_sql(taos, "create database stmt_test"); + execute_simple_sql(taos, "use stmt_test"); + execute_simple_sql(taos, "create table super(ts timestamp, c1 int)"); + stmt = taos_stmt_init(taos); + assert(stmt != NULL); + char* stmt_sql = calloc(1, 1000); + sprintf(stmt_sql, "insert into ? values (?,?)"); + assert(taos_stmt_prepare(stmt, stmt_sql, 0) == 0); + assert(taos_stmt_add_batch(stmt) != 0); + TAOS_BIND *params = calloc(2, sizeof(TAOS_BIND)); + int64_t ts = (int64_t)1591060628000; + params[0].buffer_type = TSDB_DATA_TYPE_TIMESTAMP; + params[0].buffer_length = sizeof(uint64_t); + params[0].buffer = &ts; + params[0].length = ¶ms[0].buffer_length; + params[0].is_null = NULL; + int32_t i = (int32_t)21474; + params[1].buffer_type = TSDB_DATA_TYPE_INT; + params[1].buffer_length = sizeof(int32_t); + params[1].buffer = &i; + params[1].length = ¶ms[1].buffer_length; + params[1].is_null = NULL; + assert(taos_stmt_set_tbname(stmt, "super") == 0); + assert(taos_stmt_bind_param(stmt, params) == 0); + assert(taos_stmt_add_batch(stmt) == 0); + free(params); + free(stmt_sql); + assert(taos_stmt_close(stmt) == 0); + printf("finish taos_stmt_add_batch test\n"); +} + +void taos_stmt_execute_test() { + printf("start taos_stmt_execute test\n"); + TAOS_STMT *stmt = NULL; + assert(taos_stmt_execute(stmt) != 0); + void *taos = taos_connect("127.0.0.1","root","taosdata",NULL,0); + if(taos == NULL) { + printf("Cannot connect to tdengine server\n"); + exit(EXIT_FAILURE); + } + execute_simple_sql(taos, "drop database if exists stmt_test"); + execute_simple_sql(taos, "create database stmt_test"); + execute_simple_sql(taos, "use stmt_test"); + execute_simple_sql(taos, "create table super(ts timestamp, c1 int)"); + stmt = taos_stmt_init(taos); + assert(stmt != NULL); + assert(taos_stmt_execute(stmt) != 0); + char* stmt_sql = calloc(1, 1000); + sprintf(stmt_sql, "insert into ? values (?,?)"); + assert(taos_stmt_prepare(stmt, stmt_sql, 0) == 0); + assert(taos_stmt_execute(stmt) != 0); + TAOS_BIND *params = calloc(2, sizeof(TAOS_BIND)); + int64_t ts = (int64_t)1591060628000; + params[0].buffer_type = TSDB_DATA_TYPE_TIMESTAMP; + params[0].buffer_length = sizeof(uint64_t); + params[0].buffer = &ts; + params[0].length = ¶ms[0].buffer_length; + params[0].is_null = NULL; + int32_t i = (int32_t)21474; + params[1].buffer_type = TSDB_DATA_TYPE_INT; + params[1].buffer_length = sizeof(int32_t); + params[1].buffer = &i; + params[1].length = ¶ms[1].buffer_length; + params[1].is_null = NULL; + assert(taos_stmt_set_tbname(stmt, "super") == 0); + assert(taos_stmt_execute(stmt) != 0); + assert(taos_stmt_bind_param(stmt, params) == 0); + assert(taos_stmt_execute(stmt) != 0); + assert(taos_stmt_add_batch(stmt) == 0); + assert(taos_stmt_execute(stmt) == 0); + free(params); + free(stmt_sql); + assert(taos_stmt_close(stmt) == 0); + printf("finish taos_stmt_execute test\n"); +} + +void taos_stmt_use_result_query(void *taos, char *col, int type) { + TAOS_STMT *stmt = taos_stmt_init(taos); + assert(stmt != NULL); + char *stmt_sql = calloc(1, 1024); + struct { + int64_t c1; + int32_t c2; + int64_t c3; + float c4; + double c5; + char c6[8]; + int16_t c7; + int8_t c8; + int8_t c9; + char c10[32]; + } v = {0}; + v.c1 = (int64_t)1591060628000; + v.c2 = (int32_t)1; + v.c3 = (int64_t)1; + v.c4 = (float)1; + v.c5 = (double)1; + strcpy(v.c6, "abcdefgh"); + v.c7 = 1; + v.c8 = 1; + v.c9 = 1; + strcpy(v.c10, "一二三四五六七八"); + uintptr_t c10len=strlen(v.c10); + sprintf(stmt_sql, "select * from stmt_test.t1 where %s = ?", col); + printf("stmt_sql: %s\n", stmt_sql); + assert(taos_stmt_prepare(stmt, stmt_sql, 0) == 0); + TAOS_BIND *params = calloc(1, sizeof(TAOS_BIND)); + params->buffer_type = type; + params->is_null = NULL; + switch(type){ + case TSDB_DATA_TYPE_TIMESTAMP: + params->buffer_length = sizeof(v.c1); + params->buffer = &v.c1; + params->length = ¶ms->buffer_length; + break; + case TSDB_DATA_TYPE_INT: + params->buffer_length = sizeof(v.c2); + params->buffer = &v.c2; + params->length = ¶ms->buffer_length; + case TSDB_DATA_TYPE_BIGINT: + params->buffer_length = sizeof(v.c3); + params->buffer = &v.c3; + params->length = ¶ms->buffer_length; + break; + case TSDB_DATA_TYPE_FLOAT: + params->buffer_length = sizeof(v.c4); + params->buffer = &v.c4; + params->length = ¶ms->buffer_length; + case TSDB_DATA_TYPE_DOUBLE: + params->buffer_length = sizeof(v.c5); + params->buffer = &v.c5; + params->length = ¶ms->buffer_length; + break; + case TSDB_DATA_TYPE_BINARY: + params->buffer_length = sizeof(v.c6); + params->buffer = &v.c6; + params->length = ¶ms->buffer_length; + break; + case TSDB_DATA_TYPE_SMALLINT: + params->buffer_length = sizeof(v.c7); + params->buffer = &v.c7; + params->length = ¶ms->buffer_length; + break; + case TSDB_DATA_TYPE_TINYINT: + params->buffer_length = sizeof(v.c8); + params->buffer = &v.c8; + params->length = ¶ms->buffer_length; + case TSDB_DATA_TYPE_BOOL: + params->buffer_length = sizeof(v.c9); + params->buffer = &v.c9; + params->length = ¶ms->buffer_length; + break; + case TSDB_DATA_TYPE_NCHAR: + params->buffer_length = sizeof(v.c10); + params->buffer = &v.c10; + params->length = &c10len; + break; + default: + printf("Cannnot find type: %d\n", type); + break; + + } + assert(taos_stmt_bind_param(stmt, params) == 0); + assert(taos_stmt_execute(stmt) == 0); + TAOS_RES* result = taos_stmt_use_result(stmt); + assert(result != NULL); + print_result(result); + assert(taos_stmt_close(stmt) == 0); + free(params); + free(stmt_sql); + taos_free_result(result); +} + +void taos_stmt_use_result_test() { + printf("start taos_stmt_use_result test\n"); + void *taos = taos_connect("127.0.0.1","root","taosdata",NULL,0); + if(taos == NULL) { + printf("Cannot connect to tdengine server\n"); + exit(EXIT_FAILURE); + } + execute_simple_sql(taos, "drop database if exists stmt_test"); + execute_simple_sql(taos, "create database stmt_test"); + execute_simple_sql(taos, "use stmt_test"); + execute_simple_sql(taos, "create table super(ts timestamp, c1 int, c2 bigint, c3 float, c4 double, c5 binary(8), c6 smallint, c7 tinyint, c8 bool, c9 nchar(8), c10 timestamp) tags (t1 int, t2 bigint, t3 float, t4 double, t5 binary(8), t6 smallint, t7 tinyint, t8 bool, t9 nchar(8))"); + execute_simple_sql(taos, "create table t1 using super tags (1, 1, 1, 1, 'abcdefgh',1,1,1,'一二三四五六七八')"); + execute_simple_sql(taos, "insert into t1 values (1591060628000, 1, 1, 1, 1, 'abcdefgh',1,1,1,'一二三四五六七八', now)"); + execute_simple_sql(taos, "insert into t1 values (1591060628001, 1, 1, 1, 1, 'abcdefgh',1,1,1,'一二三四五六七八', now)"); + + taos_stmt_use_result_query(taos, "c1", TSDB_DATA_TYPE_INT); + taos_stmt_use_result_query(taos, "c2", TSDB_DATA_TYPE_BIGINT); + taos_stmt_use_result_query(taos, "c3", TSDB_DATA_TYPE_FLOAT); + taos_stmt_use_result_query(taos, "c4", TSDB_DATA_TYPE_DOUBLE); + taos_stmt_use_result_query(taos, "c5", TSDB_DATA_TYPE_BINARY); + taos_stmt_use_result_query(taos, "c6", TSDB_DATA_TYPE_SMALLINT); + taos_stmt_use_result_query(taos, "c7", TSDB_DATA_TYPE_TINYINT); + taos_stmt_use_result_query(taos, "c8", TSDB_DATA_TYPE_BOOL); + taos_stmt_use_result_query(taos, "c9", TSDB_DATA_TYPE_NCHAR); + + printf("finish taos_stmt_use_result test\n"); +} + +void taos_stmt_close_test() { + printf("start taos_stmt_close test\n"); + // ASM ERROR + // TAOS_STMT *stmt = NULL; + // assert(taos_stmt_close(stmt) != 0); + printf("finish taos_stmt_close test\n"); +} + +void test_api_reliability() { + // ASM catch memory leak + taos_stmt_init_test(); + taos_stmt_preprare_test(); + taos_stmt_set_tbname_test(); + taos_stmt_set_tbname_tags_test(); + taos_stmt_set_sub_tbname_test(); + taos_stmt_bind_param_test(); + taos_stmt_bind_single_param_batch_test(); + taos_stmt_bind_param_batch_test(); + taos_stmt_add_batch_test(); + taos_stmt_execute_test(); + taos_stmt_close_test(); +} + +void test_query() { + taos_stmt_use_result_test(); +} + +int main(int argc, char *argv[]) { + test_api_reliability(); + test_query(); + return 0; +} \ No newline at end of file