diff --git a/src/client/inc/tscSQLParser.h b/src/client/inc/tscSQLParser.h index dd579d08c3c6b1465ce6b34e29f453c7b00827ec..0e4ad279dc0beaf0c56109583d3d02f5ae60b4f3 100644 --- a/src/client/inc/tscSQLParser.h +++ b/src/client/inc/tscSQLParser.h @@ -86,15 +86,16 @@ enum _sql_cmd { TSDB_SQL_MAX //48 }; -#define MAX_TOKEN_LEN 30 - -// token type enum { TSQL_NODE_TYPE_EXPR = 0x1, TSQL_NODE_TYPE_ID = 0x2, TSQL_NODE_TYPE_VALUE = 0x4, }; +#define NON_ARITHMEIC_EXPR 0 +#define NORMAL_ARITHMETIC 1 +#define AGG_ARIGHTMEIC 2 + extern char tTokenTypeSwitcher[13]; #define toTSDBType(x) \ @@ -112,7 +113,7 @@ typedef struct SLimitVal { } SLimitVal; typedef struct SOrderVal { - int32_t order; + uint32_t order; int32_t orderColId; } SOrderVal; diff --git a/src/client/inc/tscUtil.h b/src/client/inc/tscUtil.h index c67e7cb679592886040bd9cf6cf6d7adec5a656c..a869e45198fe2da615b2178c55a32bcd64a9285a 100644 --- a/src/client/inc/tscUtil.h +++ b/src/client/inc/tscUtil.h @@ -128,6 +128,8 @@ void tscFieldInfoSetValFromSchema(SFieldInfo* pFieldInfo, int32_t index, SSchema void tscFieldInfoSetValFromField(SFieldInfo* pFieldInfo, int32_t index, TAOS_FIELD* pField); void tscFieldInfoSetValue(SFieldInfo* pFieldInfo, int32_t index, int8_t type, const char* name, int16_t bytes); void tscFieldInfoUpdateVisible(SFieldInfo* pFieldInfo, int32_t index, bool visible); +void tscFieldInfoSetExpr(SFieldInfo* pFieldInfo, int32_t index, SSqlExpr* pExpr); +void tscFieldInfoSetBinExpr(SFieldInfo* pFieldInfo, int32_t index, SSqlFunctionExpr* pExpr); void tscFieldInfoCalOffset(SQueryInfo* pQueryInfo); void tscFieldInfoUpdateOffsetForInterResult(SQueryInfo* pQueryInfo); @@ -149,9 +151,10 @@ SSqlExpr* tscSqlExprInsertEmpty(SQueryInfo* pQueryInfo, int32_t index, int16_t f SSqlExpr* tscSqlExprUpdate(SQueryInfo* pQueryInfo, int32_t index, int16_t functionId, int16_t srcColumnIndex, int16_t type, int16_t size); +int32_t tscSqlExprNumOfExprs(SQueryInfo* pQueryInfo); SSqlExpr* tscSqlExprGet(SQueryInfo* pQueryInfo, int32_t index); -void tscSqlExprCopy(SSqlExprInfo* dst, const SSqlExprInfo* src, uint64_t uid); +void tscSqlExprCopy(SSqlExprInfo* dst, const SSqlExprInfo* src, uint64_t uid, bool deepcopy); void* tscSqlExprDestroy(SSqlExpr* pExpr); void tscSqlExprInfoDestroy(SSqlExprInfo* pExprInfo); diff --git a/src/client/inc/tsclient.h b/src/client/inc/tsclient.h index 700d6a43cf25a4be54f87bdccb35d46dc51d3867..7e3b54545a5c6fb942d2a70da6c09b5f47123727 100644 --- a/src/client/inc/tsclient.h +++ b/src/client/inc/tsclient.h @@ -32,9 +32,8 @@ extern "C" { #include "tutil.h" #include "trpc.h" -#define TSC_GET_RESPTR_BASE(res, _queryinfo, col, ord) \ - (res->data + tscFieldInfoGetOffset(_queryinfo, col) * res->numOfRows) - +#define TSC_GET_RESPTR_BASE(res, _queryinfo, col) (res->data + ((_queryinfo)->fieldsInfo.pSqlExpr[col]->offset) * res->numOfRows) + // forward declaration struct SSqlInfo; @@ -71,13 +70,19 @@ typedef struct SSqlExpr { int16_t interResBytes; // inter result buffer size int16_t numOfParams; // argument value of each function tVariant param[3]; // parameters are not more than 3 + int32_t offset; // sub result column value of arithmetic expression. } SSqlExpr; +typedef struct SColumnIndex { + int16_t tableIndex; + int16_t columnIndex; +} SColumnIndex; + typedef struct SFieldInfo { int16_t numOfOutputCols; // number of column in result int16_t numOfAlloc; // allocated size TAOS_FIELD *pFields; - short * pOffset; +// short * pOffset; /* * define if this column is belong to the queried result, it may be add by parser to faciliate @@ -86,20 +91,17 @@ typedef struct SFieldInfo { * NOTE: these hidden columns always locate at the end of the output columns */ bool * pVisibleCols; - int32_t numOfHiddenCols; // the number of column not belongs to the queried result columns + int32_t numOfHiddenCols; // the number of column not belongs to the queried result columns + SSqlFunctionExpr** pExpr; // used for aggregation arithmetic express,such as count(*)+count(*) + SSqlExpr** pSqlExpr; } SFieldInfo; typedef struct SSqlExprInfo { - int16_t numOfAlloc; - int16_t numOfExprs; - SSqlExpr *pExprs; + int16_t numOfAlloc; + int16_t numOfExprs; + SSqlExpr** pExprs; } SSqlExprInfo; -typedef struct SColumnIndex { - int16_t tableIndex; - int16_t columnIndex; -} SColumnIndex; - typedef struct SColumnBase { SColumnIndex colIndex; int32_t numOfFilters; @@ -164,7 +166,7 @@ typedef struct STableDataBlocks { int32_t rowSize; // row size for current table uint32_t nAllocSize; - uint32_t headerSize; // header for metadata (submit metadata) + uint32_t headerSize; // header for metadata (submit metadata) uint32_t size; /* @@ -199,9 +201,9 @@ typedef struct SQueryInfo { char intervalTimeUnit; int64_t etime, stime; - int64_t nAggTimeInterval; // aggregation time interval - int64_t nSlidingTime; // sliding window in mseconds - SSqlGroupbyExpr groupbyExpr; // group by tags info + int64_t intervalTime; // aggregation time interval + int64_t slidingTime; // sliding window in mseconds + SSqlGroupbyExpr groupbyExpr; // group by tags info SColumnBaseInfo colList; SFieldInfo fieldsInfo; @@ -217,9 +219,9 @@ typedef struct SQueryInfo { int64_t * defaultVal; // default value for interpolation char * msg; // pointer to the pCmd->payload to keep error message temporarily int64_t clauseLimit; // limit for current sub clause - + // offset value in the original sql expression, NOT sent to virtual node, only applied at client side - int64_t prjOffset; + int64_t prjOffset; } SQueryInfo; // data source from sql string or from file @@ -270,29 +272,27 @@ typedef struct SResRec { struct STSBuf; typedef struct { - int32_t code; - int64_t numOfRows; // num of results in current retrieved - int64_t numOfTotal; // num of total results - int64_t numOfTotalInCurrentClause; // num of total result in current subclause - - char * pRsp; - int rspType; - int rspLen; - uint64_t qhandle; - int64_t uid; - int64_t useconds; - int64_t offset; // offset value from vnode during projection query of stable - int row; - int16_t numOfnchar; - int16_t precision; - int32_t numOfGroups; - SResRec * pGroupRec; - char * data; - short * bytes; - void ** tsrow; - char ** buffer; // Buffer used to put multibytes encoded using unicode (wchar_t) + int32_t code; + int64_t numOfRows; // num of results in current retrieved + int64_t numOfTotal; // num of total results + int64_t numOfTotalInCurrentClause; // num of total result in current subclause + char * pRsp; + int rspType; + int rspLen; + uint64_t qhandle; + int64_t uid; + int64_t useconds; + int64_t offset; // offset value from vnode during projection query of stable + int row; + int16_t numOfCols; + int16_t precision; + int32_t numOfGroups; + SResRec * pGroupRec; + char * data; + void ** tsrow; + char ** buffer; // Buffer used to put multibytes encoded using unicode (wchar_t) + SColumnIndex *pColumnIndex; struct SLocalReducer *pLocalReducer; - SColumnIndex * pColumnIndex; } SSqlRes; typedef struct _tsc_obj { @@ -400,19 +400,17 @@ int taos_retrieve(TAOS_RES *res); int32_t tscTansformSQLFunctionForSTableQuery(SQueryInfo *pQueryInfo); void tscRestoreSQLFunctionForMetricQuery(SQueryInfo *pQueryInfo); -void tscClearSqlMetaInfoForce(SSqlCmd *pCmd); - int32_t tscCreateResPointerInfo(SSqlRes *pRes, SQueryInfo *pQueryInfo); void tscDestroyResPointerInfo(SSqlRes *pRes); void tscFreeSqlCmdData(SSqlCmd *pCmd); -void tscFreeResData(SSqlObj* pSql); +void tscFreeResData(SSqlObj *pSql); /** * free query result of the sql object * @param pObj */ -void tscFreeSqlResult(SSqlObj* pSql); +void tscFreeSqlResult(SSqlObj *pSql); /** * only free part of resources allocated during query. diff --git a/src/client/src/tscAst.c b/src/client/src/tscAst.c index f34067006ac50bb0261c10f2cf0f74f68126ce29..22100bc1d17c71af57b1230e2421e135b0c9eec6 100644 --- a/src/client/src/tscAst.c +++ b/src/client/src/tscAst.c @@ -158,7 +158,7 @@ static tSQLSyntaxNode *tSQLSyntaxNodeCreate(SSchema *pSchema, int32_t numOfCols, return pNode; } -static uint8_t getBinaryExprOptr(SSQLToken *pToken) { +uint8_t getBinaryExprOptr(SSQLToken *pToken) { switch (pToken->type) { case TK_LT: return TSDB_RELATION_LESS; @@ -183,6 +183,7 @@ static uint8_t getBinaryExprOptr(SSQLToken *pToken) { case TK_STAR: return TSDB_BINARY_OP_MULTIPLY; case TK_SLASH: + case TK_DIVIDE: return TSDB_BINARY_OP_DIVIDE; case TK_REM: return TSDB_BINARY_OP_REMAINDER; diff --git a/src/client/src/tscAsync.c b/src/client/src/tscAsync.c index fddca2bc89952b08b1a86caa3c0874a75f4aa503..9528097d207f7d2546c3702f2c2712591fb81cc6 100644 --- a/src/client/src/tscAsync.c +++ b/src/client/src/tscAsync.c @@ -284,8 +284,15 @@ void tscAsyncFetchSingleRowProxy(void *param, TAOS_RES *tres, int numOfRows) { return; } - for (int i = 0; i < pCmd->numOfCols; ++i) - pRes->tsrow[i] = TSC_GET_RESPTR_BASE(pRes, pQueryInfo, i, pQueryInfo->order) + pRes->bytes[i] * pRes->row; + for (int i = 0; i < pCmd->numOfCols; ++i){ + SSqlExpr* pExpr = pQueryInfo->fieldsInfo.pSqlExpr[i]; + if (pExpr != NULL) { + pRes->tsrow[i] = TSC_GET_RESPTR_BASE(pRes, pQueryInfo, i) + pExpr->resBytes * pRes->row; + } else { + //todo add + } + } + pRes->row++; (*pSql->fetchFp)(pSql->param, pSql, pSql->res.tsrow); @@ -299,7 +306,12 @@ void tscProcessFetchRow(SSchedMsg *pMsg) { SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); for (int i = 0; i < pCmd->numOfCols; ++i) { - pRes->tsrow[i] = TSC_GET_RESPTR_BASE(pRes, pQueryInfo, i, pQueryInfo->order) + pRes->bytes[i] * pRes->row; + SSqlExpr* pExpr = pQueryInfo->fieldsInfo.pSqlExpr[i]; + if (pExpr != NULL) { + pRes->tsrow[i] = TSC_GET_RESPTR_BASE(pRes, pQueryInfo, i) + pExpr->resBytes * pRes->row; + } else { + //todo add + } } pRes->row++; diff --git a/src/client/src/tscFunctionImpl.c b/src/client/src/tscFunctionImpl.c index 837a0ce0054b8fd7cc92a7b164f667cb6841a276..88b1fc0c28157f9023a3fbef62dabc05802cf05c 100644 --- a/src/client/src/tscFunctionImpl.c +++ b/src/client/src/tscFunctionImpl.c @@ -322,6 +322,10 @@ int32_t getResultDataInfo(int32_t dataType, int32_t dataBytes, int32_t functionI return TSDB_CODE_SUCCESS; } +bool stableQueryFunctChanged(int32_t funcId) { + return (aAggs[funcId].stableFuncId != funcId); +} + /** * the numOfRes should be kept, since it may be used later * and allow the ResultInfo to be re initialized @@ -719,12 +723,15 @@ static int32_t first_dist_data_req_info(SQLFunctionCtx *pCtx, TSKEY start, TSKEY return BLK_DATA_NO_NEEDED; } - SFirstLastInfo *pInfo = (SFirstLastInfo*) (pCtx->aOutputBuf + pCtx->inputBytes); - if (pInfo->hasResult != DATA_SET_FLAG) { - return BLK_DATA_ALL_NEEDED; - } else { // data in current block is not earlier than current result - return (pInfo->ts <= start) ? BLK_DATA_NO_NEEDED : BLK_DATA_ALL_NEEDED; - } + // result buffer has not been set yet. + return BLK_DATA_ALL_NEEDED; + //todo optimize the filter info +// SFirstLastInfo *pInfo = (SFirstLastInfo*) (pCtx->aOutputBuf + pCtx->inputBytes); +// if (pInfo->hasResult != DATA_SET_FLAG) { +// return BLK_DATA_ALL_NEEDED; +// } else { // data in current block is not earlier than current result +// return (pInfo->ts <= start) ? BLK_DATA_NO_NEEDED : BLK_DATA_ALL_NEEDED; +// } } static int32_t last_dist_data_req_info(SQLFunctionCtx *pCtx, TSKEY start, TSKEY end, int32_t colId, @@ -733,12 +740,13 @@ static int32_t last_dist_data_req_info(SQLFunctionCtx *pCtx, TSKEY start, TSKEY return BLK_DATA_NO_NEEDED; } - SFirstLastInfo *pInfo = (SFirstLastInfo*) (pCtx->aOutputBuf + pCtx->inputBytes); - if (pInfo->hasResult != DATA_SET_FLAG) { - return BLK_DATA_ALL_NEEDED; - } else { - return (pInfo->ts > end) ? BLK_DATA_NO_NEEDED : BLK_DATA_ALL_NEEDED; - } + return BLK_DATA_ALL_NEEDED; +// SFirstLastInfo *pInfo = (SFirstLastInfo*) (pCtx->aOutputBuf + pCtx->inputBytes); +// if (pInfo->hasResult != DATA_SET_FLAG) { +// return BLK_DATA_ALL_NEEDED; +// } else { +// return (pInfo->ts > end) ? BLK_DATA_NO_NEEDED : BLK_DATA_ALL_NEEDED; +// } } ////////////////////////////////////////////////////////////////////////////////////////////// @@ -1437,7 +1445,9 @@ static void stddev_next_step(SQLFunctionCtx *pCtx) { */ pStd->stage++; avg_finalizer(pCtx); - + + pResInfo->initialized = true; // set it initialized to avoid re-initialization + // save average value into tmpBuf, for second stage scan SAvgInfo *pAvg = pResInfo->interResultBuf; @@ -2184,7 +2194,7 @@ static STopBotInfo *getTopBotOutputInfo(SQLFunctionCtx *pCtx) { // only the first_stage_merge is directly written data into final output buffer if (pResInfo->superTableQ && pCtx->currentStage != SECONDARY_STAGE_MERGE) { return (STopBotInfo*) pCtx->aOutputBuf; - } else { // for normal table query and super table at the secondary_stage, result is written to intermediate buffer + } else { // during normal table query and super table at the secondary_stage, result is written to intermediate buffer return pResInfo->interResultBuf; } } @@ -3312,7 +3322,7 @@ static void arithmetic_function(SQLFunctionCtx *pCtx) { tSQLBinaryExprCalcTraverse(sas->pExpr->pBinExprInfo.pBinExpr, pCtx->size, pCtx->aOutputBuf, sas, pCtx->order, arithmetic_callback_function); - pCtx->aOutputBuf += pCtx->outputBytes * pCtx->size/* * GET_FORWARD_DIRECTION_FACTOR(pCtx->order)*/; + pCtx->aOutputBuf += pCtx->outputBytes * pCtx->size; pCtx->param[1].pz = NULL; } @@ -3573,6 +3583,7 @@ void spread_function_finalizer(SQLFunctionCtx *pCtx) { } GET_RES_INFO(pCtx)->numOfRes = 1; // todo add test case + doFinalizer(pCtx); } /* diff --git a/src/client/src/tscJoinProcess.c b/src/client/src/tscJoinProcess.c index 1bafb60f1a0e487aeaa7b70e1c1817111f8a631d..afd8e98edac4522089e0aaafa02237da67bdd1cc 100644 --- a/src/client/src/tscJoinProcess.c +++ b/src/client/src/tscJoinProcess.c @@ -100,7 +100,7 @@ static int64_t doTSBlockIntersect(SSqlObj* pSql, SJoinSubquerySupporter* pSuppor * in case of stable query, limit/offset is not applied here. the limit/offset is applied to the * final results which is acquired after the secondry merge of in the client. */ - if (pLimit->offset == 0 || pQueryInfo->nAggTimeInterval > 0 || QUERY_IS_STABLE_QUERY(pQueryInfo->type)) { + if (pLimit->offset == 0 || pQueryInfo->intervalTime > 0 || QUERY_IS_STABLE_QUERY(pQueryInfo->type)) { if (*st > elem1.ts) { *st = elem1.ts; } @@ -165,7 +165,7 @@ SJoinSubquerySupporter* tscCreateJoinSupporter(SSqlObj* pSql, SSubqueryState* pS pSupporter->subqueryIndex = index; SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, pSql->cmd.clauseIndex); - pSupporter->interval = pQueryInfo->nAggTimeInterval; + pSupporter->interval = pQueryInfo->intervalTime; pSupporter->limit = pQueryInfo->limit; SMeterMetaInfo* pMeterMetaInfo = tscGetMeterMetaInfo(&pSql->cmd, pSql->cmd.clauseIndex, index); @@ -275,6 +275,7 @@ int32_t tscLaunchSecondPhaseSubqueries(SSqlObj* pSql) { pSubQueryInfo->tsBuf = NULL; // free result for async object will also free sqlObj + assert(pSubQueryInfo->exprsInfo.numOfExprs == 1); // ts_comp query only requires one resutl columns taos_free_result(pPrevSub); SSqlObj *pNew = createSubqueryObj(pSql, (int16_t) i, tscJoinQueryCallback, pSupporter, NULL); @@ -293,24 +294,26 @@ int32_t tscLaunchSecondPhaseSubqueries(SSqlObj* pSql) { // set the second stage sub query for join process pQueryInfo->type |= TSDB_QUERY_TYPE_JOIN_SEC_STAGE; - pQueryInfo->nAggTimeInterval = pSupporter->interval; + pQueryInfo->intervalTime = pSupporter->interval; pQueryInfo->groupbyExpr = pSupporter->groupbyExpr; tscColumnBaseInfoCopy(&pQueryInfo->colList, &pSupporter->colList, 0); tscTagCondCopy(&pQueryInfo->tagCond, &pSupporter->tagCond); - tscSqlExprCopy(&pQueryInfo->exprsInfo, &pSupporter->exprsInfo, pSupporter->uid); + tscSqlExprCopy(&pQueryInfo->exprsInfo, &pSupporter->exprsInfo, pSupporter->uid, false); tscFieldInfoCopyAll(&pQueryInfo->fieldsInfo, &pSupporter->fieldsInfo); - + + pSupporter->exprsInfo.numOfExprs = 0; + pSupporter->fieldsInfo.numOfOutputCols = 0; + /* * if the first column of the secondary query is not ts function, add this function. * Because this column is required to filter with timestamp after intersecting. */ - if (pSupporter->exprsInfo.pExprs[0].functionId != TSDB_FUNC_TS) { + if (pSupporter->exprsInfo.pExprs[0]->functionId != TSDB_FUNC_TS) { tscAddTimestampColumn(pQueryInfo, TSDB_FUNC_TS, 0); } - // todo refactor function name SQueryInfo *pNewQueryInfo = tscGetQueryInfoDetail(&pNew->cmd, 0); assert(pNew->numOfSubs == 0 && pNew->cmd.numOfClause == 1 && pNewQueryInfo->numOfTables == 1); diff --git a/src/client/src/tscLocal.c b/src/client/src/tscLocal.c index 8c90554e936286432da712c77f4d70141d225882..ab57719d0979d4994e2c5ee913f21d320ca21561 100644 --- a/src/client/src/tscLocal.c +++ b/src/client/src/tscLocal.c @@ -251,6 +251,13 @@ static int32_t tscBuildMeterSchemaResultFields(SSqlObj *pSql, int32_t numOfCols, tscFieldInfoSetValue(&pQueryInfo->fieldsInfo, 3, TSDB_DATA_TYPE_BINARY, "Note", noteColLength); rowLen += noteColLength; + + //set the sqlexpr part + SColumnIndex index = {0}; + pQueryInfo->fieldsInfo.pSqlExpr[0] = tscSqlExprInsert(pQueryInfo, 0, TSDB_FUNC_TS_DUMMY, &index, TSDB_DATA_TYPE_BINARY, TSDB_COL_NAME_LEN, TSDB_COL_NAME_LEN); + pQueryInfo->fieldsInfo.pSqlExpr[1] = tscSqlExprInsert(pQueryInfo, 1, TSDB_FUNC_TS_DUMMY, &index, TSDB_DATA_TYPE_BINARY, typeColLength, typeColLength); + pQueryInfo->fieldsInfo.pSqlExpr[2] = tscSqlExprInsert(pQueryInfo, 2, TSDB_FUNC_TS_DUMMY, &index, TSDB_DATA_TYPE_INT, sizeof(int32_t), sizeof(int32_t)); + pQueryInfo->fieldsInfo.pSqlExpr[3] = tscSqlExprInsert(pQueryInfo, 3, TSDB_FUNC_TS_DUMMY, &index, TSDB_DATA_TYPE_BINARY, noteColLength, noteColLength); return rowLen; } @@ -455,6 +462,8 @@ void tscSetLocalQueryResult(SSqlObj *pSql, const char *val, const char *columnNa tscInitResObjForLocalQuery(pSql, 1, valueLength); TAOS_FIELD *pField = tscFieldInfoGetField(pQueryInfo, 0); + pQueryInfo->fieldsInfo.pSqlExpr[0] = pQueryInfo->exprsInfo.pExprs[0]; + strncpy(pRes->data, val, pField->bytes); } diff --git a/src/client/src/tscSQLParser.c b/src/client/src/tscSQLParser.c index bf0418d69068b18fa95fc2fa2db8d5b24f4e70fc..92323dcdfe05e40fd0281ca9dd0495f0230fd1e9 100644 --- a/src/client/src/tscSQLParser.c +++ b/src/client/src/tscSQLParser.c @@ -22,6 +22,7 @@ #include "tstoken.h" #include "tstrbuild.h" #include "ttime.h" +#include "tast.h" #include "tscSQLParser.h" #include "tscUtil.h" @@ -58,9 +59,9 @@ static int32_t setObjFullName(char* fullName, const char* account, SSQLToken* pD static void getColumnName(tSQLExprItem* pItem, char* resultFieldName, int32_t nameLength); static void getRevisedName(char* resultFieldName, int32_t functionId, int32_t maxLen, char* columnName); -static int32_t addExprAndResultField(SQueryInfo* pQueryInfo, int32_t colIdx, tSQLExprItem* pItem); +static int32_t addExprAndResultField(SQueryInfo* pQueryInfo, int32_t colIdx, tSQLExprItem* pItem, bool isResultColumn); static int32_t insertResultField(SQueryInfo* pQueryInfo, int32_t outputIndex, SColumnList* pIdList, int16_t bytes, - int8_t type, char* fieldName); + int8_t type, char* fieldName, SSqlExpr* pSqlExpr); static int32_t changeFunctionID(int32_t optr, int16_t* functionId); static int32_t parseSelectClause(SSqlCmd* pCmd, int32_t clauseIndex, tSQLExprList* pSelection, bool isSTable); @@ -85,7 +86,7 @@ static int32_t setAlterTableInfo(SSqlObj* pSql, struct SSqlInfo* pInfo); static int32_t validateSqlFunctionInStreamSql(SQueryInfo* pQueryInfo); static int32_t buildArithmeticExprString(tSQLExpr* pExpr, char** exprString); static int32_t validateFunctionsInIntervalOrGroupbyQuery(SQueryInfo* pQueryInfo); -static int32_t validateArithmeticSQLExpr(tSQLExpr* pExpr, SQueryInfo* pQueryInfo, SColumnList* pList); +static int32_t validateArithmeticSQLExpr(tSQLExpr* pExpr, SQueryInfo* pQueryInfo, SColumnList* pList, int32_t* type); static int32_t validateDNodeConfig(tDCLSQL* pOptions); static int32_t validateLocalConfig(tDCLSQL* pOptions); static int32_t validateColumnName(char* name); @@ -93,7 +94,6 @@ static int32_t setKillInfo(SSqlObj* pSql, struct SSqlInfo* pInfo); static bool validateOneTags(SSqlCmd* pCmd, TAOS_FIELD* pTagField); static bool hasTimestampForPointInterpQuery(SQueryInfo* pQueryInfo); -static bool hasDefaultQueryTimeRange(SQueryInfo *pQueryInfo); static void updateTagColumnIndex(SQueryInfo* pQueryInfo, int32_t tableIndex); @@ -115,6 +115,9 @@ static int32_t doCheckForCreateFromStable(SSqlObj* pSql, SSqlInfo* pInfo); static int32_t doCheckForStream(SSqlObj* pSql, SSqlInfo* pInfo); static int32_t doCheckForQuery(SSqlObj* pSql, SQuerySQL* pQuerySql, int32_t index); +static int32_t tSQLBinaryExprCreateFromSqlExpr(tSQLSyntaxNode **pExpr, tSQLExpr* pAst, int32_t* num, + SColIndexEx** pColIndex, SSqlExprInfo* pExprInfo); + /* * Used during parsing query sql. Since the query sql usually small in length, error position * is not needed in the final error message. @@ -127,7 +130,7 @@ static int32_t tscQueryOnlyMetricTags(SQueryInfo* pQueryInfo, bool* queryOnMetri assert(QUERY_IS_STABLE_QUERY(pQueryInfo->type)); *queryOnMetricTags = true; - for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, i); if (pExpr->functionId != TSDB_FUNC_TAGPRJ && @@ -203,7 +206,7 @@ int32_t tscToSQLCmd(SSqlObj* pSql, struct SSqlInfo* pInfo) { int32_t code = tscGetQueryInfoDetailSafely(pCmd, pCmd->clauseIndex, &pQueryInfo); assert(pQueryInfo->numOfTables == 0); - + SMeterMetaInfo* pMeterMetaInfo = tscAddEmptyMeterMetaInfo(pQueryInfo); pCmd->command = pInfo->type; @@ -413,7 +416,7 @@ int32_t tscToSQLCmd(SSqlObj* pSql, struct SSqlInfo* pInfo) { const char* msg3 = "name too long"; pCmd->command = pInfo->type; - //tDCLSQL* pDCL = pInfo->pDCLInfo; + // tDCLSQL* pDCL = pInfo->pDCLInfo; SUserInfo* pUser = &pInfo->pDCLInfo->user; SSQLToken* pName = &pUser->user; @@ -501,7 +504,7 @@ int32_t tscToSQLCmd(SSqlObj* pSql, struct SSqlInfo* pInfo) { case TSDB_SQL_SELECT: { assert(pCmd->numOfClause == 1); const char* msg1 = "columns in select clause not identical"; - + for (int32_t i = pCmd->numOfClause; i < pInfo->subclauseInfo.numOfClause; ++i) { SQueryInfo* pqi = NULL; if ((code = tscGetQueryInfoDetailSafely(pCmd, i, &pqi)) != TSDB_CODE_SUCCESS) { @@ -516,18 +519,18 @@ int32_t tscToSQLCmd(SSqlObj* pSql, struct SSqlInfo* pInfo) { if ((code = doCheckForQuery(pSql, pQuerySql, i)) != TSDB_CODE_SUCCESS) { return code; } - + tscPrintSelectClause(pSql, i); } - + // set the command/global limit parameters from the first subclause to the sqlcmd object SQueryInfo* pQueryInfo1 = tscGetQueryInfoDetail(pCmd, 0); pCmd->command = pQueryInfo1->command; - + // if there is only one element, the limit of clause is the limit of global result. - for(int32_t i = 1; i < pCmd->numOfClause; ++i) { + for (int32_t i = 1; i < pCmd->numOfClause; ++i) { SQueryInfo* pQueryInfo2 = tscGetQueryInfoDetail(pCmd, i); - + int32_t ret = tscFieldInfoCompare(&pQueryInfo1->fieldsInfo, &pQueryInfo2->fieldsInfo); if (ret != 0) { return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1); @@ -567,7 +570,7 @@ int32_t tscToSQLCmd(SSqlObj* pSql, struct SSqlInfo* pInfo) { * are available. */ static bool isTopBottomQuery(SQueryInfo* pQueryInfo) { - for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { int32_t functionId = tscSqlExprGet(pQueryInfo, i)->functionId; if (functionId == TSDB_FUNC_TOP || functionId == TSDB_FUNC_BOTTOM) { @@ -590,25 +593,29 @@ int32_t parseIntervalClause(SQueryInfo* pQueryInfo, SQuerySQL* pQuerySql) { // interval is not null SSQLToken* t = &pQuerySql->interval; - if (getTimestampInUsFromStr(t->z, t->n, &pQueryInfo->nAggTimeInterval) != TSDB_CODE_SUCCESS) { + if (getTimestampInUsFromStr(t->z, t->n, &pQueryInfo->intervalTime) != TSDB_CODE_SUCCESS) { return TSDB_CODE_INVALID_SQL; } // if the unit of time window value is millisecond, change the value from microsecond if (pMeterMetaInfo->pMeterMeta->precision == TSDB_TIME_PRECISION_MILLI) { - pQueryInfo->nAggTimeInterval = pQueryInfo->nAggTimeInterval / 1000; + pQueryInfo->intervalTime = pQueryInfo->intervalTime / 1000; } /* parser has filter the illegal type, no need to check here */ pQueryInfo->intervalTimeUnit = pQuerySql->interval.z[pQuerySql->interval.n - 1]; // interval cannot be less than 10 milliseconds - if (pQueryInfo->nAggTimeInterval < tsMinIntervalTime) { + if (pQueryInfo->intervalTime < tsMinIntervalTime) { return invalidSqlErrMsg(pQueryInfo->msg, msg2); } // for top/bottom + interval query, we do not add additional timestamp column in the front if (isTopBottomQuery(pQueryInfo)) { + if (parseSlidingClause(pQueryInfo, pQuerySql) != TSDB_CODE_SUCCESS) { + return TSDB_CODE_INVALID_SQL; + } + return TSDB_CODE_SUCCESS; } @@ -616,18 +623,18 @@ int32_t parseIntervalClause(SQueryInfo* pQueryInfo, SQuerySQL* pQuerySql) { * check invalid SQL: * select count(tbname)/count(tag1)/count(tag2) from super_table_name interval(1d); */ - for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, i); if (pExpr->functionId == TSDB_FUNC_COUNT && TSDB_COL_IS_TAG(pExpr->colInfo.flag)) { return invalidSqlErrMsg(pQueryInfo->msg, msg1); } } - + /* * check invalid SQL: * select tbname, tags_fields from super_table_name interval(1s) */ - if (tscQueryMetricTags(pQueryInfo) && pQueryInfo->nAggTimeInterval > 0) { + if (tscQueryMetricTags(pQueryInfo) && pQueryInfo->intervalTime > 0) { return invalidSqlErrMsg(pQueryInfo->msg, msg1); } @@ -648,19 +655,20 @@ int32_t parseIntervalClause(SQueryInfo* pQueryInfo, SQuerySQL* pQuerySql) { } SColumnIndex index = {tableIndex, PRIMARYKEY_TIMESTAMP_COL_INDEX}; - tscSqlExprInsert(pQueryInfo, 0, TSDB_FUNC_TS, &index, TSDB_DATA_TYPE_TIMESTAMP, TSDB_KEYSIZE, TSDB_KEYSIZE); + SSqlExpr* pExpr = tscSqlExprInsert(pQueryInfo, 0, TSDB_FUNC_TS, &index, TSDB_DATA_TYPE_TIMESTAMP, TSDB_KEYSIZE, TSDB_KEYSIZE); SColumnList ids = getColumnList(1, 0, PRIMARYKEY_TIMESTAMP_COL_INDEX); - int32_t ret = insertResultField(pQueryInfo, 0, &ids, TSDB_KEYSIZE, TSDB_DATA_TYPE_TIMESTAMP, aAggs[TSDB_FUNC_TS].aName); + int32_t ret = + insertResultField(pQueryInfo, 0, &ids, TSDB_KEYSIZE, TSDB_DATA_TYPE_TIMESTAMP, aAggs[TSDB_FUNC_TS].aName, pExpr); if (ret != TSDB_CODE_SUCCESS) { return ret; } - + if (parseSlidingClause(pQueryInfo, pQuerySql) != TSDB_CODE_SUCCESS) { return TSDB_CODE_INVALID_SQL; } - + return TSDB_CODE_SUCCESS; } @@ -672,20 +680,20 @@ int32_t parseSlidingClause(SQueryInfo* pQueryInfo, SQuerySQL* pQuerySql) { SSQLToken* pSliding = &pQuerySql->sliding; if (pSliding->n != 0) { - getTimestampInUsFromStr(pSliding->z, pSliding->n, &pQueryInfo->nSlidingTime); + getTimestampInUsFromStr(pSliding->z, pSliding->n, &pQueryInfo->slidingTime); if (pMeterMetaInfo->pMeterMeta->precision == TSDB_TIME_PRECISION_MILLI) { - pQueryInfo->nSlidingTime /= 1000; + pQueryInfo->slidingTime /= 1000; } - if (pQueryInfo->nSlidingTime < tsMinSlidingTime) { + if (pQueryInfo->slidingTime < tsMinSlidingTime) { return invalidSqlErrMsg(pQueryInfo->msg, msg0); } - if (pQueryInfo->nSlidingTime > pQueryInfo->nAggTimeInterval) { + if (pQueryInfo->slidingTime > pQueryInfo->intervalTime) { return invalidSqlErrMsg(pQueryInfo->msg, msg1); } } else { - pQueryInfo->nSlidingTime = -1; + pQueryInfo->slidingTime = pQueryInfo->intervalTime; } return TSDB_CODE_SUCCESS; @@ -699,11 +707,11 @@ int32_t setMeterID(SMeterMetaInfo* pMeterMetaInfo, SSQLToken* pzTableName, SSqlO // backup the old name in pMeterMetaInfo size_t size = strlen(pMeterMetaInfo->name); - char* oldName = NULL; + char* oldName = NULL; if (size > 0) { oldName = strdup(pMeterMetaInfo->name); } - + if (hasSpecifyDB(pzTableName)) { // db has been specified in sql string so we ignore current db path code = setObjFullName(pMeterMetaInfo->name, getAccountId(pSql), NULL, pzTableName, NULL); @@ -722,7 +730,7 @@ int32_t setMeterID(SMeterMetaInfo* pMeterMetaInfo, SSQLToken* pzTableName, SSqlO free(oldName); return code; } - + /* * the old name exists and is not equalled to the new name. Release the metermeta/metricmeta * that are corresponding to the old name for the new table name. @@ -734,7 +742,7 @@ int32_t setMeterID(SMeterMetaInfo* pMeterMetaInfo, SSQLToken* pzTableName, SSqlO } else { assert(pMeterMetaInfo->pMeterMeta == NULL && pMeterMetaInfo->pMetricMeta == NULL); } - + tfree(oldName); return TSDB_CODE_SUCCESS; } @@ -881,7 +889,7 @@ bool validateOneTags(SSqlCmd* pCmd, TAOS_FIELD* pTagField) { const char* msg6 = "invalid data type in tags"; assert(pCmd->numOfClause == 1); - + SMeterMetaInfo* pMeterMetaInfo = tscGetMeterMetaInfo(pCmd, pCmd->clauseIndex, 0); STableMeta* pMeterMeta = pMeterMetaInfo->pMeterMeta; @@ -1099,11 +1107,11 @@ int32_t parseSelectClause(SSqlCmd* pCmd, int32_t clauseIndex, tSQLExprList* pSel const char* msg3 = "not support query expression"; const char* msg4 = "columns from different table mixed up in arithmetic expression"; const char* msg5 = "invalid function name"; - + SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, clauseIndex); for (int32_t i = 0; i < pSelection->nExpr; ++i) { - int32_t outputIndex = pQueryInfo->fieldsInfo.numOfOutputCols; + int32_t outputIndex = pQueryInfo->exprsInfo.numOfExprs; tSQLExprItem* pItem = &pSelection->a[i]; // project on all fields @@ -1115,7 +1123,6 @@ int32_t parseSelectClause(SSqlCmd* pCmd, int32_t clauseIndex, tSQLExprList* pSel // if the name of column is quoted, remove it and set the right information for later process extractColumnNameFromString(pItem); - pQueryInfo->type |= TSDB_QUERY_TYPE_PROJECTION_QUERY; // select table_name1.field_name1, table_name2.field_name2 from table_name1, table_name2 @@ -1124,45 +1131,94 @@ int32_t parseSelectClause(SSqlCmd* pCmd, int32_t clauseIndex, tSQLExprList* pSel } } else if (pItem->pNode->nSQLOptr >= TK_COUNT && pItem->pNode->nSQLOptr <= TK_AVG_IRATE) { // sql function in selection clause, append sql function info in pSqlCmd structure sequentially - if (addExprAndResultField(pQueryInfo, outputIndex, pItem) != TSDB_CODE_SUCCESS) { + if (addExprAndResultField(pQueryInfo, outputIndex, pItem, true) != TSDB_CODE_SUCCESS) { return TSDB_CODE_INVALID_SQL; } } else if (pItem->pNode->nSQLOptr >= TK_PLUS && pItem->pNode->nSQLOptr <= TK_REM) { - // arithmetic function in select + // arithmetic function in select clause SColumnList columnList = {0}; - if (validateArithmeticSQLExpr(pItem->pNode, pQueryInfo, &columnList) != TSDB_CODE_SUCCESS) { + int32_t arithmeticType = NON_ARITHMEIC_EXPR; + + if (validateArithmeticSQLExpr(pItem->pNode, pQueryInfo, &columnList, &arithmeticType) != TSDB_CODE_SUCCESS) { return invalidSqlErrMsg(pQueryInfo->msg, msg1); } int32_t tableIndex = columnList.ids[0].tableIndex; - for(int32_t f = 1; f < columnList.num; ++f) { - if (columnList.ids[f].tableIndex != tableIndex) { - return invalidSqlErrMsg(pQueryInfo->msg, msg4); - } - } - char arithmeticExprStr[1024] = {0}; char* p = arithmeticExprStr; - - if (buildArithmeticExprString(pItem->pNode, &p) != TSDB_CODE_SUCCESS) { - return TSDB_CODE_INVALID_SQL; - } - - // expr string is set as the parameter of function - SColumnIndex index = {.tableIndex = tableIndex}; - SSqlExpr* pExpr = tscSqlExprInsert(pQueryInfo, outputIndex, TSDB_FUNC_ARITHM, &index, TSDB_DATA_TYPE_DOUBLE, - sizeof(double), sizeof(double)); - addExprParams(pExpr, arithmeticExprStr, TSDB_DATA_TYPE_BINARY, strlen(arithmeticExprStr), index.tableIndex); - - /* todo alias name should use the original sql string */ - if (pItem->aliasName != NULL) { - strncpy(pExpr->aliasName, pItem->aliasName, TSDB_COL_NAME_LEN); + + if (arithmeticType == NORMAL_ARITHMETIC) { + pQueryInfo->type |= TSDB_QUERY_TYPE_PROJECTION_QUERY; + + // all columns in arithmetic expression must belong to the same table + for (int32_t f = 1; f < columnList.num; ++f) { + if (columnList.ids[f].tableIndex != tableIndex) { + return invalidSqlErrMsg(pQueryInfo->msg, msg4); + } + } + + if (buildArithmeticExprString(pItem->pNode, &p) != TSDB_CODE_SUCCESS) { + return TSDB_CODE_INVALID_SQL; + } + + // expr string is set as the parameter of function + SColumnIndex index = {.tableIndex = tableIndex}; + SSqlExpr* pExpr = tscSqlExprInsert(pQueryInfo, outputIndex, TSDB_FUNC_ARITHM, &index, TSDB_DATA_TYPE_DOUBLE, + sizeof(double), sizeof(double)); + addExprParams(pExpr, arithmeticExprStr, TSDB_DATA_TYPE_BINARY, strlen(arithmeticExprStr), index.tableIndex); + + /* todo alias name should use the original sql string */ + char* name = (pItem->aliasName != NULL)? pItem->aliasName:arithmeticExprStr; + strncpy(pExpr->aliasName, name, TSDB_COL_NAME_LEN); + + insertResultField(pQueryInfo, i, &columnList, sizeof(double), TSDB_DATA_TYPE_DOUBLE, pExpr->aliasName, pExpr); } else { - strncpy(pExpr->aliasName, arithmeticExprStr, TSDB_COL_NAME_LEN); + columnList.num = 0; + columnList.ids[0] = (SColumnIndex) {0, 0}; + + insertResultField(pQueryInfo, i, &columnList, sizeof(double), TSDB_DATA_TYPE_DOUBLE, "abc", NULL); + + int32_t slot = tscNumOfFields(pQueryInfo) - 1; + + if (pQueryInfo->fieldsInfo.pExpr[slot] == NULL) { + SSqlFunctionExpr* pFuncExpr = calloc(1, sizeof(SSqlFunctionExpr)); + tscFieldInfoSetBinExpr(&pQueryInfo->fieldsInfo, slot, pFuncExpr); + + // arithmetic expression always return result in the format of double float + pFuncExpr->resBytes = sizeof(double); + pFuncExpr->interResBytes = sizeof(double); + pFuncExpr->resType = TSDB_DATA_TYPE_DOUBLE; + + SSqlBinaryExprInfo* pBinExprInfo = &pFuncExpr->pBinExprInfo; + + tSQLSyntaxNode* pNode = NULL; + SColIndexEx* pColIndex = NULL; + + int32_t ret = tSQLBinaryExprCreateFromSqlExpr(&pNode, pItem->pNode, &pBinExprInfo->numOfCols, &pColIndex, &pQueryInfo->exprsInfo); + if (ret != TSDB_CODE_SUCCESS) { + tSQLBinaryExprDestroy(&pNode->pExpr, NULL); + return invalidSqlErrMsg(pQueryInfo->msg, "invalid expression in select clause"); + } + + pBinExprInfo->pBinExpr = pNode->pExpr; + pBinExprInfo->pReqColumns = pColIndex; + + for(int32_t k = 0; k < pBinExprInfo->numOfCols; ++k) { + SColIndexEx* pCol = &pBinExprInfo->pReqColumns[k]; + for(int32_t f = 0; f < pQueryInfo->exprsInfo.numOfExprs; ++f) { + SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, f); + if (strcmp(pExpr->aliasName, pCol->name) == 0) { + pCol->colIdxInBuf = f; + break; + } + } + + assert(pCol->colIdxInBuf >= 0 && pCol->colIdxInBuf < pQueryInfo->exprsInfo.numOfExprs); + tfree(pNode); + } + } } - - insertResultField(pQueryInfo, i, &columnList, sizeof(double), TSDB_DATA_TYPE_DOUBLE, pExpr->aliasName); } else { /* * not support such expression @@ -1184,7 +1240,7 @@ int32_t parseSelectClause(SSqlCmd* pCmd, int32_t clauseIndex, tSQLExprList* pSel pQueryInfo->type |= TSDB_QUERY_TYPE_STABLE_QUERY; SMeterMetaInfo* pMeterMetaInfo = tscGetMeterMetaInfoFromQueryInfo(pQueryInfo, 0); - if (tscQueryMetricTags(pQueryInfo)) { // local handle the metric tag query + if (tscQueryMetricTags(pQueryInfo)) { // local handle the metric tag query pCmd->count = pMeterMetaInfo->pMeterMeta->numOfColumns; // the number of meter schema, tricky. pQueryInfo->command = TSDB_SQL_RETRIEVE_TAGS; } @@ -1203,13 +1259,15 @@ int32_t parseSelectClause(SSqlCmd* pCmd, int32_t clauseIndex, tSQLExprList* pSel return TSDB_CODE_SUCCESS; } -int32_t insertResultField(SQueryInfo* pQueryInfo, int32_t outputIndex, SColumnList* pIdList, int16_t bytes, int8_t type, - char* fieldName) { +int32_t insertResultField(SQueryInfo* pQueryInfo, int32_t outputIndex, SColumnList* pIdList, int16_t bytes, + int8_t type, char* fieldName, SSqlExpr* pSqlExpr) { for (int32_t i = 0; i < pIdList->num; ++i) { tscColumnBaseInfoInsert(pQueryInfo, &(pIdList->ids[i])); } tscFieldInfoSetValue(&pQueryInfo->fieldsInfo, outputIndex, type, fieldName, bytes); + tscFieldInfoSetExpr(&pQueryInfo->fieldsInfo, outputIndex, pSqlExpr); + return TSDB_CODE_SUCCESS; } @@ -1272,7 +1330,8 @@ static void addProjectQueryCol(SQueryInfo* pQueryInfo, int32_t startPos, SColumn SSchema* pSchema = tsGetColumnSchema(pMeterMeta, pIndex->columnIndex); char* colName = (pItem->aliasName == NULL) ? pSchema->name : pItem->aliasName; - + strncpy(pExpr->aliasName, colName, tListLen(pExpr->aliasName)); + SColumnList ids = {0}; ids.num = 1; ids.ids[0] = *pIndex; @@ -1281,7 +1340,7 @@ static void addProjectQueryCol(SQueryInfo* pQueryInfo, int32_t startPos, SColumn ids.num = 0; } - insertResultField(pQueryInfo, startPos, &ids, pExpr->resBytes, pExpr->resType, colName); + insertResultField(pQueryInfo, startPos, &ids, pExpr->resBytes, pExpr->resType, pExpr->aliasName, pExpr); } void tscAddSpecialColumnForSelect(SQueryInfo* pQueryInfo, int32_t outputColIndex, int16_t functionId, @@ -1294,7 +1353,7 @@ void tscAddSpecialColumnForSelect(SQueryInfo* pQueryInfo, int32_t outputColIndex ids.num = 0; } - insertResultField(pQueryInfo, outputColIndex, &ids, pColSchema->bytes, pColSchema->type, pColSchema->name); + insertResultField(pQueryInfo, outputColIndex, &ids, pColSchema->bytes, pColSchema->type, pColSchema->name, pExpr); pExpr->colInfo.flag = flag; if (TSDB_COL_IS_TAG(flag)) { @@ -1316,7 +1375,8 @@ static int32_t doAddProjectionExprAndResultFields(SQueryInfo* pQueryInfo, SColum } for (int32_t j = 0; j < numOfTotalColumns; ++j) { - doAddProjectCol(pQueryInfo, startPos + j, j, pIndex->tableIndex); + SSqlExpr* pExpr = doAddProjectCol(pQueryInfo, startPos + j, j, pIndex->tableIndex); + strncpy(pExpr->aliasName, pSchema[j].name, tListLen(pExpr->aliasName)); pIndex->columnIndex = j; SColumnList ids = {0}; @@ -1325,7 +1385,7 @@ static int32_t doAddProjectionExprAndResultFields(SQueryInfo* pQueryInfo, SColum // tag columns do not add to source list ids.num = (j >= pMeterMeta->numOfColumns) ? 0 : 1; - insertResultField(pQueryInfo, startPos + j, &ids, pSchema[j].bytes, pSchema[j].type, pSchema[j].name); + insertResultField(pQueryInfo, startPos + j, &ids, pSchema[j].bytes, pSchema[j].type, pSchema[j].name, pExpr); } return numOfTotalColumns; @@ -1335,7 +1395,7 @@ int32_t addProjectionExprAndResultField(SQueryInfo* pQueryInfo, tSQLExprItem* pI const char* msg0 = "invalid column name"; const char* msg1 = "tag for table query is not allowed"; - int32_t startPos = pQueryInfo->fieldsInfo.numOfOutputCols; + int32_t startPos = pQueryInfo->exprsInfo.numOfExprs; if (pItem->pNode->nSQLOptr == TK_ALL) { // project on all fields SColumnIndex index = COLUMN_INDEX_INITIALIZER; @@ -1411,9 +1471,10 @@ static int32_t setExprInfoForFunctions(SQueryInfo* pQueryInfo, SSchema* pSchema, } else { getRevisedName(columnName, functionID, TSDB_COL_NAME_LEN, pSchema[pColIndex->columnIndex].name); } - - tscSqlExprInsert(pQueryInfo, resColIdx, functionID, pColIndex, type, bytes, bytes); - + + SSqlExpr* pExpr = tscSqlExprInsert(pQueryInfo, resColIdx, functionID, pColIndex, type, bytes, bytes); + strncpy(pExpr->aliasName, columnName, tListLen(pExpr->aliasName)); + // for point interpolation/last_row query, we need the timestamp column to be loaded SColumnIndex index = {.tableIndex = pColIndex->tableIndex, .columnIndex = PRIMARYKEY_TIMESTAMP_COL_INDEX}; if (functionID == TSDB_FUNC_INTERP || functionID == TSDB_FUNC_LAST_ROW) { @@ -1421,12 +1482,12 @@ static int32_t setExprInfoForFunctions(SQueryInfo* pQueryInfo, SSchema* pSchema, } SColumnList ids = getColumnList(1, pColIndex->tableIndex, pColIndex->columnIndex); - insertResultField(pQueryInfo, resColIdx, &ids, bytes, type, columnName); + insertResultField(pQueryInfo, resColIdx, &ids, bytes, type, columnName, pExpr); return TSDB_CODE_SUCCESS; } -int32_t addExprAndResultField(SQueryInfo* pQueryInfo, int32_t colIdx, tSQLExprItem* pItem) { +int32_t addExprAndResultField(SQueryInfo* pQueryInfo, int32_t colIdx, tSQLExprItem* pItem, bool finalResult) { SMeterMetaInfo* pMeterMetaInfo = NULL; int32_t optr = pItem->pNode->nSQLOptr; @@ -1449,6 +1510,7 @@ int32_t addExprAndResultField(SQueryInfo* pQueryInfo, int32_t colIdx, tSQLExprIt return TSDB_CODE_INVALID_SQL; } + SSqlExpr* pExpr = NULL; SColumnIndex index = COLUMN_INDEX_INITIALIZER; if (pItem->pNode->pParam != NULL) { @@ -1469,7 +1531,7 @@ int32_t addExprAndResultField(SQueryInfo* pQueryInfo, int32_t colIdx, tSQLExprIt index = (SColumnIndex){0, PRIMARYKEY_TIMESTAMP_COL_INDEX}; int32_t size = tDataTypeDesc[TSDB_DATA_TYPE_BIGINT].nSize; - tscSqlExprInsert(pQueryInfo, colIdx, functionID, &index, TSDB_DATA_TYPE_BIGINT, size, size); + pExpr = tscSqlExprInsert(pQueryInfo, colIdx, functionID, &index, TSDB_DATA_TYPE_BIGINT, size, size); } else { // count the number of meters created according to the metric if (getColumnIndexByName(pToken, pQueryInfo, &index) != TSDB_CODE_SUCCESS) { @@ -1484,22 +1546,28 @@ int32_t addExprAndResultField(SQueryInfo* pQueryInfo, int32_t colIdx, tSQLExprIt } int32_t size = tDataTypeDesc[TSDB_DATA_TYPE_BIGINT].nSize; - tscSqlExprInsert(pQueryInfo, colIdx, functionID, &index, TSDB_DATA_TYPE_BIGINT, size, size); + pExpr = tscSqlExprInsert(pQueryInfo, colIdx, functionID, &index, TSDB_DATA_TYPE_BIGINT, size, size); } } else { // count(*) is equalled to count(primary_timestamp_key) index = (SColumnIndex){0, PRIMARYKEY_TIMESTAMP_COL_INDEX}; int32_t size = tDataTypeDesc[TSDB_DATA_TYPE_BIGINT].nSize; - tscSqlExprInsert(pQueryInfo, colIdx, functionID, &index, TSDB_DATA_TYPE_BIGINT, size, size); + pExpr = tscSqlExprInsert(pQueryInfo, colIdx, functionID, &index, TSDB_DATA_TYPE_BIGINT, size, size); } - - char columnName[TSDB_COL_NAME_LEN] = {0}; - getColumnName(pItem, columnName, TSDB_COL_NAME_LEN); - - // count always use the primary timestamp key column, which is 0. + + memset(pExpr->aliasName, 0, tListLen(pExpr->aliasName)); + getColumnName(pItem, pExpr->aliasName, TSDB_COL_NAME_LEN); + SColumnList ids = getColumnList(1, index.tableIndex, index.columnIndex); - - insertResultField(pQueryInfo, colIdx, &ids, sizeof(int64_t), TSDB_DATA_TYPE_BIGINT, columnName); + if (finalResult) { + int32_t numOfOutput = tscNumOfFields(pQueryInfo); + insertResultField(pQueryInfo, numOfOutput, &ids, sizeof(int64_t), TSDB_DATA_TYPE_BIGINT, pExpr->aliasName, pExpr); + } else { + for (int32_t i = 0; i < ids.num; ++i) { + tscColumnBaseInfoInsert(pQueryInfo, &(ids.ids[i])); + } + } + return TSDB_CODE_SUCCESS; } case TK_SUM: @@ -1543,9 +1611,6 @@ int32_t addExprAndResultField(SQueryInfo* pQueryInfo, int32_t colIdx, tSQLExprIt return invalidSqlErrMsg(pQueryInfo->msg, msg1); } - char columnName[TSDB_COL_NAME_LEN] = {0}; - getColumnName(pItem, columnName, TSDB_COL_NAME_LEN); - int16_t resultType = 0; int16_t resultSize = 0; int16_t intermediateResSize = 0; @@ -1564,11 +1629,11 @@ int32_t addExprAndResultField(SQueryInfo* pQueryInfo, int32_t colIdx, tSQLExprIt if (optr == TK_DIFF) { colIdx += 1; SColumnIndex indexTS = {.tableIndex = index.tableIndex, .columnIndex = 0}; - tscSqlExprInsert(pQueryInfo, 0, TSDB_FUNC_TS_DUMMY, &indexTS, TSDB_DATA_TYPE_TIMESTAMP, TSDB_KEYSIZE, + SSqlExpr* pExpr = tscSqlExprInsert(pQueryInfo, 0, TSDB_FUNC_TS_DUMMY, &indexTS, TSDB_DATA_TYPE_TIMESTAMP, TSDB_KEYSIZE, TSDB_KEYSIZE); SColumnList ids = getColumnList(1, 0, 0); - insertResultField(pQueryInfo, 0, &ids, TSDB_KEYSIZE, TSDB_DATA_TYPE_TIMESTAMP, aAggs[TSDB_FUNC_TS_DUMMY].aName); + insertResultField(pQueryInfo, 0, &ids, TSDB_KEYSIZE, TSDB_DATA_TYPE_TIMESTAMP, aAggs[TSDB_FUNC_TS_DUMMY].aName, pExpr); } // functions can not be applied to tags @@ -1598,8 +1663,18 @@ int32_t addExprAndResultField(SQueryInfo* pQueryInfo, int32_t colIdx, tSQLExprIt SColumnList ids = {0}; ids.num = 1; ids.ids[0] = index; - - insertResultField(pQueryInfo, colIdx, &ids, pExpr->resBytes, pExpr->resType, columnName); + + memset(pExpr->aliasName, 0, tListLen(pExpr->aliasName)); + getColumnName(pItem, pExpr->aliasName, TSDB_COL_NAME_LEN); + + if (finalResult) { + int32_t numOfOutput = tscNumOfFields(pQueryInfo); + insertResultField(pQueryInfo, numOfOutput, &ids, pExpr->resBytes, pExpr->resType, pExpr->aliasName, pExpr); + } else { + for (int32_t i = 0; i < ids.num; ++i) { + tscColumnBaseInfoInsert(pQueryInfo, &(ids.ids[i])); + } + } return TSDB_CODE_SUCCESS; } @@ -1701,10 +1776,7 @@ int32_t addExprAndResultField(SQueryInfo* pQueryInfo, int32_t colIdx, tSQLExprIt if (pParamElem->pNode->nSQLOptr != TK_ID) { return invalidSqlErrMsg(pQueryInfo->msg, msg2); } - - char columnName[TSDB_COL_NAME_LEN] = {0}; - getColumnName(pItem, columnName, TSDB_COL_NAME_LEN); - + SColumnIndex index = COLUMN_INDEX_INITIALIZER; if (getColumnIndexByName(&pParamElem->pNode->colInfo, pQueryInfo, &index) != TSDB_CODE_SUCCESS) { return invalidSqlErrMsg(pQueryInfo->msg, msg3); @@ -1735,7 +1807,8 @@ int32_t addExprAndResultField(SQueryInfo* pQueryInfo, int32_t colIdx, tSQLExprIt int16_t resultSize = pSchema[index.columnIndex].bytes; char val[8] = {0}; - int32_t numOfAddedColumn = 1; + SSqlExpr* pExpr = NULL; + if (optr == TK_PERCENTILE || optr == TK_APERCENTILE) { tVariantDump(pVariant, val, TSDB_DATA_TYPE_DOUBLE); @@ -1757,7 +1830,7 @@ int32_t addExprAndResultField(SQueryInfo* pQueryInfo, int32_t colIdx, tSQLExprIt return TSDB_CODE_INVALID_SQL; } - SSqlExpr* pExpr = tscSqlExprInsert(pQueryInfo, colIdx, functionId, &index, resultType, resultSize, resultSize); + pExpr = tscSqlExprInsert(pQueryInfo, colIdx, functionId, &index, resultType, resultSize, resultSize); addExprParams(pExpr, val, TSDB_DATA_TYPE_DOUBLE, sizeof(double), 0); } else { tVariantDump(pVariant, val, TSDB_DATA_TYPE_BIGINT); @@ -1774,22 +1847,30 @@ int32_t addExprAndResultField(SQueryInfo* pQueryInfo, int32_t colIdx, tSQLExprIt // set the first column ts for top/bottom query SColumnIndex index1 = {0, PRIMARYKEY_TIMESTAMP_COL_INDEX}; - tscSqlExprInsert(pQueryInfo, 0, TSDB_FUNC_TS, &index1, TSDB_DATA_TYPE_TIMESTAMP, TSDB_KEYSIZE, TSDB_KEYSIZE); + pExpr = tscSqlExprInsert(pQueryInfo, 0, TSDB_FUNC_TS, &index1, TSDB_DATA_TYPE_TIMESTAMP, TSDB_KEYSIZE, TSDB_KEYSIZE); const int32_t TS_COLUMN_INDEX = 0; SColumnList ids = getColumnList(1, 0, TS_COLUMN_INDEX); insertResultField(pQueryInfo, TS_COLUMN_INDEX, &ids, TSDB_KEYSIZE, TSDB_DATA_TYPE_TIMESTAMP, - aAggs[TSDB_FUNC_TS].aName); + aAggs[TSDB_FUNC_TS].aName, pExpr); colIdx += 1; // the first column is ts - numOfAddedColumn += 1; - SSqlExpr* pExpr = tscSqlExprInsert(pQueryInfo, colIdx, functionId, &index, resultType, resultSize, resultSize); + pExpr = tscSqlExprInsert(pQueryInfo, colIdx, functionId, &index, resultType, resultSize, resultSize); addExprParams(pExpr, val, TSDB_DATA_TYPE_BIGINT, sizeof(int64_t), 0); } - + + memset(pExpr->aliasName, 0, tListLen(pExpr->aliasName)); + getColumnName(pItem, pExpr->aliasName, TSDB_COL_NAME_LEN); + SColumnList ids = getColumnList(1, 0, index.columnIndex); - insertResultField(pQueryInfo, colIdx, &ids, resultSize, resultType, columnName); + if (finalResult) { + insertResultField(pQueryInfo, colIdx, &ids, resultSize, resultType, pExpr->aliasName, pExpr); + } else { + for (int32_t i = 0; i < ids.num; ++i) { + tscColumnBaseInfoInsert(pQueryInfo, &(ids.ids[i])); + } + } return TSDB_CODE_SUCCESS; } @@ -2036,7 +2117,7 @@ int32_t setShowInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) { SSqlCmd* pCmd = &pSql->cmd; SMeterMetaInfo* pMeterMetaInfo = tscGetMeterMetaInfo(pCmd, pCmd->clauseIndex, 0); assert(pCmd->numOfClause == 1); - + pCmd->command = TSDB_SQL_SHOW; const char* msg1 = "invalid name"; @@ -2166,16 +2247,17 @@ int32_t tscTansformSQLFunctionForSTableQuery(SQueryInfo* pQueryInfo) { int16_t type = 0; int16_t intermediateBytes = 0; - for (int32_t k = 0; k < pQueryInfo->fieldsInfo.numOfOutputCols; ++k) { + for (int32_t k = 0; k < pQueryInfo->exprsInfo.numOfExprs; ++k) { SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, k); - TAOS_FIELD* pField = tscFieldInfoGetField(pQueryInfo, k); - int16_t functionId = aAggs[pExpr->functionId].stableFuncId; + int32_t colIndex = pExpr->colInfo.colIdx; + SSchema* pSrcSchema = tsGetColumnSchema(pMeterMetaInfo->pMeterMeta, colIndex); + if ((functionId >= TSDB_FUNC_SUM && functionId <= TSDB_FUNC_TWA) || (functionId >= TSDB_FUNC_FIRST_DST && functionId <= TSDB_FUNC_LAST_DST) || (functionId >= TSDB_FUNC_RATE && functionId <= TSDB_FUNC_AVG_IRATE)) { - if (getResultDataInfo(pField->type, pField->bytes, functionId, pExpr->param[0].i64Key, &type, &bytes, + if (getResultDataInfo(pSrcSchema->type, pSrcSchema->bytes, functionId, pExpr->param[0].i64Key, &type, &bytes, &intermediateBytes, 0, true) != TSDB_CODE_SUCCESS) { return TSDB_CODE_INVALID_SQL; } @@ -2197,15 +2279,31 @@ void tscRestoreSQLFunctionForMetricQuery(SQueryInfo* pQueryInfo) { return; } - for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, i); - TAOS_FIELD* pField = tscFieldInfoGetField(pQueryInfo, i); - - if ((pExpr->functionId >= TSDB_FUNC_FIRST_DST && pExpr->functionId <= TSDB_FUNC_LAST_DST) || - (pExpr->functionId >= TSDB_FUNC_SUM && pExpr->functionId <= TSDB_FUNC_MAX)) { - pExpr->resBytes = pField->bytes; - pExpr->resType = pField->type; - } + SSchema* pSchema = tsGetColumnSchema(pMeterMetaInfo->pMeterMeta, pExpr->colInfo.colIdx); + +// if (/*(pExpr->functionId >= TSDB_FUNC_FIRST_DST && pExpr->functionId <= TSDB_FUNC_LAST_DST) || +// (pExpr->functionId >= TSDB_FUNC_SUM && pExpr->functionId <= TSDB_FUNC_MAX) || +// pExpr->functionId == TSDB_FUNC_LAST_ROW*/) { + // the final result size and type in the same as query on single table. + // so here, set the flag to be false; + int16_t inter = 0; + + int32_t functionId = pExpr->functionId; + if (functionId >= TSDB_FUNC_TS && functionId <= TSDB_FUNC_DIFF) { + continue; + } + + if (functionId == TSDB_FUNC_FIRST_DST) { + functionId = TSDB_FUNC_FIRST; + } else if (functionId == TSDB_FUNC_LAST_DST) { + functionId = TSDB_FUNC_LAST; + } + + getResultDataInfo(pSchema->type, pSchema->bytes, functionId, 0, &pExpr->resType, &pExpr->resBytes, + &inter, 0, false); +// } } } @@ -2213,9 +2311,9 @@ bool hasUnsupportFunctionsForSTableQuery(SQueryInfo* pQueryInfo) { const char* msg1 = "TWA not allowed to apply to super table directly"; const char* msg2 = "TWA only support group by tbname for super table query"; const char* msg3 = "function not support for super table query"; - + // filter sql function not supported by metric query yet. - for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { int32_t functionId = tscSqlExprGet(pQueryInfo, i)->functionId; if ((aAggs[functionId].nStatus & TSDB_FUNCSTATE_METRIC) == 0) { invalidSqlErrMsg(pQueryInfo->msg, msg3); @@ -2252,7 +2350,7 @@ static bool functionCompatibleCheck(SQueryInfo* pQueryInfo) { // diff function cannot be executed with other function // arithmetic function can be executed with other arithmetic functions - for (int32_t i = startIdx + 1; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = startIdx + 1; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, i); int16_t functionId = pExpr->functionId; @@ -2554,7 +2652,13 @@ static int32_t tSQLExprNodeToString(tSQLExpr* pExpr, char** str) { } else if (pExpr->nSQLOptr >= TK_BOOL && pExpr->nSQLOptr <= TK_STRING) { // value *str += tVariantToString(&pExpr->val, *str); - } else { + } else if (pExpr->nSQLOptr >= TK_COUNT && pExpr->nSQLOptr <= TK_AVG_IRATE) { + /* + * arithmetic expression of aggregation, such as count(ts) + count(ts) *2 + */ + strncpy(*str, pExpr->operand.z, pExpr->operand.n); + *str += pExpr->operand.n; + } else { // not supported operation assert(false); } @@ -2890,8 +2994,7 @@ int32_t buildArithmeticExprString(tSQLExpr* pExpr, char** exprString) { tSQLExpr* pLeft = pExpr->pLeft; tSQLExpr* pRight = pExpr->pRight; - *(*exprString) = '('; - *exprString += 1; + *(*exprString)++ = '('; if (pLeft->nSQLOptr >= TK_PLUS && pLeft->nSQLOptr <= TK_REM) { buildArithmeticExprString(pLeft, exprString); @@ -2913,50 +3016,67 @@ int32_t buildArithmeticExprString(tSQLExpr* pExpr, char** exprString) { } } - *(*exprString) = ')'; - *exprString += 1; + *(*exprString)++ = ')'; return TSDB_CODE_SUCCESS; } -static int32_t validateSQLExpr(tSQLExpr* pExpr, SQueryInfo* pQueryInfo, SColumnList* pList) { +static int32_t validateSQLExpr(tSQLExpr* pExpr, SQueryInfo* pQueryInfo, SColumnList* pList, int32_t* type) { if (pExpr->nSQLOptr == TK_ID) { - SColumnIndex index = COLUMN_INDEX_INITIALIZER; - if (getColumnIndexByName(&pExpr->colInfo, pQueryInfo, &index) != TSDB_CODE_SUCCESS) { - return TSDB_CODE_INVALID_SQL; - } + if (*type == NON_ARITHMEIC_EXPR) { + *type = NORMAL_ARITHMETIC; + } else if (*type == AGG_ARIGHTMEIC) { + return TSDB_CODE_INVALID_SQL; + } - // if column is timestamp, bool, binary, nchar, not support arithmetic, so return invalid sql - STableMeta* pMeterMeta = tscGetMeterMetaInfoFromQueryInfo(pQueryInfo, index.tableIndex)->pMeterMeta; - SSchema* pSchema = tsGetSchema(pMeterMeta) + index.columnIndex; - if ((pSchema->type == TSDB_DATA_TYPE_TIMESTAMP) || (pSchema->type == TSDB_DATA_TYPE_BOOL) - || (pSchema->type == TSDB_DATA_TYPE_BINARY) || (pSchema->type == TSDB_DATA_TYPE_NCHAR)){ - return TSDB_CODE_INVALID_SQL; - } - - pList->ids[pList->num++] = index; + SColumnIndex index = COLUMN_INDEX_INITIALIZER; + if (getColumnIndexByName(&pExpr->colInfo, pQueryInfo, &index) != TSDB_CODE_SUCCESS) { + return TSDB_CODE_INVALID_SQL; + } + + // if column is timestamp, bool, binary, nchar, not support arithmetic, so return invalid sql + STableMeta* pMeterMeta = tscGetMeterMetaInfoFromQueryInfo(pQueryInfo, index.tableIndex)->pMeterMeta; + SSchema* pSchema = tsGetSchema(pMeterMeta) + index.columnIndex; + if ((pSchema->type == TSDB_DATA_TYPE_TIMESTAMP) || (pSchema->type == TSDB_DATA_TYPE_BOOL) || + (pSchema->type == TSDB_DATA_TYPE_BINARY) || (pSchema->type == TSDB_DATA_TYPE_NCHAR)) { + return TSDB_CODE_INVALID_SQL; + } + + pList->ids[pList->num++] = index; } else if (pExpr->nSQLOptr == TK_FLOAT && (isnan(pExpr->val.dKey) || isinf(pExpr->val.dKey))) { return TSDB_CODE_INVALID_SQL; - } else if (pExpr->nSQLOptr >= TK_MIN && pExpr->nSQLOptr <= TK_AVG_IRATE) { - return TSDB_CODE_INVALID_SQL; + } else if (pExpr->nSQLOptr >= TK_COUNT && pExpr->nSQLOptr <= TK_AVG_IRATE) { + if (*type == NON_ARITHMEIC_EXPR) { + *type = AGG_ARIGHTMEIC; + } else if (*type == NORMAL_ARITHMETIC) { + return TSDB_CODE_INVALID_SQL; + } + + int32_t outputIndex = pQueryInfo->exprsInfo.numOfExprs; + tSQLExprItem item = {.pNode = pExpr, .aliasName = NULL}; + + // sql function in selection clause, append sql function info in pSqlCmd structure sequentially + if (addExprAndResultField(pQueryInfo, outputIndex, &item, false) != TSDB_CODE_SUCCESS) { + return TSDB_CODE_INVALID_SQL; + } } return TSDB_CODE_SUCCESS; } -static int32_t validateArithmeticSQLExpr(tSQLExpr* pExpr, SQueryInfo* pQueryInfo, SColumnList* pList) { +static int32_t validateArithmeticSQLExpr(tSQLExpr* pExpr, SQueryInfo* pQueryInfo, SColumnList* pList, int32_t* type) { if (pExpr == NULL) { return TSDB_CODE_SUCCESS; } tSQLExpr* pLeft = pExpr->pLeft; if (pLeft->nSQLOptr >= TK_PLUS && pLeft->nSQLOptr <= TK_REM) { - int32_t ret = validateArithmeticSQLExpr(pLeft, pQueryInfo, pList); + int32_t ret = validateArithmeticSQLExpr(pLeft, pQueryInfo, pList, type); if (ret != TSDB_CODE_SUCCESS) { return ret; } } else { - int32_t ret = validateSQLExpr(pLeft, pQueryInfo, pList); + int32_t ret = validateSQLExpr(pLeft, pQueryInfo, pList, type); if (ret != TSDB_CODE_SUCCESS) { return ret; } @@ -2964,12 +3084,12 @@ static int32_t validateArithmeticSQLExpr(tSQLExpr* pExpr, SQueryInfo* pQueryInfo tSQLExpr* pRight = pExpr->pRight; if (pRight->nSQLOptr >= TK_PLUS && pRight->nSQLOptr <= TK_REM) { - int32_t ret = validateArithmeticSQLExpr(pRight, pQueryInfo, pList); + int32_t ret = validateArithmeticSQLExpr(pRight, pQueryInfo, pList, type); if (ret != TSDB_CODE_SUCCESS) { return ret; } } else { - int32_t ret = validateSQLExpr(pRight, pQueryInfo, pList); + int32_t ret = validateSQLExpr(pRight, pQueryInfo, pList, type); if (ret != TSDB_CODE_SUCCESS) { return ret; } @@ -3771,6 +3891,7 @@ int32_t getTimeRange(int64_t* stime, int64_t* etime, tSQLExpr* pRight, int32_t o return TSDB_CODE_SUCCESS; } +// todo error !!!! int32_t tsRewriteFieldNameIfNecessary(SQueryInfo* pQueryInfo) { const char rep[] = {'(', ')', '*', ',', '.', '/', '\\', '+', '-', '%', ' '}; @@ -3817,7 +3938,7 @@ int32_t parseFillClause(SQueryInfo* pQueryInfo, SQuerySQL* pQuerySQL) { } if (pQueryInfo->defaultVal == NULL) { - pQueryInfo->defaultVal = calloc(pQueryInfo->fieldsInfo.numOfOutputCols, sizeof(int64_t)); + pQueryInfo->defaultVal = calloc(pQueryInfo->exprsInfo.numOfExprs, sizeof(int64_t)); if (pQueryInfo->defaultVal == NULL) { return TSDB_CODE_CLI_OUT_OF_MEMORY; } @@ -3827,7 +3948,7 @@ int32_t parseFillClause(SQueryInfo* pQueryInfo, SQuerySQL* pQuerySQL) { pQueryInfo->interpoType = TSDB_INTERPO_NONE; } else if (strncasecmp(pItem->pVar.pz, "null", 4) == 0 && pItem->pVar.nLen == 4) { pQueryInfo->interpoType = TSDB_INTERPO_NULL; - for (int32_t i = START_INTERPO_COL_IDX; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = START_INTERPO_COL_IDX; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { TAOS_FIELD* pFields = tscFieldInfoGetField(pQueryInfo, i); setNull((char*)&pQueryInfo->defaultVal[i], pFields->type, pFields->bytes); } @@ -3849,12 +3970,12 @@ int32_t parseFillClause(SQueryInfo* pQueryInfo, SQuerySQL* pQuerySQL) { if (tscIsPointInterpQuery(pQueryInfo)) { startPos = 0; - if (numOfFillVal > pQueryInfo->fieldsInfo.numOfOutputCols) { - numOfFillVal = pQueryInfo->fieldsInfo.numOfOutputCols; + if (numOfFillVal > pQueryInfo->exprsInfo.numOfExprs) { + numOfFillVal = pQueryInfo->exprsInfo.numOfExprs; } } else { - numOfFillVal = (pFillToken->nExpr > pQueryInfo->fieldsInfo.numOfOutputCols) - ? pQueryInfo->fieldsInfo.numOfOutputCols + numOfFillVal = (pFillToken->nExpr > pQueryInfo->exprsInfo.numOfExprs) + ? pQueryInfo->exprsInfo.numOfExprs : pFillToken->nExpr; } @@ -3862,28 +3983,29 @@ int32_t parseFillClause(SQueryInfo* pQueryInfo, SQuerySQL* pQuerySQL) { for (int32_t i = startPos; i < numOfFillVal; ++i, ++j) { TAOS_FIELD* pFields = tscFieldInfoGetField(pQueryInfo, i); - + if (pFields->type == TSDB_DATA_TYPE_BINARY || pFields->type == TSDB_DATA_TYPE_NCHAR) { setNull((char*)(&pQueryInfo->defaultVal[i]), pFields->type, pFields->bytes); continue; } - + int32_t ret = tVariantDump(&pFillToken->a[j].pVar, (char*)&pQueryInfo->defaultVal[i], pFields->type); if (ret != TSDB_CODE_SUCCESS) { return invalidSqlErrMsg(pQueryInfo->msg, msg); } } - if ((pFillToken->nExpr < pQueryInfo->fieldsInfo.numOfOutputCols) || - ((pFillToken->nExpr - 1 < pQueryInfo->fieldsInfo.numOfOutputCols) && (tscIsPointInterpQuery(pQueryInfo)))) { + if ((pFillToken->nExpr < pQueryInfo->exprsInfo.numOfExprs) || + ((pFillToken->nExpr - 1 < pQueryInfo->exprsInfo.numOfExprs) && (tscIsPointInterpQuery(pQueryInfo)))) { tVariantListItem* lastItem = &pFillToken->a[pFillToken->nExpr - 1]; - for (int32_t i = numOfFillVal; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = numOfFillVal; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { TAOS_FIELD* pFields = tscFieldInfoGetField(pQueryInfo, i); - tVariantDump(&lastItem->pVar, (char*)&pQueryInfo->defaultVal[i], pFields->type); if (pFields->type == TSDB_DATA_TYPE_BINARY || pFields->type == TSDB_DATA_TYPE_NCHAR) { setNull((char*)(&pQueryInfo->defaultVal[i]), pFields->type, pFields->bytes); + } else { + tVariantDump(&lastItem->pVar, (char*)&pQueryInfo->defaultVal[i], pFields->type); } } } @@ -4277,11 +4399,11 @@ int32_t validateSqlFunctionInStreamSql(SQueryInfo* pQueryInfo) { const char* msg0 = "sample interval can not be less than 10ms."; const char* msg1 = "functions not allowed in select clause"; - if (pQueryInfo->nAggTimeInterval != 0 && pQueryInfo->nAggTimeInterval < 10) { + if (pQueryInfo->intervalTime != 0 && pQueryInfo->intervalTime < 10) { return invalidSqlErrMsg(pQueryInfo->msg, msg0); } - for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { int32_t functId = tscSqlExprGet(pQueryInfo, i)->functionId; if (!IS_STREAM_QUERY_VALID(aAggs[functId].nStatus)) { return invalidSqlErrMsg(pQueryInfo->msg, msg1); @@ -4296,13 +4418,13 @@ int32_t validateFunctionsInIntervalOrGroupbyQuery(SQueryInfo* pQueryInfo) { const char* msg1 = "column projection is not compatible with interval"; // multi-output set/ todo refactor - for (int32_t k = 0; k < pQueryInfo->fieldsInfo.numOfOutputCols; ++k) { + for (int32_t k = 0; k < pQueryInfo->exprsInfo.numOfExprs; ++k) { SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, k); // projection query on primary timestamp, the selectivity function needs to be present. if (pExpr->functionId == TSDB_FUNC_PRJ && pExpr->colInfo.colId == PRIMARYKEY_TIMESTAMP_COL_INDEX) { bool hasSelectivity = false; - for (int32_t j = 0; j < pQueryInfo->fieldsInfo.numOfOutputCols; ++j) { + for (int32_t j = 0; j < pQueryInfo->exprsInfo.numOfExprs; ++j) { SSqlExpr* pEx = tscSqlExprGet(pQueryInfo, j); if ((aAggs[pEx->functionId].nStatus & TSDB_FUNCSTATE_SELECTIVITY) == TSDB_FUNCSTATE_SELECTIVITY) { hasSelectivity = true; @@ -4470,13 +4592,15 @@ int32_t parseLimitClause(SQueryInfo* pQueryInfo, int32_t clauseIndex, SQuerySQL* const char* msg1 = "slimit/soffset only available for STable query"; const char* msg2 = "function not supported on table"; const char* msg3 = "slimit/soffset can not apply to projection query"; - + // handle the limit offset value, validate the limit pQueryInfo->limit = pQuerySql->limit; pQueryInfo->clauseLimit = pQueryInfo->limit.limit; - pQueryInfo->slimit = pQuerySql->slimit; - + + tscTrace("%p limit:%d, offset:%" PRId64 " slimit:%d, soffset:%" PRId64, pSql, pQueryInfo->limit.limit, + pQueryInfo->limit.offset, pQueryInfo->slimit.limit, pQueryInfo->slimit.offset); + if (pQueryInfo->slimit.offset < 0 || pQueryInfo->limit.offset < 0) { return invalidSqlErrMsg(pQueryInfo->msg, msg0); } @@ -4500,24 +4624,16 @@ int32_t parseLimitClause(SQueryInfo* pQueryInfo, int32_t clauseIndex, SQuerySQL* if (pQueryInfo->slimit.limit > 0 || pQueryInfo->slimit.offset > 0) { return invalidSqlErrMsg(pQueryInfo->msg, msg3); } - + + // for projection query on super table, all queries are subqueries if (tscNonOrderedProjectionQueryOnSTable(pQueryInfo, 0)) { -// if (pQueryInfo->order.orderColId >= 0) { -// if (pQueryInfo->limit.limit == -1) { -// return invalidSqlErrMsg(pQueryInfo->msg, msg4); -// } else if (pQueryInfo->limit.limit > 10000) { // the result set can not be larger than 10000 -// //todo use global config parameter -// return invalidSqlErrMsg(pQueryInfo->msg, msg5); -// } -// } - - pQueryInfo->type |= TSDB_QUERY_TYPE_SUBQUERY; // for projection query on super table, all queries are subqueries + pQueryInfo->type |= TSDB_QUERY_TYPE_SUBQUERY; } } } if (pQueryInfo->slimit.limit == 0) { - tscTrace("%p limit 0, no output result", pSql); + tscTrace("%p slimit 0, no output result", pSql); pQueryInfo->command = TSDB_SQL_RETRIEVE_EMPTY_RESULT; return TSDB_CODE_SUCCESS; } @@ -4543,7 +4659,7 @@ int32_t parseLimitClause(SQueryInfo* pQueryInfo, int32_t clauseIndex, SQuerySQL* // keep original limitation value in globalLimit pQueryInfo->clauseLimit = pQueryInfo->limit.limit; pQueryInfo->prjOffset = pQueryInfo->limit.offset; - + if (tscOrderedProjectionQueryOnSTable(pQueryInfo, 0)) { /* * the limitation/offset value should be removed during retrieve data from virtual node, @@ -4553,7 +4669,7 @@ int32_t parseLimitClause(SQueryInfo* pQueryInfo, int32_t clauseIndex, SQuerySQL* if (pQueryInfo->limit.limit > 0) { pQueryInfo->limit.limit = -1; } - + pQueryInfo->limit.offset = 0; } } else { @@ -4562,7 +4678,7 @@ int32_t parseLimitClause(SQueryInfo* pQueryInfo, int32_t clauseIndex, SQuerySQL* } // filter the query functions operating on "tbname" column that are not supported by normal columns. - for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, i); if (pExpr->colInfo.colIdx == TSDB_TBNAME_COLUMN_INDEX) { return invalidSqlErrMsg(pQueryInfo->msg, msg2); @@ -4677,7 +4793,7 @@ void tscAddTimestampColumn(SQueryInfo* pQueryInfo, int16_t functionId, int16_t t // NOTE: tag column does not add to source column list SColumnList ids = getColumnList(1, tableIndex, PRIMARYKEY_TIMESTAMP_COL_INDEX); - insertResultField(pQueryInfo, 0, &ids, TSDB_KEYSIZE, TSDB_DATA_TYPE_TIMESTAMP, "ts"); + insertResultField(pQueryInfo, 0, &ids, TSDB_KEYSIZE, TSDB_DATA_TYPE_TIMESTAMP, "ts", pExpr); } } @@ -4700,13 +4816,13 @@ void addGroupInfoForSubquery(SSqlObj* pParentObj, SSqlObj* pSql, int32_t subClau int16_t bytes = pSchema[index.columnIndex].bytes; char* name = pSchema[index.columnIndex].name; - pExpr = tscSqlExprInsert(pQueryInfo, pQueryInfo->fieldsInfo.numOfOutputCols, TSDB_FUNC_TAG, &index, type, bytes, + pExpr = tscSqlExprInsert(pQueryInfo, pQueryInfo->exprsInfo.numOfExprs, TSDB_FUNC_TAG, &index, type, bytes, bytes); pExpr->colInfo.flag = TSDB_COL_TAG; // NOTE: tag column does not add to source column list SColumnList ids = {0}; - insertResultField(pQueryInfo, pQueryInfo->fieldsInfo.numOfOutputCols, &ids, bytes, type, name); + insertResultField(pQueryInfo, pQueryInfo->exprsInfo.numOfExprs, &ids, bytes, type, name, pExpr); int32_t relIndex = index.columnIndex; @@ -4721,7 +4837,7 @@ void addGroupInfoForSubquery(SSqlObj* pParentObj, SSqlObj* pSql, int32_t subClau // limit the output to be 1 for each state value static void doLimitOutputNormalColOfGroupby(SSqlExpr* pExpr) { int32_t outputRow = 1; - tVariantCreateFromBinary(&pExpr->param[0], (char*) &outputRow, sizeof(int32_t), TSDB_DATA_TYPE_INT); + tVariantCreateFromBinary(&pExpr->param[0], (char*)&outputRow, sizeof(int32_t), TSDB_DATA_TYPE_INT); pExpr->numOfParams = 1; } @@ -4733,25 +4849,25 @@ void doAddGroupColumnForSubquery(SQueryInfo* pQueryInfo, int32_t tagIndex) { SSchema* pSchema = tsGetColumnSchema(pMeterMetaInfo->pMeterMeta, index); SColumnIndex colIndex = {.tableIndex = 0, .columnIndex = index}; - SSqlExpr* pExpr = tscSqlExprInsert(pQueryInfo, pQueryInfo->fieldsInfo.numOfOutputCols, TSDB_FUNC_PRJ, &colIndex, + SSqlExpr* pExpr = tscSqlExprInsert(pQueryInfo, pQueryInfo->exprsInfo.numOfExprs, TSDB_FUNC_PRJ, &colIndex, pSchema->type, pSchema->bytes, pSchema->bytes); pExpr->colInfo.flag = TSDB_COL_NORMAL; doLimitOutputNormalColOfGroupby(pExpr); - + // NOTE: tag column does not add to source column list SColumnList list = {0}; list.num = 1; list.ids[0] = colIndex; - insertResultField(pQueryInfo, pQueryInfo->fieldsInfo.numOfOutputCols, &list, pSchema->bytes, pSchema->type, - pSchema->name); - tscFieldInfoUpdateVisible(&pQueryInfo->fieldsInfo, pQueryInfo->fieldsInfo.numOfOutputCols - 1, false); + insertResultField(pQueryInfo, pQueryInfo->exprsInfo.numOfExprs - 1, &list, pSchema->bytes, pSchema->type, + pSchema->name, pExpr); + tscFieldInfoUpdateVisible(&pQueryInfo->fieldsInfo, pQueryInfo->exprsInfo.numOfExprs - 1, false); } static void doUpdateSqlFunctionForTagPrj(SQueryInfo* pQueryInfo) { int32_t tagLength = 0; - for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, i); if (pExpr->functionId == TSDB_FUNC_TAGPRJ || pExpr->functionId == TSDB_FUNC_TAG) { pExpr->functionId = TSDB_FUNC_TAG_DUMMY; @@ -4765,7 +4881,7 @@ static void doUpdateSqlFunctionForTagPrj(SQueryInfo* pQueryInfo) { SMeterMetaInfo* pMeterMetaInfo = tscGetMeterMetaInfoFromQueryInfo(pQueryInfo, 0); SSchema* pSchema = tsGetSchema(pMeterMetaInfo->pMeterMeta); - for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, i); if (pExpr->functionId != TSDB_FUNC_TAG_DUMMY && pExpr->functionId != TSDB_FUNC_TS_DUMMY) { SSchema* pColSchema = &pSchema[pExpr->colInfo.colIdx]; @@ -4776,7 +4892,7 @@ static void doUpdateSqlFunctionForTagPrj(SQueryInfo* pQueryInfo) { } static void doUpdateSqlFunctionForColPrj(SQueryInfo* pQueryInfo) { - for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, i); if (pExpr->functionId == TSDB_FUNC_PRJ) { bool qualifiedCol = false; @@ -4808,7 +4924,7 @@ static bool onlyTagPrjFunction(SQueryInfo* pQueryInfo) { bool hasTagPrj = false; bool hasColumnPrj = false; - for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, i); if (pExpr->functionId == TSDB_FUNC_PRJ) { hasColumnPrj = true; @@ -4824,7 +4940,7 @@ static bool onlyTagPrjFunction(SQueryInfo* pQueryInfo) { static bool allTagPrjInGroupby(SQueryInfo* pQueryInfo) { bool allInGroupby = true; - for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, i); if (pExpr->functionId != TSDB_FUNC_TAGPRJ) { continue; @@ -4841,7 +4957,7 @@ static bool allTagPrjInGroupby(SQueryInfo* pQueryInfo) { } static void updateTagPrjFunction(SQueryInfo* pQueryInfo) { - for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, i); if (pExpr->functionId == TSDB_FUNC_TAGPRJ) { pExpr->functionId = TSDB_FUNC_TAG; @@ -4863,7 +4979,7 @@ static int32_t checkUpdateTagPrjFunctions(SQueryInfo* pQueryInfo) { int16_t numOfSelectivity = 0; int16_t numOfAggregation = 0; - for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, i); if (pExpr->functionId == TSDB_FUNC_TAGPRJ || (pExpr->functionId == TSDB_FUNC_PRJ && pExpr->colInfo.colId == PRIMARYKEY_TIMESTAMP_COL_INDEX)) { @@ -4872,7 +4988,7 @@ static int32_t checkUpdateTagPrjFunctions(SQueryInfo* pQueryInfo) { } } - for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { int16_t functionId = tscSqlExprGet(pQueryInfo, i)->functionId; if (functionId == TSDB_FUNC_TAGPRJ || functionId == TSDB_FUNC_PRJ || functionId == TSDB_FUNC_TS || functionId == TSDB_FUNC_ARITHM) { @@ -4904,7 +5020,7 @@ static int32_t checkUpdateTagPrjFunctions(SQueryInfo* pQueryInfo) { * If more than one selectivity functions exist, all the selectivity functions must be last_row. * Otherwise, return with error code. */ - for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { int16_t functionId = tscSqlExprGet(pQueryInfo, i)->functionId; if (functionId == TSDB_FUNC_TAGPRJ) { continue; @@ -4965,22 +5081,22 @@ static int32_t doAddGroupbyColumnsOnDemand(SQueryInfo* pQueryInfo) { if (TSDB_COL_IS_TAG(pColIndex->flag)) { SColumnIndex index = {.tableIndex = pQueryInfo->groupbyExpr.tableIndex, .columnIndex = colIndex}; - SSqlExpr* pExpr = tscSqlExprInsert(pQueryInfo, pQueryInfo->fieldsInfo.numOfOutputCols, TSDB_FUNC_TAG, &index, + SSqlExpr* pExpr = tscSqlExprInsert(pQueryInfo, pQueryInfo->exprsInfo.numOfExprs, TSDB_FUNC_TAG, &index, type, bytes, bytes); pExpr->colInfo.flag = TSDB_COL_TAG; // NOTE: tag column does not add to source column list SColumnList ids = {0}; - insertResultField(pQueryInfo, pQueryInfo->fieldsInfo.numOfOutputCols, &ids, bytes, type, name); + insertResultField(pQueryInfo, pQueryInfo->exprsInfo.numOfExprs-1, &ids, bytes, type, name, pExpr); } else { // if this query is "group by" normal column, interval is not allowed - if (pQueryInfo->nAggTimeInterval > 0) { + if (pQueryInfo->intervalTime > 0) { return invalidSqlErrMsg(pQueryInfo->msg, msg2); } bool hasGroupColumn = false; - for (int32_t j = 0; j < pQueryInfo->fieldsInfo.numOfOutputCols; ++j) { + for (int32_t j = 0; j < pQueryInfo->exprsInfo.numOfExprs; ++j) { SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, j); if (pExpr->colInfo.colId == pColIndex->colId) { break; @@ -5008,7 +5124,7 @@ int32_t doFunctionsCompatibleCheck(SSqlCmd* pCmd, SQueryInfo* pQueryInfo) { // only retrieve tags, group by is not supportted if (pCmd->command == TSDB_SQL_RETRIEVE_TAGS) { - if (pQueryInfo->groupbyExpr.numOfGroupCols > 0 || pQueryInfo->nAggTimeInterval > 0) { + if (pQueryInfo->groupbyExpr.numOfGroupCols > 0 || pQueryInfo->intervalTime > 0) { return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg4); } else { return TSDB_CODE_SUCCESS; @@ -5023,7 +5139,7 @@ int32_t doFunctionsCompatibleCheck(SSqlCmd* pCmd, SQueryInfo* pQueryInfo) { } // check all query functions in selection clause, multi-output functions are not allowed - for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, i); int32_t functId = pExpr->functionId; @@ -5111,11 +5227,8 @@ int32_t doLocalQueryProcess(SQueryInfo* pQueryInfo, SQuerySQL* pQuerySql) { } SSqlExpr* pExpr1 = tscSqlExprInsertEmpty(pQueryInfo, 0, TSDB_FUNC_TAG_DUMMY); - if (pExprList->a[0].aliasName != NULL) { - strncpy(pExpr1->aliasName, pExprList->a[0].aliasName, tListLen(pExpr1->aliasName)); - } else { - strncpy(pExpr1->aliasName, functionsInfo[index].name, tListLen(pExpr1->aliasName)); - } + const char* name = (pExprList->a[0].aliasName != NULL)? pExprList->a[0].aliasName:functionsInfo[index].name; + strncpy(pExpr1->aliasName, name, tListLen(pExpr1->aliasName)); switch (index) { case 0: @@ -5220,8 +5333,8 @@ void tscPrintSelectClause(SSqlObj* pSql, int32_t subClauseIndex) { } int32_t totalBufSize = 1024; - - char str[1024] = {0}; + + char str[1024] = {0}; int32_t offset = 0; offset += sprintf(str, "num:%d [", pQueryInfo->exprsInfo.numOfExprs); @@ -5229,12 +5342,13 @@ void tscPrintSelectClause(SSqlObj* pSql, int32_t subClauseIndex) { SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, i); char tmpBuf[1024] = {0}; - int32_t tmpLen = 0; - tmpLen = sprintf(tmpBuf, "%s(uid:%" PRId64 ", %d)", aAggs[pExpr->functionId].aName, pExpr->uid, pExpr->colInfo.colId); + int32_t tmpLen = 0; + tmpLen = + sprintf(tmpBuf, "%s(uid:%" PRId64 ", %d)", aAggs[pExpr->functionId].aName, pExpr->uid, pExpr->colInfo.colId); if (tmpLen + offset > totalBufSize) break; offset += sprintf(str + offset, "%s", tmpBuf); - + if (i < pQueryInfo->exprsInfo.numOfExprs - 1) { str[offset++] = ','; } @@ -5424,7 +5538,7 @@ int32_t doCheckForStream(SSqlObj* pSql, SSqlInfo* pInfo) { if (parseIntervalClause(pQueryInfo, pQuerySql) != TSDB_CODE_SUCCESS) { return TSDB_CODE_INVALID_SQL; } else { - if ((pQueryInfo->nAggTimeInterval > 0) && + if ((pQueryInfo->intervalTime > 0) && (validateFunctionsInIntervalOrGroupbyQuery(pQueryInfo) != TSDB_CODE_SUCCESS)) { return TSDB_CODE_INVALID_SQL; } @@ -5454,7 +5568,7 @@ int32_t doCheckForStream(SSqlObj* pSql, SSqlInfo* pInfo) { * not here. */ if (pQuerySql->fillType != NULL) { - if (pQueryInfo->nAggTimeInterval == 0) { + if (pQueryInfo->intervalTime == 0) { return invalidSqlErrMsg(pQueryInfo->msg, msg3); } @@ -5493,7 +5607,7 @@ int32_t doCheckForQuery(SSqlObj* pSql, SQuerySQL* pQuerySql, int32_t index) { if (pMeterMetaInfo == NULL) { pMeterMetaInfo = tscAddEmptyMeterMetaInfo(pQueryInfo); } - + // too many result columns not support order by in query if (pQuerySql->pSelection->nExpr > TSDB_MAX_COLUMNS) { return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg8); @@ -5517,7 +5631,7 @@ int32_t doCheckForQuery(SSqlObj* pSql, SQuerySQL* pQuerySql, int32_t index) { } pQueryInfo->command = TSDB_SQL_SELECT; - + // set all query tables, which are maybe more than one. for (int32_t i = 0; i < pQuerySql->from->nExpr; ++i) { tVariant* pTableItem = &pQuerySql->from->a[i].pVar; @@ -5566,7 +5680,7 @@ int32_t doCheckForQuery(SSqlObj* pSql, SQuerySQL* pQuerySql, int32_t index) { if (parseIntervalClause(pQueryInfo, pQuerySql) != TSDB_CODE_SUCCESS) { return TSDB_CODE_INVALID_SQL; } else { - if ((pQueryInfo->nAggTimeInterval > 0) && + if ((pQueryInfo->intervalTime > 0) && (validateFunctionsInIntervalOrGroupbyQuery(pQueryInfo) != TSDB_CODE_SUCCESS)) { return TSDB_CODE_INVALID_SQL; } @@ -5603,7 +5717,7 @@ int32_t doCheckForQuery(SSqlObj* pSql, SQuerySQL* pQuerySql, int32_t index) { // no result due to invalid query time range if (pQueryInfo->stime > pQueryInfo->etime) { - pCmd->command = TSDB_SQL_RETRIEVE_EMPTY_RESULT; + pQueryInfo->command = TSDB_SQL_RETRIEVE_EMPTY_RESULT; return TSDB_CODE_SUCCESS; } @@ -5633,24 +5747,24 @@ int32_t doCheckForQuery(SSqlObj* pSql, SQuerySQL* pQuerySql, int32_t index) { for (int32_t i = 0; i < pQueryInfo->numOfTables; ++i) { updateTagColumnIndex(pQueryInfo, i); } - + /* * fill options are set at the end position, when all columns are set properly * the columns may be increased due to group by operation */ if (pQuerySql->fillType != NULL) { - if (pQueryInfo->nAggTimeInterval == 0 && (!tscIsPointInterpQuery(pQueryInfo))) { + if (pQueryInfo->intervalTime == 0 && (!tscIsPointInterpQuery(pQueryInfo))) { return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg5); } - - if (pQueryInfo->nAggTimeInterval > 0) { + + if (pQueryInfo->intervalTime > 0) { int64_t timeRange = labs(pQueryInfo->stime - pQueryInfo->etime); // number of result is not greater than 10,000,000 - if ((timeRange == 0) || (timeRange / pQueryInfo->nAggTimeInterval) > MAX_RETRIEVE_ROWS_IN_INTERVAL_QUERY) { + if ((timeRange == 0) || (timeRange / pQueryInfo->intervalTime) > MAX_RETRIEVE_ROWS_IN_INTERVAL_QUERY) { return invalidSqlErrMsg(pQueryInfo->msg, msg6); } } - + int32_t ret = parseFillClause(pQueryInfo, pQuerySql); if (ret != TSDB_CODE_SUCCESS) { return ret; @@ -5660,7 +5774,80 @@ int32_t doCheckForQuery(SSqlObj* pSql, SQuerySQL* pQuerySql, int32_t index) { return TSDB_CODE_SUCCESS; // Does not build query message here } -bool hasDefaultQueryTimeRange(SQueryInfo *pQueryInfo) { - return (pQueryInfo->stime == 0 && pQueryInfo->etime == INT64_MAX) || - (pQueryInfo->stime == INT64_MAX && pQueryInfo->etime == 0); +static int32_t tSQLBinaryExprCreateFromSqlExpr(tSQLSyntaxNode **pExpr, tSQLExpr* pAst, int32_t* num, + SColIndexEx** pColIndex, SSqlExprInfo* pExprInfo) { + tSQLSyntaxNode* pLeft = NULL; + tSQLSyntaxNode* pRight= NULL; + + if (pAst->pLeft != NULL) { + int32_t ret = tSQLBinaryExprCreateFromSqlExpr(&pLeft, pAst->pLeft, num, pColIndex, pExprInfo); + if (ret != TSDB_CODE_SUCCESS) { + return ret; + } + } + + if (pAst->pRight != NULL) { + int32_t ret = tSQLBinaryExprCreateFromSqlExpr(&pRight, pAst->pRight, num, pColIndex, pExprInfo); + if (ret != TSDB_CODE_SUCCESS) { + return ret; + } + } + + if (pAst->pLeft == NULL) { + if (pAst->nSQLOptr >= TK_TINYINT && pAst->nSQLOptr <= TK_DOUBLE) { + *pExpr = calloc(1, sizeof(tSQLSyntaxNode) + sizeof(tVariant)); + (*pExpr)->nodeType = TSQL_NODE_VALUE; + (*pExpr)->pVal = (tVariant*) ((char*)(*pExpr) + sizeof(tSQLSyntaxNode)); + tVariantAssign((*pExpr)->pVal, &pAst->val); + } else if (pAst->nSQLOptr >= TK_COUNT && pAst->nSQLOptr <= TK_AVG_IRATE) { + *pExpr = calloc(1, sizeof(tSQLSyntaxNode) + sizeof(SSchemaEx)); + (*pExpr)->nodeType = TSQL_NODE_COL; + (*pExpr)->pSchema = (SSchema*)((char*)(*pExpr) + sizeof(tSQLSyntaxNode)); + strncpy((*pExpr)->pSchema->name, pAst->operand.z, pAst->operand.n); + + // set the input column data byte and type. + for (int32_t i = 0; i < pExprInfo->numOfExprs; ++i) { + if (strcmp((*pExpr)->pSchema->name, pExprInfo->pExprs[i]->aliasName) == 0) { + (*pExpr)->pSchema->type = pExprInfo->pExprs[i]->resType; + (*pExpr)->pSchema->bytes = pExprInfo->pExprs[i]->resBytes; + break; + } + } + } else { //todo return error + return TSDB_CODE_SUCCESS; + } + + (*pExpr)->colId = -1; + + *pColIndex = realloc(*pColIndex, (++(*num)) * sizeof(SColIndexEx)); + memset(&(*pColIndex)[(*num) - 1], 0, sizeof(SColIndexEx)); + + strncpy((*pColIndex)[(*num) - 1].name, pAst->operand.z, pAst->operand.n); + } else { + tSQLBinaryExpr *pBinExpr = (tSQLBinaryExpr *)calloc(1, sizeof(tSQLBinaryExpr)); + pBinExpr->filterOnPrimaryKey = false; + pBinExpr->pLeft = pLeft; + pBinExpr->pRight = pRight; + SSQLToken t = {.type = pAst->nSQLOptr}; + pBinExpr->nSQLBinaryOptr = getBinaryExprOptr(&t); + + assert(pBinExpr->nSQLBinaryOptr != 0); + + (*pExpr) = malloc(sizeof(tSQLSyntaxNode)); + (*pExpr)->nodeType = TSQL_NODE_EXPR; + (*pExpr)->pExpr = pBinExpr; + (*pExpr)->colId = -1; + + if (pBinExpr->nSQLBinaryOptr == TSDB_BINARY_OP_DIVIDE) { + if (pRight->nodeType == TSQL_NODE_VALUE) { + if (pRight->pVal->nType == TSDB_DATA_TYPE_INT && pRight->pVal->i64Key == 0) { + return TSDB_CODE_INVALID_SQL; + } else if (pRight->pVal->nType == TSDB_DATA_TYPE_FLOAT && pRight->pVal->dKey == 0) { + return TSDB_CODE_INVALID_SQL; + } + } + } + } + + return TSDB_CODE_SUCCESS; } diff --git a/src/client/src/tscSecondaryMerge.c b/src/client/src/tscSecondaryMerge.c index ca57030539a451d4967ace21fc688a1e44ffea76..51a59005f001f7555a3ffc2e5c7e15ed111af988 100644 --- a/src/client/src/tscSecondaryMerge.c +++ b/src/client/src/tscSecondaryMerge.c @@ -13,10 +13,11 @@ * along with this program. If not, see . */ +#include "tscSecondaryMerge.h" #include "os.h" #include "tlosertree.h" -#include "tscSecondaryMerge.h" #include "tscUtil.h" +#include "tschemautil.h" #include "tsclient.h" #include "tutil.h" @@ -58,40 +59,37 @@ static void tscInitSqlContext(SSqlCmd *pCmd, SSqlRes *pRes, SLocalReducer *pRedu * the fields and offset attributes in pCmd and pModel may be different due to * merge requirement. So, the final result in pRes structure is formatted in accordance with the pCmd object. */ - SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); - for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); + for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { SQLFunctionCtx *pCtx = &pReducer->pCtx[i]; + SSqlExpr * pExpr = tscSqlExprGet(pQueryInfo, i); - pCtx->aOutputBuf = pReducer->pResultBuf->data + tscFieldInfoGetOffset(pQueryInfo, i) * pReducer->resColModel->capacity; + pCtx->aOutputBuf = + pReducer->pResultBuf->data + tscFieldInfoGetOffset(pQueryInfo, i) * pReducer->resColModel->capacity; pCtx->order = pQueryInfo->order.order; - pCtx->functionId = pQueryInfo->exprsInfo.pExprs[i].functionId; + pCtx->functionId = pExpr->functionId; // input buffer hold only one point data - int16_t offset = getColumnModelOffset(pDesc->pColumnModel, i); - SSchema* pSchema = getColumnModelSchema(pDesc->pColumnModel, i); - + int16_t offset = getColumnModelOffset(pDesc->pColumnModel, i); + SSchema *pSchema = getColumnModelSchema(pDesc->pColumnModel, i); + pCtx->aInputElemBuf = pReducer->pTempBuffer->data + offset; // input data format comes from pModel pCtx->inputType = pSchema->type; pCtx->inputBytes = pSchema->bytes; - TAOS_FIELD *pField = tscFieldInfoGetField(pQueryInfo, i); // output data format yet comes from pCmd. - pCtx->outputBytes = pField->bytes; - pCtx->outputType = pField->type; + pCtx->outputBytes = pExpr->resBytes; + pCtx->outputType = pExpr->resType; pCtx->startOffset = 0; pCtx->size = 1; pCtx->hasNull = true; pCtx->currentStage = SECONDARY_STAGE_MERGE; - pRes->bytes[i] = pField->bytes; - - SSqlExpr *pExpr = tscSqlExprGet(pQueryInfo, i); - // for top/bottom function, the output of timestamp is the first column - int32_t functionId = pExpr->functionId; + int32_t functionId = pExpr->functionId; if (functionId == TSDB_FUNC_TOP || functionId == TSDB_FUNC_BOTTOM) { pCtx->ptsOutputBuf = pReducer->pCtx[0].aOutputBuf; pCtx->param[2].i64Key = pQueryInfo->order.order; @@ -107,12 +105,12 @@ static void tscInitSqlContext(SSqlCmd *pCmd, SSqlRes *pRes, SLocalReducer *pRedu pCtx->resultInfo->superTableQ = true; } - int16_t n = 0; - int16_t tagLen = 0; - SQLFunctionCtx** pTagCtx = calloc(pQueryInfo->fieldsInfo.numOfOutputCols, POINTER_BYTES); + int16_t n = 0; + int16_t tagLen = 0; + SQLFunctionCtx **pTagCtx = calloc(pQueryInfo->fieldsInfo.numOfOutputCols, POINTER_BYTES); - SQLFunctionCtx* pCtx = NULL; - for(int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + SQLFunctionCtx *pCtx = NULL; + for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { SSqlExpr *pExpr = tscSqlExprGet(pQueryInfo, i); if (pExpr->functionId == TSDB_FUNC_TAG_DUMMY || pExpr->functionId == TSDB_FUNC_TS_DUMMY) { tagLen += pExpr->resBytes; @@ -218,12 +216,12 @@ void tscCreateLocalReducer(tExtMemBuffer **pMemBuffer, int32_t numOfBuffer, tOrd #ifdef _DEBUG_VIEW printf("load data page into mem for build loser tree: %" PRIu64 " rows\n", pDS->filePage.numOfElems); SSrcColumnInfo colInfo[256] = {0}; - SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); + SQueryInfo * pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); tscGetSrcColumnInfo(colInfo, pQueryInfo); - tColModelDisplayEx(pDesc->pColumnModel, pDS->filePage.data, pDS->filePage.numOfElems, pMemBuffer[0]->numOfElemsPerPage, - colInfo); + tColModelDisplayEx(pDesc->pColumnModel, pDS->filePage.data, pDS->filePage.numOfElems, + pMemBuffer[0]->numOfElemsPerPage, colInfo); #endif if (pDS->filePage.numOfElems == 0) { // no data in this flush tscTrace("%p flush data is empty, ignore %d flush record", pSqlObjAddr, idx); @@ -244,8 +242,8 @@ void tscCreateLocalReducer(tExtMemBuffer **pMemBuffer, int32_t numOfBuffer, tOrd param->pLocalData = pReducer->pLocalDataSrc; param->pDesc = pReducer->pDesc; param->numOfElems = pReducer->pLocalDataSrc[0]->pMemBuffer->numOfElemsPerPage; - SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); - + SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); + param->groupOrderType = pQueryInfo->groupbyExpr.orderType; pRes->code = tLoserTreeCreate(&pReducer->pLoserTree, pReducer->numOfBuffer, param, treeComparator); @@ -255,7 +253,7 @@ void tscCreateLocalReducer(tExtMemBuffer **pMemBuffer, int32_t numOfBuffer, tOrd // the input data format follows the old format, but output in a new format. // so, all the input must be parsed as old format - pReducer->pCtx = (SQLFunctionCtx *)calloc(pQueryInfo->fieldsInfo.numOfOutputCols, sizeof(SQLFunctionCtx)); + pReducer->pCtx = (SQLFunctionCtx *)calloc(pQueryInfo->exprsInfo.numOfExprs, sizeof(SQLFunctionCtx)); pReducer->rowSize = pMemBuffer[0]->nElemSize; @@ -279,7 +277,7 @@ void tscCreateLocalReducer(tExtMemBuffer **pMemBuffer, int32_t numOfBuffer, tOrd pReducer->nResultBufSize = pMemBuffer[0]->pageSize * 16; pReducer->pResultBuf = (tFilePage *)calloc(1, pReducer->nResultBufSize + sizeof(tFilePage)); - + int32_t finalRowLength = tscGetResRowLength(pQueryInfo); pReducer->resColModel = finalmodel; pReducer->resColModel->capacity = pReducer->nResultBufSize / finalRowLength; @@ -288,12 +286,12 @@ void tscCreateLocalReducer(tExtMemBuffer **pMemBuffer, int32_t numOfBuffer, tOrd pReducer->pFinalRes = calloc(1, pReducer->rowSize * pReducer->resColModel->capacity); pReducer->pBufForInterpo = calloc(1, pReducer->nResultBufSize); - if (pReducer->pTempBuffer == NULL|| pReducer->discardData == NULL || pReducer->pResultBuf == NULL || + if (pReducer->pTempBuffer == NULL || pReducer->discardData == NULL || pReducer->pResultBuf == NULL || pReducer->pBufForInterpo == NULL || pReducer->pFinalRes == NULL || pReducer->prevRowOfInput == NULL) { tfree(pReducer->pTempBuffer); tfree(pReducer->discardData); tfree(pReducer->pResultBuf); - tfree(pReducer->pFinalRes); + tfree(pReducer->pFinalRes); tfree(pReducer->pBufForInterpo); tfree(pReducer->prevRowOfInput); @@ -302,30 +300,31 @@ void tscCreateLocalReducer(tExtMemBuffer **pMemBuffer, int32_t numOfBuffer, tOrd } pReducer->pTempBuffer->numOfElems = 0; - pReducer->pResInfo = calloc((size_t)pQueryInfo->fieldsInfo.numOfOutputCols, sizeof(SResultInfo)); + pReducer->pResInfo = calloc((size_t)pQueryInfo->exprsInfo.numOfExprs, sizeof(SResultInfo)); tscCreateResPointerInfo(pRes, pQueryInfo); tscInitSqlContext(pCmd, pRes, pReducer, pDesc); // we change the capacity of schema to denote that there is only one row in temp buffer pReducer->pDesc->pColumnModel->capacity = 1; - - //restore the limitation value at the last stage + + // restore the limitation value at the last stage if (tscOrderedProjectionQueryOnSTable(pQueryInfo, 0)) { pQueryInfo->limit.limit = pQueryInfo->clauseLimit; pQueryInfo->limit.offset = pQueryInfo->prjOffset; } - + pReducer->offset = pQueryInfo->limit.offset; - + pRes->pLocalReducer = pReducer; pRes->numOfGroups = 0; - SMeterMetaInfo* pMeterMetaInfo = tscGetMeterMetaInfo(pCmd, pCmd->clauseIndex, 0); - int16_t prec = pMeterMetaInfo->pMeterMeta->precision; + SMeterMetaInfo *pMeterMetaInfo = tscGetMeterMetaInfo(pCmd, pCmd->clauseIndex, 0); + int16_t prec = pMeterMetaInfo->pMeterMeta->precision; int64_t stime = (pQueryInfo->stime < pQueryInfo->etime) ? pQueryInfo->stime : pQueryInfo->etime; - int64_t revisedSTime = taosGetIntervalStartTimestamp(stime, pQueryInfo->nAggTimeInterval, pQueryInfo->intervalTimeUnit, prec); + int64_t revisedSTime = + taosGetIntervalStartTimestamp(stime, pQueryInfo->intervalTime, pQueryInfo->intervalTimeUnit, prec); SInterpolationInfo *pInterpoInfo = &pReducer->interpolationInfo; taosInitInterpoInfo(pInterpoInfo, pQueryInfo->order.order, revisedSTime, pQueryInfo->groupbyExpr.numOfGroupCols, @@ -336,7 +335,7 @@ void tscCreateLocalReducer(tExtMemBuffer **pMemBuffer, int32_t numOfBuffer, tOrd if (pQueryInfo->groupbyExpr.numOfGroupCols > 0) { pInterpoInfo->pTags[0] = (char *)pInterpoInfo->pTags + POINTER_BYTES * pQueryInfo->groupbyExpr.numOfGroupCols; for (int32_t i = 1; i < pQueryInfo->groupbyExpr.numOfGroupCols; ++i) { - SSchema* pSchema = getColumnModelSchema(pReducer->resColModel, startIndex + i - 1); + SSchema *pSchema = getColumnModelSchema(pReducer->resColModel, startIndex + i - 1); pInterpoInfo->pTags[i] = pSchema->bytes + pInterpoInfo->pTags[i - 1]; } } else { @@ -388,7 +387,7 @@ int32_t tscFlushTmpBuffer(tExtMemBuffer *pMemoryBuf, tOrderDescriptor *pDesc, tF int32_t saveToBuffer(tExtMemBuffer *pMemoryBuf, tOrderDescriptor *pDesc, tFilePage *pPage, void *data, int32_t numOfRows, int32_t orderType) { SColumnModel *pModel = pDesc->pColumnModel; - + if (pPage->numOfElems + numOfRows <= pModel->capacity) { tColModelAppend(pModel, pPage, data, 0, numOfRows, numOfRows); return 0; @@ -445,11 +444,11 @@ void tscDestroyLocalReducer(SSqlObj *pSql) { return; } - SSqlCmd *pCmd = &pSql->cmd; - SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); - + SSqlCmd * pCmd = &pSql->cmd; + SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); + // there is no more result, so we release all allocated resource - SLocalReducer *pLocalReducer = (SLocalReducer*)atomic_exchange_ptr(&pRes->pLocalReducer, NULL); + SLocalReducer *pLocalReducer = (SLocalReducer *)atomic_exchange_ptr(&pRes->pLocalReducer, NULL); if (pLocalReducer != NULL) { int32_t status = 0; while ((status = atomic_val_compare_exchange_32(&pLocalReducer->status, TSC_LOCALREDUCE_READY, @@ -461,19 +460,18 @@ void tscDestroyLocalReducer(SSqlObj *pSql) { taosDestoryInterpoInfo(&pLocalReducer->interpolationInfo); if (pLocalReducer->pCtx != NULL) { - for(int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { SQLFunctionCtx *pCtx = &pLocalReducer->pCtx[i]; - + tVariantDestroy(&pCtx->tag); if (pCtx->tagInfo.pTagCtxList != NULL) { tfree(pCtx->tagInfo.pTagCtxList); } } - + tfree(pLocalReducer->pCtx); } - tfree(pLocalReducer->prevRowOfInput); tfree(pLocalReducer->pTempBuffer); @@ -514,15 +512,15 @@ void tscDestroyLocalReducer(SSqlObj *pSql) { } static int32_t createOrderDescriptor(tOrderDescriptor **pOrderDesc, SSqlCmd *pCmd, SColumnModel *pModel) { - int32_t numOfGroupByCols = 0; - SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); - + int32_t numOfGroupByCols = 0; + SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); + if (pQueryInfo->groupbyExpr.numOfGroupCols > 0) { numOfGroupByCols = pQueryInfo->groupbyExpr.numOfGroupCols; } // primary timestamp column is involved in final result - if (pQueryInfo->nAggTimeInterval != 0 || tscOrderedProjectionQueryOnSTable(pQueryInfo, 0)) { + if (pQueryInfo->intervalTime != 0 || tscOrderedProjectionQueryOnSTable(pQueryInfo, 0)) { numOfGroupByCols++; } @@ -539,7 +537,7 @@ static int32_t createOrderDescriptor(tOrderDescriptor **pOrderDesc, SSqlCmd *pCm orderIdx[i] = startCols++; } - if (pQueryInfo->nAggTimeInterval != 0) { + if (pQueryInfo->intervalTime != 0) { // the first column is the timestamp, handles queries like "interval(10m) group by tags" orderIdx[numOfGroupByCols - 1] = PRIMARYKEY_TIMESTAMP_COL_INDEX; } @@ -556,17 +554,17 @@ static int32_t createOrderDescriptor(tOrderDescriptor **pOrderDesc, SSqlCmd *pCm } bool isSameGroup(SSqlCmd *pCmd, SLocalReducer *pReducer, char *pPrev, tFilePage *tmpBuffer) { - SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); - + SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); + int16_t functionId = tscSqlExprGet(pQueryInfo, 0)->functionId; // disable merge procedure for column projection query assert(functionId != TSDB_FUNC_ARITHM); - + if (tscOrderedProjectionQueryOnSTable(pQueryInfo, 0)) { return true; } - + if (functionId == TSDB_FUNC_PRJ || functionId == TSDB_FUNC_ARITHM) { return false; } @@ -581,10 +579,10 @@ bool isSameGroup(SSqlCmd *pCmd, SLocalReducer *pReducer, char *pPrev, tFilePage if (pOrderDesc->orderIdx.pData[numOfCols - 1] == PRIMARYKEY_TIMESTAMP_COL_INDEX) { //<= 0 // super table interval query - assert(pQueryInfo->nAggTimeInterval > 0); + assert(pQueryInfo->intervalTime > 0); pOrderDesc->orderIdx.numOfCols -= 1; } else { // simple group by query - assert(pQueryInfo->nAggTimeInterval == 0); + assert(pQueryInfo->intervalTime == 0); } // only one row exists @@ -599,11 +597,11 @@ int32_t tscLocalReducerEnvCreate(SSqlObj *pSql, tExtMemBuffer ***pMemBuffer, tOr SSqlCmd *pCmd = &pSql->cmd; SSqlRes *pRes = &pSql->res; - SSchema * pSchema = NULL; + SSchema * pSchema = NULL; SColumnModel *pModel = NULL; *pFinalModel = NULL; - SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); + SQueryInfo * pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); SMeterMetaInfo *pMeterMetaInfo = tscGetMeterMetaInfoFromQueryInfo(pQueryInfo, 0); (*pMemBuffer) = (tExtMemBuffer **)malloc(POINTER_BYTES * pMeterMetaInfo->pMetricMeta->numOfVnodes); @@ -613,7 +611,7 @@ int32_t tscLocalReducerEnvCreate(SSqlObj *pSql, tExtMemBuffer ***pMemBuffer, tOr return pRes->code; } - pSchema = (SSchema *)calloc(1, sizeof(SSchema) * pQueryInfo->fieldsInfo.numOfOutputCols); + pSchema = (SSchema *)calloc(1, sizeof(SSchema) * pQueryInfo->exprsInfo.numOfExprs); if (pSchema == NULL) { tscError("%p failed to allocate memory", pSql); pRes->code = TSDB_CODE_CLI_OUT_OF_MEMORY; @@ -621,7 +619,7 @@ int32_t tscLocalReducerEnvCreate(SSqlObj *pSql, tExtMemBuffer ***pMemBuffer, tOr } int32_t rlen = 0; - for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { SSqlExpr *pExpr = tscSqlExprGet(pQueryInfo, i); pSchema[i].bytes = pExpr->resBytes; @@ -634,8 +632,8 @@ int32_t tscLocalReducerEnvCreate(SSqlObj *pSql, tExtMemBuffer ***pMemBuffer, tOr if (rlen != 0) { capacity = nBufferSizes / rlen; } - - pModel = createColumnModel(pSchema, pQueryInfo->fieldsInfo.numOfOutputCols, capacity); + + pModel = createColumnModel(pSchema, pQueryInfo->exprsInfo.numOfExprs, capacity); for (int32_t i = 0; i < pMeterMetaInfo->pMetricMeta->numOfVnodes; ++i) { (*pMemBuffer)[i] = createExtMemBuffer(nBufferSizes, rlen, pModel); @@ -647,16 +645,43 @@ int32_t tscLocalReducerEnvCreate(SSqlObj *pSql, tExtMemBuffer ***pMemBuffer, tOr return pRes->code; } - memset(pSchema, 0, sizeof(SSchema) * pQueryInfo->fieldsInfo.numOfOutputCols); - for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { - TAOS_FIELD *pField = tscFieldInfoGetField(pQueryInfo, i); + // final result depends on the fields number + memset(pSchema, 0, sizeof(SSchema) * pQueryInfo->exprsInfo.numOfExprs); + for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { + SSqlExpr *pExpr = tscSqlExprGet(pQueryInfo, i); + + SSchema *p1 = tsGetColumnSchema(pMeterMetaInfo->pMeterMeta, pExpr->colInfo.colIdx); + + int16_t inter = 0; + int16_t type = -1; + int16_t bytes = 0; + + // if ((pExpr->functionId >= TSDB_FUNC_FIRST_DST && pExpr->functionId <= TSDB_FUNC_LAST_DST) || + // (pExpr->functionId >= TSDB_FUNC_SUM && pExpr->functionId <= TSDB_FUNC_MAX) || + // pExpr->functionId == TSDB_FUNC_LAST_ROW) { + // the final result size and type in the same as query on single table. + // so here, set the flag to be false; + + int32_t functionId = pExpr->functionId; + if (functionId >= TSDB_FUNC_TS && functionId <= TSDB_FUNC_DIFF) { + type = pModel->pFields[i].field.type; + bytes = pModel->pFields[i].field.bytes; + } else { + if (functionId == TSDB_FUNC_FIRST_DST) { + functionId = TSDB_FUNC_FIRST; + } else if (functionId == TSDB_FUNC_LAST_DST) { + functionId = TSDB_FUNC_LAST; + } - pSchema[i].type = pField->type; - pSchema[i].bytes = pField->bytes; - strcpy(pSchema[i].name, pField->name); + getResultDataInfo(p1->type, p1->bytes, functionId, 0, &type, &bytes, &inter, 0, false); + } + + pSchema[i].type = type; + pSchema[i].bytes = bytes; + strcpy(pSchema[i].name, pModel->pFields[i].field.name); } - *pFinalModel = createColumnModel(pSchema, pQueryInfo->fieldsInfo.numOfOutputCols, capacity); + *pFinalModel = createColumnModel(pSchema, pQueryInfo->exprsInfo.numOfExprs, capacity); tfree(pSchema); return TSDB_CODE_SUCCESS; @@ -746,13 +771,15 @@ void adjustLoserTreeFromNewData(SLocalReducer *pLocalReducer, SLocalDataSource * } } -void savePrevRecordAndSetupInterpoInfo(SLocalReducer *pLocalReducer, SQueryInfo* pQueryInfo, SInterpolationInfo *pInterpoInfo) { +void savePrevRecordAndSetupInterpoInfo(SLocalReducer *pLocalReducer, SQueryInfo *pQueryInfo, + SInterpolationInfo *pInterpoInfo) { // discard following dataset in the same group and reset the interpolation information - SMeterMetaInfo* pMeterMetaInfo = tscGetMeterMetaInfoFromQueryInfo(pQueryInfo, 0); - int16_t prec = pMeterMetaInfo->pMeterMeta->precision; + SMeterMetaInfo *pMeterMetaInfo = tscGetMeterMetaInfoFromQueryInfo(pQueryInfo, 0); + int16_t prec = pMeterMetaInfo->pMeterMeta->precision; int64_t stime = (pQueryInfo->stime < pQueryInfo->etime) ? pQueryInfo->stime : pQueryInfo->etime; - int64_t revisedSTime = taosGetIntervalStartTimestamp(stime, pQueryInfo->nAggTimeInterval, pQueryInfo->intervalTimeUnit, prec); + int64_t revisedSTime = + taosGetIntervalStartTimestamp(stime, pQueryInfo->intervalTime, pQueryInfo->intervalTimeUnit, prec); taosInitInterpoInfo(pInterpoInfo, pQueryInfo->order.order, revisedSTime, pQueryInfo->groupbyExpr.numOfGroupCols, pLocalReducer->rowSize); @@ -765,24 +792,25 @@ void savePrevRecordAndSetupInterpoInfo(SLocalReducer *pLocalReducer, SQueryInfo* } // todo merge with following function -static void reversedCopyResultToDstBuf(SQueryInfo* pQueryInfo, SSqlRes *pRes, tFilePage *pFinalDataPage) { - - for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { - TAOS_FIELD *pField = tscFieldInfoGetField(pQueryInfo, i); - - int32_t offset = tscFieldInfoGetOffset(pQueryInfo, i); - char * src = pFinalDataPage->data + (pRes->numOfRows - 1) * pField->bytes + pRes->numOfRows * offset; - char * dst = pRes->data + pRes->numOfRows * offset; - - for (int32_t j = 0; j < pRes->numOfRows; ++j) { - memcpy(dst, src, (size_t)pField->bytes); - dst += pField->bytes; - src -= pField->bytes; - } - } -} +// static void reversedCopyResultToDstBuf(SQueryInfo* pQueryInfo, SSqlRes *pRes, tFilePage *pFinalDataPage) { +// +// for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { +// TAOS_FIELD *pField = tscFieldInfoGetField(pQueryInfo, i); +// +// int32_t offset = tscFieldInfoGetOffset(pQueryInfo, i); +// char * src = pFinalDataPage->data + (pRes->numOfRows - 1) * pField->bytes + pRes->numOfRows * offset; +// char * dst = pRes->data + pRes->numOfRows * offset; +// +// for (int32_t j = 0; j < pRes->numOfRows; ++j) { +// memcpy(dst, src, (size_t)pField->bytes); +// dst += pField->bytes; +// src -= pField->bytes; +// } +// } +//} -static void reversedCopyFromInterpolationToDstBuf(SQueryInfo* pQueryInfo, SSqlRes *pRes, tFilePage **pResPages, SLocalReducer *pLocalReducer) { +static void reversedCopyFromInterpolationToDstBuf(SQueryInfo *pQueryInfo, SSqlRes *pRes, tFilePage **pResPages, + SLocalReducer *pLocalReducer) { assert(0); for (int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { TAOS_FIELD *pField = tscFieldInfoGetField(pQueryInfo, i); @@ -806,11 +834,11 @@ static void reversedCopyFromInterpolationToDstBuf(SQueryInfo* pQueryInfo, SSqlRe * by "interuptHandler" function in shell */ static void doInterpolateResult(SSqlObj *pSql, SLocalReducer *pLocalReducer, bool doneOutput) { - SSqlCmd * pCmd = &pSql->cmd; - SSqlRes * pRes = &pSql->res; - tFilePage *pFinalDataPage = pLocalReducer->pResultBuf; - SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); - + SSqlCmd * pCmd = &pSql->cmd; + SSqlRes * pRes = &pSql->res; + tFilePage * pFinalDataPage = pLocalReducer->pResultBuf; + SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); + if (pRes->pLocalReducer != pLocalReducer) { /* * Release the SSqlObj is called, and it is int destroying function invoked by other thread. @@ -820,7 +848,7 @@ static void doInterpolateResult(SSqlObj *pSql, SLocalReducer *pLocalReducer, boo assert(pRes->pLocalReducer == NULL); } - if (pQueryInfo->nAggTimeInterval == 0 || pQueryInfo->interpoType == TSDB_INTERPO_NONE) { + if (pQueryInfo->intervalTime == 0 || pQueryInfo->interpoType == TSDB_INTERPO_NONE) { // no interval query, no interpolation pRes->data = pLocalReducer->pFinalRes; pRes->numOfRows = pFinalDataPage->numOfElems; @@ -862,19 +890,14 @@ static void doInterpolateResult(SSqlObj *pSql, SLocalReducer *pLocalReducer, boo } int32_t rowSize = tscGetResRowLength(pQueryInfo); - // handle the descend order output -// if (pQueryInfo->order.order == TSQL_SO_ASC) { - memcpy(pRes->data, pFinalDataPage->data, pRes->numOfRows * rowSize); -// } else { -// reversedCopyResultToDstBuf(pQueryInfo, pRes, pFinalDataPage); -// } + memcpy(pRes->data, pFinalDataPage->data, pRes->numOfRows * rowSize); pFinalDataPage->numOfElems = 0; return; } int64_t *pPrimaryKeys = (int64_t *)pLocalReducer->pBufForInterpo; - + SInterpolationInfo *pInterpoInfo = &pLocalReducer->interpolationInfo; int64_t actualETime = (pQueryInfo->stime < pQueryInfo->etime) ? pQueryInfo->etime : pQueryInfo->stime; @@ -889,22 +912,23 @@ static void doInterpolateResult(SSqlObj *pSql, SLocalReducer *pLocalReducer, boo int32_t *functions = (int32_t *)((char *)srcData + pQueryInfo->fieldsInfo.numOfOutputCols * sizeof(void *)); for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { - srcData[i] = pLocalReducer->pBufForInterpo + tscFieldInfoGetOffset(pQueryInfo, i) * pInterpoInfo->numOfRawDataInRows; + srcData[i] = + pLocalReducer->pBufForInterpo + tscFieldInfoGetOffset(pQueryInfo, i) * pInterpoInfo->numOfRawDataInRows; functions[i] = tscSqlExprGet(pQueryInfo, i)->functionId; } - SMeterMetaInfo* pMeterMetaInfo = tscGetMeterMetaInfo(pCmd, pCmd->clauseIndex, 0); - int8_t precision = pMeterMetaInfo->pMeterMeta->precision; + SMeterMetaInfo *pMeterMetaInfo = tscGetMeterMetaInfo(pCmd, pCmd->clauseIndex, 0); + int8_t precision = pMeterMetaInfo->pMeterMeta->precision; while (1) { int32_t remains = taosNumOfRemainPoints(pInterpoInfo); - TSKEY etime = taosGetRevisedEndKey(actualETime, pQueryInfo->order.order, pQueryInfo->nAggTimeInterval, pQueryInfo->intervalTimeUnit, - precision); - int32_t nrows = taosGetNumOfResultWithInterpo(pInterpoInfo, pPrimaryKeys, remains, pQueryInfo->nAggTimeInterval, etime, + TSKEY etime = taosGetRevisedEndKey(actualETime, pQueryInfo->order.order, pQueryInfo->intervalTime, + pQueryInfo->intervalTimeUnit, precision); + int32_t nrows = taosGetNumOfResultWithInterpo(pInterpoInfo, pPrimaryKeys, remains, pQueryInfo->intervalTime, etime, pLocalReducer->resColModel->capacity); int32_t newRows = taosDoInterpoResult(pInterpoInfo, pQueryInfo->interpoType, pResPages, remains, nrows, - pQueryInfo->nAggTimeInterval, pPrimaryKeys, pLocalReducer->resColModel, srcData, + pQueryInfo->intervalTime, pPrimaryKeys, pLocalReducer->resColModel, srcData, pQueryInfo->defaultVal, functions, pLocalReducer->resColModel->capacity); assert(newRows <= nrows); @@ -914,7 +938,8 @@ static void doInterpolateResult(SSqlObj *pSql, SLocalReducer *pLocalReducer, boo if (pQueryInfo->limit.offset > 0) { for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { TAOS_FIELD *pField = tscFieldInfoGetField(pQueryInfo, i); - memmove(pResPages[i]->data, pResPages[i]->data + pField->bytes * pQueryInfo->limit.offset, newRows * pField->bytes); + memmove(pResPages[i]->data, pResPages[i]->data + pField->bytes * pQueryInfo->limit.offset, + newRows * pField->bytes); } } @@ -937,7 +962,7 @@ static void doInterpolateResult(SSqlObj *pSql, SLocalReducer *pLocalReducer, boo /* all output for current group are completed */ int32_t totalRemainRows = - taosGetNumOfResWithoutLimit(pInterpoInfo, pPrimaryKeys, rpoints, pQueryInfo->nAggTimeInterval, actualETime); + taosGetNumOfResWithoutLimit(pInterpoInfo, pPrimaryKeys, rpoints, pQueryInfo->intervalTime, actualETime); if (totalRemainRows <= 0) { break; } @@ -962,10 +987,10 @@ static void doInterpolateResult(SSqlObj *pSql, SLocalReducer *pLocalReducer, boo if (pQueryInfo->order.order == TSQL_SO_ASC) { for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { TAOS_FIELD *pField = tscFieldInfoGetField(pQueryInfo, i); - int16_t offset = getColumnModelOffset(pLocalReducer->resColModel, i); + int16_t offset = getColumnModelOffset(pLocalReducer->resColModel, i); memcpy(pRes->data + offset * pRes->numOfRows, pResPages[i]->data, pField->bytes * pRes->numOfRows); } - } else {//todo bug?? + } else { // todo bug?? reversedCopyFromInterpolationToDstBuf(pQueryInfo, pRes, pResPages, pLocalReducer); } } @@ -985,9 +1010,9 @@ static void savePreviousRow(SLocalReducer *pLocalReducer, tFilePage *tmpBuffer) // copy to previous temp buffer for (int32_t i = 0; i < pColumnModel->numOfCols; ++i) { - SSchema* pSchema = getColumnModelSchema(pColumnModel, i); - int16_t offset = getColumnModelOffset(pColumnModel, i); - + SSchema *pSchema = getColumnModelSchema(pColumnModel, i); + int16_t offset = getColumnModelOffset(pColumnModel, i); + memcpy(pLocalReducer->prevRowOfInput + offset, tmpBuffer->data + offset, pSchema->bytes); } @@ -995,19 +1020,19 @@ static void savePreviousRow(SLocalReducer *pLocalReducer, tFilePage *tmpBuffer) pLocalReducer->hasPrevRow = true; } -static void doExecuteSecondaryMerge(SSqlCmd* pCmd, SLocalReducer *pLocalReducer, bool needInit) { +static void doExecuteSecondaryMerge(SSqlCmd *pCmd, SLocalReducer *pLocalReducer, bool needInit) { // the tag columns need to be set before all functions execution - SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); - - for(int32_t j = 0; j < pQueryInfo->fieldsInfo.numOfOutputCols; ++j) { + SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); + + for (int32_t j = 0; j < pQueryInfo->exprsInfo.numOfExprs; ++j) { SSqlExpr * pExpr = tscSqlExprGet(pQueryInfo, j); SQLFunctionCtx *pCtx = &pLocalReducer->pCtx[j]; tVariantAssign(&pCtx->param[0], &pExpr->param[0]); // tags/tags_dummy function, the tag field of SQLFunctionCtx is from the input buffer - if (pExpr->functionId == TSDB_FUNC_TAG_DUMMY || pExpr->functionId == TSDB_FUNC_TAG || - pExpr->functionId == TSDB_FUNC_TS_DUMMY) { + int32_t functionId = pExpr->functionId; + if (functionId == TSDB_FUNC_TAG_DUMMY || functionId == TSDB_FUNC_TAG || functionId == TSDB_FUNC_TS_DUMMY) { tVariantDestroy(&pCtx->tag); tVariantCreateFromBinary(&pCtx->tag, pCtx->aInputElemBuf, pCtx->inputBytes, pCtx->inputType); } @@ -1019,7 +1044,7 @@ static void doExecuteSecondaryMerge(SSqlCmd* pCmd, SLocalReducer *pLocalReducer, } } - for (int32_t j = 0; j < pQueryInfo->fieldsInfo.numOfOutputCols; ++j) { + for (int32_t j = 0; j < pQueryInfo->exprsInfo.numOfExprs; ++j) { int32_t functionId = tscSqlExprGet(pQueryInfo, j)->functionId; if (functionId == TSDB_FUNC_TAG_DUMMY || functionId == TSDB_FUNC_TS_DUMMY) { continue; @@ -1029,7 +1054,7 @@ static void doExecuteSecondaryMerge(SSqlCmd* pCmd, SLocalReducer *pLocalReducer, } } -static void handleUnprocessedRow(SSqlCmd* pCmd, SLocalReducer *pLocalReducer, tFilePage *tmpBuffer) { +static void handleUnprocessedRow(SSqlCmd *pCmd, SLocalReducer *pLocalReducer, tFilePage *tmpBuffer) { if (pLocalReducer->hasUnprocessedRow) { pLocalReducer->hasUnprocessedRow = false; doExecuteSecondaryMerge(pCmd, pLocalReducer, true); @@ -1039,14 +1064,22 @@ static void handleUnprocessedRow(SSqlCmd* pCmd, SLocalReducer *pLocalReducer, tF static int64_t getNumOfResultLocal(SQueryInfo *pQueryInfo, SQLFunctionCtx *pCtx) { int64_t maxOutput = 0; - + for (int32_t j = 0; j < pQueryInfo->exprsInfo.numOfExprs; ++j) { - int32_t functionId = tscSqlExprGet(pQueryInfo, j)->functionId; + // SSqlExpr* pExpr = pQueryInfo->fieldsInfo.pSqlExpr[j]; + // if (pExpr == NULL) { + // assert(pQueryInfo->fieldsInfo.pExpr[j] != NULL); + // + // maxOutput = 1; + // continue; + // } /* * ts, tag, tagprj function can not decide the output number of current query * the number of output result is decided by main output */ + SSqlExpr *pExpr = tscSqlExprGet(pQueryInfo, j); + int32_t functionId = pExpr->functionId; if (functionId == TSDB_FUNC_TS || functionId == TSDB_FUNC_TAG || functionId == TSDB_FUNC_TAGPRJ) { continue; } @@ -1055,6 +1088,7 @@ static int64_t getNumOfResultLocal(SQueryInfo *pQueryInfo, SQLFunctionCtx *pCtx) maxOutput = GET_RES_INFO(&pCtx[j])->numOfRes; } } + return maxOutput; } @@ -1064,9 +1098,9 @@ static int64_t getNumOfResultLocal(SQueryInfo *pQueryInfo, SQLFunctionCtx *pCtx) * filled with the same result, which is the tags, specified in group by clause * */ -static void fillMultiRowsOfTagsVal(SQueryInfo* pQueryInfo, int32_t numOfRes, SLocalReducer *pLocalReducer) { +static void fillMultiRowsOfTagsVal(SQueryInfo *pQueryInfo, int32_t numOfRes, SLocalReducer *pLocalReducer) { int32_t maxBufSize = 0; // find the max tags column length to prepare the buffer - for (int32_t k = 0; k < pQueryInfo->fieldsInfo.numOfOutputCols; ++k) { + for (int32_t k = 0; k < pQueryInfo->exprsInfo.numOfExprs; ++k) { SSqlExpr *pExpr = tscSqlExprGet(pQueryInfo, k); if (maxBufSize < pExpr->resBytes && pExpr->functionId == TSDB_FUNC_TAG) { maxBufSize = pExpr->resBytes; @@ -1075,8 +1109,8 @@ static void fillMultiRowsOfTagsVal(SQueryInfo* pQueryInfo, int32_t numOfRes, SLo assert(maxBufSize >= 0); - char *buf = malloc((size_t) maxBufSize); - for (int32_t k = 0; k < pQueryInfo->fieldsInfo.numOfOutputCols; ++k) { + char *buf = malloc((size_t)maxBufSize); + for (int32_t k = 0; k < pQueryInfo->exprsInfo.numOfExprs; ++k) { SSqlExpr *pExpr = tscSqlExprGet(pQueryInfo, k); if (pExpr->functionId != TSDB_FUNC_TAG) { continue; @@ -1097,13 +1131,10 @@ static void fillMultiRowsOfTagsVal(SQueryInfo* pQueryInfo, int32_t numOfRes, SLo free(buf); } -int32_t finalizeRes(SQueryInfo* pQueryInfo, SLocalReducer *pLocalReducer) { - for (int32_t k = 0; k < pQueryInfo->fieldsInfo.numOfOutputCols; ++k) { +int32_t finalizeRes(SQueryInfo *pQueryInfo, SLocalReducer *pLocalReducer) { + for (int32_t k = 0; k < pQueryInfo->exprsInfo.numOfExprs; ++k) { SSqlExpr *pExpr = tscSqlExprGet(pQueryInfo, k); aAggs[pExpr->functionId].xFinalize(&pLocalReducer->pCtx[k]); - - // allow to re-initialize for the next round - pLocalReducer->pCtx[k].resultInfo->initialized = false; } pLocalReducer->hasPrevRow = false; @@ -1122,7 +1153,7 @@ int32_t finalizeRes(SQueryInfo* pQueryInfo, SLocalReducer *pLocalReducer) { * results generated by simple aggregation function, we merge them all into one points * *Exception*: column projection query, required no merge procedure */ -bool needToMerge(SQueryInfo* pQueryInfo, SLocalReducer *pLocalReducer, tFilePage *tmpBuffer) { +bool needToMerge(SQueryInfo *pQueryInfo, SLocalReducer *pLocalReducer, tFilePage *tmpBuffer) { int32_t ret = 0; // merge all result by default int16_t functionId = tscSqlExprGet(pQueryInfo, 0)->functionId; @@ -1144,7 +1175,7 @@ bool needToMerge(SQueryInfo* pQueryInfo, SLocalReducer *pLocalReducer, tFilePage return (ret == 0); } -static bool reachGroupResultLimit(SQueryInfo* pQueryInfo, SSqlRes *pRes) { +static bool reachGroupResultLimit(SQueryInfo *pQueryInfo, SSqlRes *pRes) { return (pRes->numOfGroups >= pQueryInfo->slimit.limit && pQueryInfo->slimit.limit >= 0); } @@ -1152,7 +1183,7 @@ static bool saveGroupResultInfo(SSqlObj *pSql) { SSqlCmd *pCmd = &pSql->cmd; SSqlRes *pRes = &pSql->res; - SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); + SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); pRes->numOfGroups += 1; // the output group is limited by the slimit clause @@ -1175,11 +1206,11 @@ static bool saveGroupResultInfo(SSqlObj *pSql) { * @return if current group is skipped, return false, and do NOT record it into pRes->numOfGroups */ bool doGenerateFinalResults(SSqlObj *pSql, SLocalReducer *pLocalReducer, bool noMoreCurrentGroupRes) { - SSqlCmd * pCmd = &pSql->cmd; - SSqlRes * pRes = &pSql->res; - - SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); - tFilePage *pResBuf = pLocalReducer->pResultBuf; + SSqlCmd *pCmd = &pSql->cmd; + SSqlRes *pRes = &pSql->res; + + SQueryInfo * pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); + tFilePage * pResBuf = pLocalReducer->pResultBuf; SColumnModel *pModel = pLocalReducer->resColModel; pRes->code = TSDB_CODE_SUCCESS; @@ -1207,11 +1238,10 @@ bool doGenerateFinalResults(SSqlObj *pSql, SLocalReducer *pLocalReducer, bool no int32_t startIndex = pQueryInfo->fieldsInfo.numOfOutputCols - pQueryInfo->groupbyExpr.numOfGroupCols; for (int32_t i = 0; i < pQueryInfo->groupbyExpr.numOfGroupCols; ++i) { - int16_t offset = getColumnModelOffset(pModel, startIndex + i); - SSchema* pSchema = getColumnModelSchema(pModel, startIndex + i); - - memcpy(pInterpoInfo->pTags[i], - pLocalReducer->pBufForInterpo + offset * pResBuf->numOfElems, pSchema->bytes); + int16_t offset = getColumnModelOffset(pModel, startIndex + i); + SSchema *pSchema = getColumnModelSchema(pModel, startIndex + i); + + memcpy(pInterpoInfo->pTags[i], pLocalReducer->pBufForInterpo + offset * pResBuf->numOfElems, pSchema->bytes); } taosInterpoSetStartInfo(&pLocalReducer->interpolationInfo, pResBuf->numOfElems, pQueryInfo->interpoType); @@ -1220,7 +1250,7 @@ bool doGenerateFinalResults(SSqlObj *pSql, SLocalReducer *pLocalReducer, bool no return true; } -void resetOutputBuf(SQueryInfo* pQueryInfo, SLocalReducer *pLocalReducer) { // reset output buffer to the beginning +void resetOutputBuf(SQueryInfo *pQueryInfo, SLocalReducer *pLocalReducer) { // reset output buffer to the beginning for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { pLocalReducer->pCtx[i].aOutputBuf = pLocalReducer->pResultBuf->data + tscFieldInfoGetOffset(pQueryInfo, i) * pLocalReducer->resColModel->capacity; @@ -1233,21 +1263,22 @@ static void resetEnvForNewResultset(SSqlRes *pRes, SSqlCmd *pCmd, SLocalReducer // In handling data in other groups, we need to reset the interpolation information for a new group data pRes->numOfRows = 0; pRes->numOfTotalInCurrentClause = 0; - - SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); - + + SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); + pQueryInfo->limit.offset = pLocalReducer->offset; - SMeterMetaInfo* pMeterMetaInfo = tscGetMeterMetaInfo(pCmd, pCmd->clauseIndex, 0); - int16_t precision = pMeterMetaInfo->pMeterMeta->precision; + SMeterMetaInfo *pMeterMetaInfo = tscGetMeterMetaInfo(pCmd, pCmd->clauseIndex, 0); + int16_t precision = pMeterMetaInfo->pMeterMeta->precision; // for group result interpolation, do not return if not data is generated if (pQueryInfo->interpoType != TSDB_INTERPO_NONE) { int64_t stime = (pQueryInfo->stime < pQueryInfo->etime) ? pQueryInfo->stime : pQueryInfo->etime; - int64_t newTime = taosGetIntervalStartTimestamp(stime, pQueryInfo->nAggTimeInterval, pQueryInfo->intervalTimeUnit, precision); + int64_t newTime = + taosGetIntervalStartTimestamp(stime, pQueryInfo->intervalTime, pQueryInfo->intervalTimeUnit, precision); - taosInitInterpoInfo(&pLocalReducer->interpolationInfo, pQueryInfo->order.order, newTime, pQueryInfo->groupbyExpr.numOfGroupCols, - pLocalReducer->rowSize); + taosInitInterpoInfo(&pLocalReducer->interpolationInfo, pQueryInfo->order.order, newTime, + pQueryInfo->groupbyExpr.numOfGroupCols, pLocalReducer->rowSize); } } @@ -1259,12 +1290,12 @@ static bool doInterpolationForCurrentGroup(SSqlObj *pSql) { SSqlCmd *pCmd = &pSql->cmd; SSqlRes *pRes = &pSql->res; - SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); + SQueryInfo * pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); SLocalReducer * pLocalReducer = pRes->pLocalReducer; SInterpolationInfo *pInterpoInfo = &pLocalReducer->interpolationInfo; - SMeterMetaInfo* pMeterMetaInfo = tscGetMeterMetaInfoFromQueryInfo(pQueryInfo, 0); - int8_t p = pMeterMetaInfo->pMeterMeta->precision; + SMeterMetaInfo *pMeterMetaInfo = tscGetMeterMetaInfoFromQueryInfo(pQueryInfo, 0); + int8_t p = pMeterMetaInfo->pMeterMeta->precision; if (taosHasRemainsDataForInterpolation(pInterpoInfo)) { assert(pQueryInfo->interpoType != TSDB_INTERPO_NONE); @@ -1273,9 +1304,10 @@ static bool doInterpolationForCurrentGroup(SSqlObj *pSql) { int64_t etime = *(int64_t *)(pFinalDataBuf->data + TSDB_KEYSIZE * (pInterpoInfo->numOfRawDataInRows - 1)); int32_t remain = taosNumOfRemainPoints(pInterpoInfo); - TSKEY ekey = taosGetRevisedEndKey(etime, pQueryInfo->order.order, pQueryInfo->nAggTimeInterval, pQueryInfo->intervalTimeUnit, p); + TSKEY ekey = + taosGetRevisedEndKey(etime, pQueryInfo->order.order, pQueryInfo->intervalTime, pQueryInfo->intervalTimeUnit, p); int32_t rows = taosGetNumOfResultWithInterpo(pInterpoInfo, (TSKEY *)pLocalReducer->pBufForInterpo, remain, - pQueryInfo->nAggTimeInterval, ekey, pLocalReducer->resColModel->capacity); + pQueryInfo->intervalTime, ekey, pLocalReducer->resColModel->capacity); if (rows > 0) { // do interpo doInterpolateResult(pSql, pLocalReducer, false); } @@ -1295,9 +1327,9 @@ static bool doHandleLastRemainData(SSqlObj *pSql) { bool prevGroupCompleted = (!pLocalReducer->discard) && pLocalReducer->hasUnprocessedRow; - SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); - SMeterMetaInfo* pMeterMetaInfo = tscGetMeterMetaInfoFromQueryInfo(pQueryInfo, 0); - int8_t precision = pMeterMetaInfo->pMeterMeta->precision; + SQueryInfo * pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); + SMeterMetaInfo *pMeterMetaInfo = tscGetMeterMetaInfoFromQueryInfo(pQueryInfo, 0); + int8_t precision = pMeterMetaInfo->pMeterMeta->precision; if ((isAllSourcesCompleted(pLocalReducer) && !pLocalReducer->hasPrevRow) || pLocalReducer->pLocalDataSrc[0] == NULL || prevGroupCompleted) { @@ -1305,8 +1337,9 @@ static bool doHandleLastRemainData(SSqlObj *pSql) { if (pQueryInfo->interpoType != TSDB_INTERPO_NONE) { int64_t etime = (pQueryInfo->stime < pQueryInfo->etime) ? pQueryInfo->etime : pQueryInfo->stime; - etime = taosGetRevisedEndKey(etime, pQueryInfo->order.order, pQueryInfo->nAggTimeInterval, pQueryInfo->intervalTimeUnit, precision); - int32_t rows = taosGetNumOfResultWithInterpo(pInterpoInfo, NULL, 0, pQueryInfo->nAggTimeInterval, etime, + etime = taosGetRevisedEndKey(etime, pQueryInfo->order.order, pQueryInfo->intervalTime, + pQueryInfo->intervalTimeUnit, precision); + int32_t rows = taosGetNumOfResultWithInterpo(pInterpoInfo, NULL, 0, pQueryInfo->intervalTime, etime, pLocalReducer->resColModel->capacity); if (rows > 0) { // do interpo doInterpolateResult(pSql, pLocalReducer, true); @@ -1334,15 +1367,15 @@ static bool doHandleLastRemainData(SSqlObj *pSql) { return false; } -static void doMergeWithPrevRows(SSqlObj *pSql, int32_t numOfRes) { - SSqlCmd * pCmd = &pSql->cmd; - SSqlRes * pRes = &pSql->res; - +static void doProcessResultInNextWindow(SSqlObj *pSql, int32_t numOfRes) { + SSqlCmd *pCmd = &pSql->cmd; + SSqlRes *pRes = &pSql->res; + SLocalReducer *pLocalReducer = pRes->pLocalReducer; - SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); - - for (int32_t k = 0; k < pQueryInfo->fieldsInfo.numOfOutputCols; ++k) { - SSqlExpr *pExpr = tscSqlExprGet(pQueryInfo, k); + SQueryInfo * pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); + + for (int32_t k = 0; k < pQueryInfo->exprsInfo.numOfExprs; ++k) { + SSqlExpr * pExpr = tscSqlExprGet(pQueryInfo, k); SQLFunctionCtx *pCtx = &pLocalReducer->pCtx[k]; pCtx->aOutputBuf += pCtx->outputBytes * numOfRes; @@ -1359,24 +1392,24 @@ static void doMergeWithPrevRows(SSqlObj *pSql, int32_t numOfRes) { int32_t tscDoLocalreduce(SSqlObj *pSql) { SSqlCmd *pCmd = &pSql->cmd; SSqlRes *pRes = &pSql->res; - + tscResetForNextRetrieve(pRes); - + if (pSql->signature != pSql || pRes == NULL || pRes->pLocalReducer == NULL) { // all data has been processed tscTrace("%s call the drop local reducer", __FUNCTION__); tscDestroyLocalReducer(pSql); return 0; } - + SLocalReducer *pLocalReducer = pRes->pLocalReducer; - SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); - + SQueryInfo * pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); + // set the data merge in progress int32_t prevStatus = atomic_val_compare_exchange_32(&pLocalReducer->status, TSC_LOCALREDUCE_READY, TSC_LOCALREDUCE_IN_PROGRESS); if (prevStatus != TSC_LOCALREDUCE_READY || pLocalReducer == NULL) { - assert(prevStatus == TSC_LOCALREDUCE_TOBE_FREED); // it is in tscDestroyLocalReducer function already + assert(prevStatus == TSC_LOCALREDUCE_TOBE_FREED); // it is in tscDestroyLocalReducer function already return TSDB_CODE_SUCCESS; } @@ -1474,8 +1507,7 @@ int32_t tscDoLocalreduce(SSqlObj *pSql) { * if the previous group does NOT generate any result (pResBuf->numOfElems == 0), * continue to process results instead of return results. */ - if ((!sameGroup && pResBuf->numOfElems > 0) || - (pResBuf->numOfElems == pLocalReducer->resColModel->capacity)) { + if ((!sameGroup && pResBuf->numOfElems > 0) || (pResBuf->numOfElems == pLocalReducer->resColModel->capacity)) { // does not belong to the same group bool notSkipped = doGenerateFinalResults(pSql, pLocalReducer, !sameGroup); @@ -1528,7 +1560,7 @@ int32_t tscDoLocalreduce(SSqlObj *pSql) { return TSDB_CODE_SUCCESS; } } else { // result buffer is not full - doMergeWithPrevRows(pSql, numOfRes); + doProcessResultInNextWindow(pSql, numOfRes); savePreviousRow(pLocalReducer, tmpBuffer); } } diff --git a/src/client/src/tscServer.c b/src/client/src/tscServer.c index 10db2c47876d308a6a8e92ae2d1f54467154e107..c6efafe3329ff57e6d5c3f1dfadd1b49952c4beb 100644 --- a/src/client/src/tscServer.c +++ b/src/client/src/tscServer.c @@ -392,19 +392,23 @@ int32_t tscLaunchJoinSubquery(SSqlObj *pSql, int16_t tableIndex, SJoinSubquerySu tscColumnBaseInfoUpdateTableIndex(&pNewQueryInfo->colList, 0); tscColumnBaseInfoCopy(&pSupporter->colList, &pNewQueryInfo->colList, 0); - tscSqlExprCopy(&pSupporter->exprsInfo, &pNewQueryInfo->exprsInfo, pSupporter->uid); - + tscSqlExprCopy(&pSupporter->exprsInfo, &pNewQueryInfo->exprsInfo, pSupporter->uid, false); tscFieldInfoCopyAll(&pSupporter->fieldsInfo, &pNewQueryInfo->fieldsInfo); + tscTagCondCopy(&pSupporter->tagCond, &pNewQueryInfo->tagCond); pNew->cmd.numOfCols = 0; - pNewQueryInfo->nAggTimeInterval = 0; + pNewQueryInfo->intervalTime = 0; memset(&pNewQueryInfo->limit, 0, sizeof(SLimitVal)); // backup the data and clear it in the sqlcmd object pSupporter->groupbyExpr = pNewQueryInfo->groupbyExpr; memset(&pNewQueryInfo->groupbyExpr, 0, sizeof(SSqlGroupbyExpr)); + // this data needs to be transfer to support struct + pNewQueryInfo->fieldsInfo.numOfOutputCols = 0; + pNewQueryInfo->exprsInfo.numOfExprs = 0; + // set the ts,tags that involved in join, as the output column of intermediate result tscClearSubqueryInfo(&pNew->cmd); @@ -649,7 +653,7 @@ int tscLaunchSTableSubqueries(SSqlObj *pSql) { tExtMemBuffer ** pMemoryBuf = NULL; tOrderDescriptor *pDesc = NULL; - SColumnModel * pModel = NULL; + SColumnModel * pModel = NULL; pRes->qhandle = 1; // hack the qhandle check @@ -1066,8 +1070,6 @@ void tscKillMetricQuery(SSqlObj *pSql) { //taosStopRpcConn(pSql->pSubs[i]->thandle); } - pSql->numOfSubs = 0; - /* * 1. if the subqueries are not launched or partially launched, we need to waiting the launched * query return to successfully free allocated resources. @@ -1290,7 +1292,7 @@ static int32_t tscEstimateQueryMsgSize(SSqlCmd *pCmd, int32_t clauseIndex) { int32_t srcColListSize = pQueryInfo->colList.numOfCols * sizeof(SColumnInfo); - int32_t exprSize = sizeof(SSqlFuncExprMsg) * pQueryInfo->fieldsInfo.numOfOutputCols; + int32_t exprSize = sizeof(SSqlFuncExprMsg) * pQueryInfo->exprsInfo.numOfExprs; SMeterMetaInfo *pMeterMetaInfo = tscGetMeterMetaInfoFromQueryInfo(pQueryInfo, 0); // meter query without tags values @@ -1299,11 +1301,10 @@ static int32_t tscEstimateQueryMsgSize(SSqlCmd *pCmd, int32_t clauseIndex) { } SSuperTableMeta *pMetricMeta = pMeterMetaInfo->pMetricMeta; - SVnodeSidList *pVnodeSidList = tscGetVnodeSidList(pMetricMeta, pMeterMetaInfo->vnodeIndex); int32_t meterInfoSize = (pMetricMeta->tagLen + sizeof(STableSidExtInfo)) * pVnodeSidList->numOfSids; - int32_t outputColumnSize = pQueryInfo->fieldsInfo.numOfOutputCols * sizeof(SSqlFuncExprMsg); + int32_t outputColumnSize = pQueryInfo->exprsInfo.numOfExprs * sizeof(SSqlFuncExprMsg); int32_t size = meterInfoSize + outputColumnSize + srcColListSize + exprSize + MIN_QUERY_MSG_PKT_SIZE; if (pQueryInfo->tsBuf != NULL) { @@ -1319,7 +1320,7 @@ static char *doSerializeTableInfo(SSqlObj *pSql, int32_t numOfTables, int32_t vn STableMeta * pMeterMeta = pMeterMetaInfo->pMeterMeta; SSuperTableMeta *pMetricMeta = pMeterMetaInfo->pMetricMeta; - tscTrace("%p vid:%d, query on %d meters", pSql, htons(vnodeId), numOfTables); + tscTrace("%p vid:%d, query on %d meters", pSql, vnodeId, numOfTables); if (UTIL_METER_IS_NOMRAL_METER(pMeterMetaInfo)) { #ifdef _DEBUG_VIEW tscTrace("%p sid:%d, uid:%" PRIu64, pSql, pMeterMetaInfo->pMeterMeta->sid, pMeterMetaInfo->pMeterMeta->uid); @@ -1436,12 +1437,12 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) { return -1; } - pQueryMsg->nAggTimeInterval = htobe64(pQueryInfo->nAggTimeInterval); + pQueryMsg->intervalTime = htobe64(pQueryInfo->intervalTime); pQueryMsg->intervalTimeUnit = pQueryInfo->intervalTimeUnit; - pQueryMsg->slidingTime = htobe64(pQueryInfo->nSlidingTime); + pQueryMsg->slidingTime = htobe64(pQueryInfo->slidingTime); - if (pQueryInfo->nAggTimeInterval < 0) { - tscError("%p illegal value of aggregation time interval in query msg: %ld", pSql, pQueryInfo->nAggTimeInterval); + if (pQueryInfo->intervalTime < 0) { + tscError("%p illegal value of aggregation time interval in query msg: %ld", pSql, pQueryInfo->intervalTime); return -1; } @@ -1521,7 +1522,7 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) { SSqlFuncExprMsg *pSqlFuncExpr = (SSqlFuncExprMsg *)pMsg; - for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { + for (int32_t i = 0; i < tscSqlExprNumOfExprs(pQueryInfo); ++i) { SSqlExpr *pExpr = tscSqlExprGet(pQueryInfo, i); if (pExpr->functionId == TSDB_FUNC_ARITHM) { @@ -1615,6 +1616,9 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) { *((int16_t *)pMsg) += pCol->flag; pMsg += sizeof(pCol->flag); + + memcpy(pMsg, pCol->name, tListLen(pCol->name)); + pMsg += tListLen(pCol->name); } } @@ -2124,16 +2128,8 @@ static int tscSetResultPointer(SQueryInfo *pQueryInfo, SSqlRes *pRes) { } for (int i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { - TAOS_FIELD *pField = tscFieldInfoGetField(pQueryInfo, i); - int16_t offset = tscFieldInfoGetOffset(pQueryInfo, i); - - pRes->bytes[i] = pField->bytes; -// if (pQueryInfo->order.order == TSQL_SO_DESC) { -// pRes->bytes[i] = -pRes->bytes[i]; -// pRes->tsrow[i] = ((pRes->data + offset * pRes->numOfRows) + (pRes->numOfRows - 1) * pField->bytes); -// } else { - pRes->tsrow[i] = (pRes->data + offset * pRes->numOfRows); -// } + int16_t offset = tscFieldInfoGetOffset(pQueryInfo, i); + pRes->tsrow[i] = (pRes->data + offset * pRes->numOfRows); } return 0; @@ -2348,8 +2344,10 @@ static int32_t tscEstimateMetricMetaMsgSize(SSqlCmd *pCmd) { int32_t joinCondLen = (TSDB_TABLE_ID_LEN + sizeof(int16_t)) * 2; int32_t elemSize = sizeof(SSuperTableMetaElemMsg) * pQueryInfo->numOfTables; + + int32_t colSize = pQueryInfo->groupbyExpr.numOfGroupCols*sizeof(SColIndexEx); - int32_t len = tagLen + joinCondLen + elemSize + defaultSize; + int32_t len = tagLen + joinCondLen + elemSize + colSize + defaultSize; return MAX(len, TSDB_DEFAULT_PAYLOAD_SIZE); } @@ -2418,7 +2416,7 @@ int tscBuildMetricMetaMsg(SSqlObj *pSql, SSqlInfo *pInfo) { int32_t condLen = 0; if (pTagCond->numOfTagCond > 0) { SCond *pCond = tsGetMetricQueryCondPos(pTagCond, uid); - if (pCond != NULL) { + if (pCond != NULL && pCond->cond != NULL) { condLen = strlen(pCond->cond) + 1; bool ret = taosMbsToUcs4(pCond->cond, condLen, pMsg, condLen * TSDB_NCHAR_SIZE); @@ -2440,11 +2438,14 @@ int tscBuildMetricMetaMsg(SSqlObj *pSql, SSqlInfo *pInfo) { offset = pMsg - (char *)pMetaMsg; pElem->tableCond = htonl(offset); - - uint32_t len = strlen(pTagCond->tbnameCond.cond); + + uint32_t len = 0; + if (pTagCond->tbnameCond.cond != NULL) { + len = strlen(pTagCond->tbnameCond.cond); + memcpy(pMsg, pTagCond->tbnameCond.cond, len); + } + pElem->tableCondLen = htonl(len); - - memcpy(pMsg, pTagCond->tbnameCond.cond, len); pMsg += len; } @@ -2474,6 +2475,7 @@ int tscBuildMetricMetaMsg(SSqlObj *pSql, SSqlInfo *pInfo) { pDestCol->colIdx = htons(pCol->colIdx); pDestCol->colId = htons(pDestCol->colId); pDestCol->flag = htons(pDestCol->flag); + strncpy(pDestCol->name, pCol->name, tListLen(pCol->name)); pMsg += sizeof(SColIndexEx); } @@ -2913,6 +2915,9 @@ int tscProcessShowRsp(SSqlObj *pSql) { index.columnIndex = i; tscColumnBaseInfoInsert(pQueryInfo, &index); tscFieldInfoSetValFromSchema(&pQueryInfo->fieldsInfo, i, &pMeterSchema[i]); + + pQueryInfo->fieldsInfo.pSqlExpr[i] = tscSqlExprInsert(pQueryInfo, i, TSDB_FUNC_TS_DUMMY, &index, + pMeterSchema[i].type, pMeterSchema[i].bytes, pMeterSchema[i].bytes); } tscFieldInfoCalOffset(pQueryInfo); diff --git a/src/client/src/tscSql.c b/src/client/src/tscSql.c index 26569313f300b916a7b17aa13ab7ab719ca4f2cf..2f3312b0b6dca5d8ec5db584b4ca732b91fcdcdf 100644 --- a/src/client/src/tscSql.c +++ b/src/client/src/tscSql.c @@ -13,8 +13,9 @@ * along with this program. If not, see . */ -#include "os.h" +#include #include "hash.h" +#include "os.h" #include "tcache.h" #include "tlog.h" #include "tnote.h" @@ -208,7 +209,7 @@ int taos_query_imp(STscObj *pObj, SSqlObj *pSql) { taosCleanUpHashTable(pSql->pTableHashList); pSql->pTableHashList = NULL; } - + tscDump("%p pObj:%p, SQL: %s", pSql, pObj, pSql->sqlstr); pRes->code = (uint8_t)tsParseSql(pSql, false); @@ -374,9 +375,7 @@ int taos_fetch_block_impl(TAOS_RES *res, TAOS_ROW *rows) { SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, 0); for (int i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { -// pRes->tsrow[i] = TSC_GET_RESPTR_BASE(pRes, pQueryInfo, i, pQueryInfo->order) + -// pRes->bytes[i] * (1 - pQueryInfo->order.order) * (pRes->numOfRows - 1); - pRes->tsrow[i] = TSC_GET_RESPTR_BASE(pRes, pQueryInfo, i, pQueryInfo->order); + pRes->tsrow[i] = TSC_GET_RESPTR_BASE(pRes, pQueryInfo, i); } *rows = pRes->tsrow; @@ -384,54 +383,115 @@ int taos_fetch_block_impl(TAOS_RES *res, TAOS_ROW *rows) { return (pQueryInfo->order.order == TSQL_SO_DESC) ? pRes->numOfRows : -pRes->numOfRows; } +static void transferNcharData(SSqlObj *pSql, int32_t columnIndex, TAOS_FIELD *pField) { + SSqlRes *pRes = &pSql->res; + + if (isNull(pRes->tsrow[columnIndex], pField->type)) { + pRes->tsrow[columnIndex] = NULL; + } else if (pField->type == TSDB_DATA_TYPE_NCHAR) { + // convert unicode to native code in a temporary buffer extra one byte for terminated symbol + if (pRes->buffer[columnIndex] == NULL) { + pRes->buffer[columnIndex] = malloc(pField->bytes + TSDB_NCHAR_SIZE); + } + + /* string terminated char for binary data*/ + memset(pRes->buffer[columnIndex], 0, pField->bytes + TSDB_NCHAR_SIZE); + + if (taosUcs4ToMbs(pRes->tsrow[columnIndex], pField->bytes, pRes->buffer[columnIndex])) { + pRes->tsrow[columnIndex] = pRes->buffer[columnIndex]; + } else { + tscError("%p charset:%s to %s. val:%ls convert failed.", pSql, DEFAULT_UNICODE_ENCODEC, tsCharset, pRes->tsrow); + pRes->tsrow[columnIndex] = NULL; + } + } +} + +static char *getArithemicInputSrc(void *param, char *name, int32_t colId) { + SArithmeticSupport *pSupport = (SArithmeticSupport *)param; + SSqlFunctionExpr * pExpr = pSupport->pExpr; + + int32_t index = -1; + for (int32_t i = 0; i < pExpr->pBinExprInfo.numOfCols; ++i) { + if (strcmp(name, pExpr->pBinExprInfo.pReqColumns[i].name) == 0) { + index = i; + break; + } + } + + assert(index >= 0 && index < pExpr->pBinExprInfo.numOfCols); + return pSupport->data[index] + pSupport->offset * pSupport->elemSize[index]; +} + static void **doSetResultRowData(SSqlObj *pSql) { SSqlCmd *pCmd = &pSql->cmd; SSqlRes *pRes = &pSql->res; - + assert(pRes->row >= 0 && pRes->row <= pRes->numOfRows); - + if (pRes->row >= pRes->numOfRows) { // all the results has returned to invoker tfree(pRes->tsrow); return pRes->tsrow; } - - SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); + SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); + + //todo refactor move away + for(int32_t k = 0; k < pQueryInfo->exprsInfo.numOfExprs; ++k) { + SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, k); + + if (k > 0) { + SSqlExpr* pPrev = tscSqlExprGet(pQueryInfo, k - 1); + pExpr->offset = pPrev->offset + pPrev->resBytes; + } + } + int32_t num = 0; - for (int i = 0; i < pQueryInfo->fieldsInfo.numOfOutputCols; ++i) { - pRes->tsrow[i] = TSC_GET_RESPTR_BASE(pRes, pQueryInfo, i, pQueryInfo->order) + pRes->bytes[i] * pRes->row; + for (int i = 0; i < tscNumOfFields(pQueryInfo); ++i) { + if (pQueryInfo->fieldsInfo.pSqlExpr[i] != NULL) { + SSqlExpr* pExpr = pQueryInfo->fieldsInfo.pSqlExpr[i]; + pRes->tsrow[i] = TSC_GET_RESPTR_BASE(pRes, pQueryInfo, i) + pExpr->resBytes * pRes->row; + } else { + assert(0); + } // primary key column cannot be null in interval query, no need to check - if (i == 0 && pQueryInfo->nAggTimeInterval > 0) { + if (i == 0 && pQueryInfo->intervalTime > 0) { continue; } TAOS_FIELD *pField = tscFieldInfoGetField(pQueryInfo, i); - if (isNull(pRes->tsrow[i], pField->type)) { - pRes->tsrow[i] = NULL; - } else if (pField->type == TSDB_DATA_TYPE_NCHAR) { - // convert unicode to native code in a temporary buffer extra one byte for terminated symbol - if (pRes->buffer[num] == NULL) { - pRes->buffer[num] = malloc(pField->bytes + TSDB_NCHAR_SIZE); - } - - /* string terminated char for binary data*/ - memset(pRes->buffer[num], 0, pField->bytes + TSDB_NCHAR_SIZE); + transferNcharData(pSql, i, pField); - if (taosUcs4ToMbs(pRes->tsrow[i], pField->bytes, pRes->buffer[num])) { - pRes->tsrow[i] = pRes->buffer[num]; - } else { - tscError("%p charset:%s to %s. val:%ls convert failed.", pSql, DEFAULT_UNICODE_ENCODEC, tsCharset, pRes->tsrow); - pRes->tsrow[i] = NULL; + // calculate the result from serveral other columns + if (pQueryInfo->fieldsInfo.pExpr != NULL && pQueryInfo->fieldsInfo.pExpr[i] != NULL) { + SArithmeticSupport *sas = (SArithmeticSupport *)calloc(1, sizeof(SArithmeticSupport)); + sas->offset = 0; + sas->pExpr = pQueryInfo->fieldsInfo.pExpr[i]; + + sas->numOfCols = sas->pExpr->pBinExprInfo.numOfCols; + + if (pRes->buffer[i] == NULL) { + pRes->buffer[i] = malloc(tscFieldInfoGetField(pQueryInfo, i)->bytes); + } + + for(int32_t k = 0; k < sas->numOfCols; ++k) { + int32_t columnIndex = sas->pExpr->pBinExprInfo.pReqColumns[k].colIdxInBuf; + SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, columnIndex); + + sas->elemSize[k] = pExpr->resBytes; + sas->data[k] = (pRes->data + pRes->numOfRows* pExpr->offset) + pRes->row*pExpr->resBytes; } + + tSQLBinaryExprCalcTraverse(sas->pExpr->pBinExprInfo.pBinExpr, 1, pRes->buffer[i], sas, TSQL_SO_ASC, getArithemicInputSrc); + pRes->tsrow[i] = pRes->buffer[i]; - num++; + free(sas); //todo optimization } } assert(num <= pQueryInfo->fieldsInfo.numOfOutputCols); - - pRes->row++; // index increase one-step + + pRes->row++; // index increase one-step return pRes->tsrow; } @@ -473,7 +533,7 @@ static bool tscHashRemainDataInSubqueryResultSet(SSqlObj *pSql) { if (pSql->pSubs[i] == 0) { continue; } - + SSqlRes * pRes1 = &pSql->pSubs[i]->res; SQueryInfo *pQueryInfo1 = tscGetQueryInfoDetail(&pSql->pSubs[i]->cmd, 0); @@ -509,11 +569,10 @@ static void **tscBuildResFromSubqueries(SSqlObj *pSql) { if (numOfTableHasRes >= 2) { // do merge result - success = (doSetResultRowData(pSql->pSubs[0]) != NULL) && - (doSetResultRowData(pSql->pSubs[1]) != NULL); - // TSKEY key1 = *(TSKEY *)pRes1->tsrow[0]; - // TSKEY key2 = *(TSKEY *)pRes2->tsrow[0]; - // printf("first:%" PRId64 ", second:%" PRId64 "\n", key1, key2); + success = (doSetResultRowData(pSql->pSubs[0]) != NULL) && (doSetResultRowData(pSql->pSubs[1]) != NULL); + // TSKEY key1 = *(TSKEY *)pRes1->tsrow[0]; + // TSKEY key2 = *(TSKEY *)pRes2->tsrow[0]; + // printf("first:%" PRId64 ", second:%" PRId64 "\n", key1, key2); } else { // only one subquery SSqlObj *pSub = pSql->pSubs[0]; if (pSub == NULL) { @@ -603,7 +662,7 @@ TAOS_ROW taos_fetch_row_impl(TAOS_RES *res) { tscProcessSql(pSql); // retrieve data from virtual node - //if failed to retrieve data from current virtual node, try next one if exists + // if failed to retrieve data from current virtual node, try next one if exists if (hasMoreVnodesToTry(pSql)) { tscTryQueryNextVnode(pSql, NULL); } @@ -645,7 +704,7 @@ TAOS_ROW taos_fetch_row(TAOS_RES *res) { // current subclause is completed, try the next subclause while (rows == NULL && pCmd->clauseIndex < pCmd->numOfClause - 1) { tscTryQueryNextClause(pSql, NULL); - + // if the rows is not NULL, return immediately rows = taos_fetch_row_impl(res); } @@ -708,7 +767,7 @@ int taos_select_db(TAOS *taos, const char *db) { return taos_query(taos, sql); } -void taos_free_result_imp(TAOS_RES* res, int keepCmd) { +void taos_free_result_imp(TAOS_RES *res, int keepCmd) { if (res == NULL) return; SSqlObj *pSql = (SSqlObj *)res; @@ -761,7 +820,7 @@ void taos_free_result_imp(TAOS_RES* res, int keepCmd) { pCmd->command = (pCmd->command > TSDB_SQL_MGMT) ? TSDB_SQL_RETRIEVE : TSDB_SQL_FETCH; tscTrace("%p code:%d, numOfRows:%d, command:%d", pSql, pRes->code, pRes->numOfRows, pCmd->command); - + void *fp = pSql->fp; if (fp != NULL) { pSql->freed = 1; @@ -808,9 +867,7 @@ void taos_free_result_imp(TAOS_RES* res, int keepCmd) { } } -void taos_free_result(TAOS_RES *res) { - taos_free_result_imp(res, 0); -} +void taos_free_result(TAOS_RES *res) { taos_free_result_imp(res, 0); } int taos_errno(TAOS *taos) { STscObj *pObj = (STscObj *)taos; @@ -826,26 +883,24 @@ int taos_errno(TAOS *taos) { return code; } -static bool validErrorCode(int32_t code) { - return code >= TSDB_CODE_SUCCESS && code < TSDB_CODE_MAX_ERROR_CODE; -} +static bool validErrorCode(int32_t code) { return code >= TSDB_CODE_SUCCESS && code < TSDB_CODE_MAX_ERROR_CODE; } /* * In case of invalid sql error, additional information is attached to explain * why the sql is invalid */ -static bool hasAdditionalErrorInfo(int32_t code, SSqlCmd* pCmd) { +static bool hasAdditionalErrorInfo(int32_t code, SSqlCmd *pCmd) { if (code != TSDB_CODE_INVALID_SQL) { return false; } size_t len = strlen(pCmd->payload); - - char* z = NULL; + + char *z = NULL; if (len > 0) { - z = strstr (pCmd->payload, "invalid SQL"); + z = strstr(pCmd->payload, "invalid SQL"); } - + return z != NULL; } @@ -856,12 +911,12 @@ char *taos_errstr(TAOS *taos) { if (pObj == NULL || pObj->signature != pObj) return (char*)tstrerror(globalCode); - SSqlObj* pSql = pObj->pSql; - + SSqlObj *pSql = pObj->pSql; + if (validErrorCode(pSql->res.code)) { code = pSql->res.code; } else { - code = TSDB_CODE_OTHERS; //unknown error + code = TSDB_CODE_OTHERS; // unknown error } if (hasAdditionalErrorInfo(code, &pSql->cmd)) { @@ -954,14 +1009,14 @@ int taos_print_row(char *str, TAOS_ROW row, TAOS_FIELD *fields, int num_fields) case TSDB_DATA_TYPE_BINARY: case TSDB_DATA_TYPE_NCHAR: { - size_t xlen = 0; - for (xlen = 0; xlen <= fields[i].bytes; xlen++) { - char c = ((char*)row[i])[xlen]; - if (c == 0) break; - str[len++] = c; - } - str[len] = 0; - } break; + size_t xlen = 0; + for (xlen = 0; xlen <= fields[i].bytes; xlen++) { + char c = ((char *)row[i])[xlen]; + if (c == 0) break; + str[len++] = c; + } + str[len] = 0; + } break; case TSDB_DATA_TYPE_TIMESTAMP: len += sprintf(str + len, "%" PRId64, *((int64_t *)row[i])); diff --git a/src/client/src/tscStream.c b/src/client/src/tscStream.c index 79b524be0f8fd9b18847e03e9420941c6ec0c05c..5fd0adf5b15b31abe741dd51025e8e0a5a211230 100644 --- a/src/client/src/tscStream.c +++ b/src/client/src/tscStream.c @@ -246,8 +246,6 @@ static void tscProcessStreamRetrieveResult(void *param, TAOS_RES *res, int numOf int32_t retry = tsProjectExecInterval; tscError("%p stream:%p, retrieve no data, code:%d, retry in %" PRId64 "ms", pSql, pStream, numOfRows, retry); - tscClearSqlMetaInfoForce(&(pStream->pSql->cmd)); - tscSetRetryTimer(pStream, pStream->pSql, retry); return; } @@ -381,41 +379,41 @@ static void tscSetSlidingWindowInfo(SSqlObj *pSql, SSqlStream *pStream) { SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0); - if (pQueryInfo->nAggTimeInterval < minIntervalTime) { + if (pQueryInfo->intervalTime < minIntervalTime) { tscWarn("%p stream:%p, original sample interval:%ld too small, reset to:%" PRId64 "", pSql, pStream, - pQueryInfo->nAggTimeInterval, minIntervalTime); - pQueryInfo->nAggTimeInterval = minIntervalTime; + pQueryInfo->intervalTime, minIntervalTime); + pQueryInfo->intervalTime = minIntervalTime; } - pStream->interval = pQueryInfo->nAggTimeInterval; // it shall be derived from sql string + pStream->interval = pQueryInfo->intervalTime; // it shall be derived from sql string - if (pQueryInfo->nSlidingTime == 0) { - pQueryInfo->nSlidingTime = pQueryInfo->nAggTimeInterval; + if (pQueryInfo->slidingTime == 0) { + pQueryInfo->slidingTime = pQueryInfo->intervalTime; } int64_t minSlidingTime = (pStream->precision == TSDB_TIME_PRECISION_MICRO) ? tsMinSlidingTime * 1000L : tsMinSlidingTime; - if (pQueryInfo->nSlidingTime == -1) { - pQueryInfo->nSlidingTime = pQueryInfo->nAggTimeInterval; - } else if (pQueryInfo->nSlidingTime < minSlidingTime) { + if (pQueryInfo->slidingTime == -1) { + pQueryInfo->slidingTime = pQueryInfo->intervalTime; + } else if (pQueryInfo->slidingTime < minSlidingTime) { tscWarn("%p stream:%p, original sliding value:%" PRId64 " too small, reset to:%" PRId64 "", pSql, pStream, - pQueryInfo->nSlidingTime, minSlidingTime); + pQueryInfo->slidingTime, minSlidingTime); - pQueryInfo->nSlidingTime = minSlidingTime; + pQueryInfo->slidingTime = minSlidingTime; } - if (pQueryInfo->nSlidingTime > pQueryInfo->nAggTimeInterval) { + if (pQueryInfo->slidingTime > pQueryInfo->intervalTime) { tscWarn("%p stream:%p, sliding value:%" PRId64 " can not be larger than interval range, reset to:%" PRId64 "", pSql, pStream, - pQueryInfo->nSlidingTime, pQueryInfo->nAggTimeInterval); + pQueryInfo->slidingTime, pQueryInfo->intervalTime); - pQueryInfo->nSlidingTime = pQueryInfo->nAggTimeInterval; + pQueryInfo->slidingTime = pQueryInfo->intervalTime; } - pStream->slidingTime = pQueryInfo->nSlidingTime; + pStream->slidingTime = pQueryInfo->slidingTime; - pQueryInfo->nAggTimeInterval = 0; // clear the interval value to avoid the force time window split by query processor - pQueryInfo->nSlidingTime = 0; + pQueryInfo->intervalTime = 0; // clear the interval value to avoid the force time window split by query processor + pQueryInfo->slidingTime = 0; } static int64_t tscGetStreamStartTimestamp(SSqlObj *pSql, SSqlStream *pStream, int64_t stime) { diff --git a/src/client/src/tscUtil.c b/src/client/src/tscUtil.c index 624220c3734cdf642ea4c977adda77cf4baea931..2a5af0473c8bc5c8e40807c43ee1968a9ead24f0 100644 --- a/src/client/src/tscUtil.c +++ b/src/client/src/tscUtil.c @@ -27,6 +27,7 @@ #include "tsclient.h" #include "tsqldef.h" #include "ttimer.h" +#include "tast.h" /* * the detailed information regarding metric meta key is: @@ -64,7 +65,7 @@ void tscGetMetricMetaCacheKey(SQueryInfo* pQueryInfo, char* str, uint64_t uid) { size_t redundantLen = 20; size_t bufSize = strlen(pMeterMetaInfo->name) + tbnameCondLen + strlen(join) + strlen(tagIdBuf); - if (cond != NULL) { + if (cond != NULL && cond->cond != NULL) { bufSize += strlen(cond->cond); } @@ -72,7 +73,7 @@ void tscGetMetricMetaCacheKey(SQueryInfo* pQueryInfo, char* str, uint64_t uid) { char* tmp = calloc(1, bufSize); int32_t keyLen = snprintf(tmp, bufSize, "%s,%s,%s,%d,%s,[%s],%d", pMeterMetaInfo->name, - (cond != NULL ? cond->cond : NULL), (tbnameCondLen > 0 ? pTagCond->tbnameCond.cond : NULL), + ((cond != NULL && cond->cond != NULL) ? cond->cond : NULL), (tbnameCondLen > 0 ? pTagCond->tbnameCond.cond : NULL), pTagCond->relType, join, tagIdBuf, pQueryInfo->groupbyExpr.orderType); assert(keyLen <= bufSize); @@ -202,6 +203,9 @@ STableSidExtInfo* tscGetMeterSidInfo(SVnodeSidList* pSidList, int32_t idx) { tscError("illegal sidIdx:%d, reset to 0, sidIdx range:%d-%d", idx, 0, sidRange); idx = 0; } + + assert(pSidList->pSidExtInfoList[idx] >= 0); + return (STableSidExtInfo*)(pSidList->pSidExtInfoList[idx] + (char*)pSidList); } @@ -211,7 +215,16 @@ bool tscIsTwoStageMergeMetricQuery(SQueryInfo* pQueryInfo, int32_t tableIndex) { } SMeterMetaInfo* pMeterMetaInfo = tscGetMeterMetaInfoFromQueryInfo(pQueryInfo, tableIndex); - if (pMeterMetaInfo == NULL || pMeterMetaInfo->pMetricMeta == NULL) { + if (pMeterMetaInfo == NULL) { + return false; + } + + // for select query super table, the metricmeta can not be null in any cases. + if (pQueryInfo->command == TSDB_SQL_SELECT && UTIL_METER_IS_SUPERTABLE(pMeterMetaInfo)) { + assert(pMeterMetaInfo->pMetricMeta != NULL); + } + + if (pMeterMetaInfo->pMetricMeta == NULL) { return false; } @@ -335,35 +348,17 @@ void tscClearInterpInfo(SQueryInfo* pQueryInfo) { tfree(pQueryInfo->defaultVal); } -void tscClearSqlMetaInfoForce(SSqlCmd* pCmd) { - /* remove the metermeta/metricmeta in cache */ - // taosRemoveDataFromCache(tscCacheHandle, (void**)&(pCmd->pMeterMeta), true); - // taosRemoveDataFromCache(tscCacheHandle, (void**)&(pCmd->pMetricMeta), true); -} - int32_t tscCreateResPointerInfo(SSqlRes* pRes, SQueryInfo* pQueryInfo) { if (pRes->tsrow == NULL) { - pRes->numOfnchar = 0; - int32_t numOfOutputCols = pQueryInfo->fieldsInfo.numOfOutputCols; - for (int32_t i = 0; i < numOfOutputCols; ++i) { - TAOS_FIELD* pField = tscFieldInfoGetField(pQueryInfo, i); - if (pField->type == TSDB_DATA_TYPE_NCHAR) { - pRes->numOfnchar++; - } - } + pRes->numOfCols = numOfOutputCols; - pRes->tsrow = calloc(1, (POINTER_BYTES + sizeof(short)) * numOfOutputCols + POINTER_BYTES * pRes->numOfnchar); - pRes->bytes = calloc(numOfOutputCols, sizeof(short)); - - if (pRes->numOfnchar > 0) { - pRes->buffer = calloc(POINTER_BYTES, pRes->numOfnchar); - } + pRes->tsrow = calloc(POINTER_BYTES, numOfOutputCols); + pRes->buffer = calloc(POINTER_BYTES, numOfOutputCols); // not enough memory - if (pRes->tsrow == NULL || pRes->bytes == NULL || (pRes->buffer == NULL && pRes->numOfnchar > 0)) { + if (pRes->tsrow == NULL || (pRes->buffer == NULL && pRes->numOfCols > 0)) { tfree(pRes->tsrow); - tfree(pRes->bytes); tfree(pRes->buffer); pRes->code = TSDB_CODE_CLI_OUT_OF_MEMORY; @@ -376,13 +371,12 @@ int32_t tscCreateResPointerInfo(SSqlRes* pRes, SQueryInfo* pQueryInfo) { void tscDestroyResPointerInfo(SSqlRes* pRes) { if (pRes->buffer != NULL) { - assert(pRes->numOfnchar > 0); // free all buffers containing the multibyte string - for (int i = 0; i < pRes->numOfnchar; i++) { + for (int i = 0; i < pRes->numOfCols; i++) { tfree(pRes->buffer[i]); } - pRes->numOfnchar = 0; + pRes->numOfCols = 0; } tfree(pRes->pRsp); @@ -391,7 +385,6 @@ void tscDestroyResPointerInfo(SSqlRes* pRes) { tfree(pRes->pGroupRec); tfree(pRes->pColumnIndex); tfree(pRes->buffer); - tfree(pRes->bytes); pRes->data = NULL; // pRes->data points to the buffer of pRsp, no need to free } @@ -835,11 +828,18 @@ static void ensureSpace(SFieldInfo* pFieldInfo, int32_t size) { pFieldInfo->pFields = realloc(pFieldInfo->pFields, newSize * sizeof(TAOS_FIELD)); memset(&pFieldInfo->pFields[oldSize], 0, inc * sizeof(TAOS_FIELD)); - pFieldInfo->pOffset = realloc(pFieldInfo->pOffset, newSize * sizeof(int16_t)); - memset(&pFieldInfo->pOffset[oldSize], 0, inc * sizeof(int16_t)); +// pFieldInfo->pOffset = realloc(pFieldInfo->pOffset, newSize * sizeof(int16_t)); +// memset(&pFieldInfo->pOffset[oldSize], 0, inc * sizeof(int16_t)); pFieldInfo->pVisibleCols = realloc(pFieldInfo->pVisibleCols, newSize * sizeof(bool)); + memset(&pFieldInfo->pVisibleCols[oldSize], 0, inc * sizeof(bool)); + pFieldInfo->pSqlExpr = realloc(pFieldInfo->pSqlExpr, POINTER_BYTES*newSize); + pFieldInfo->pExpr = realloc(pFieldInfo->pExpr, POINTER_BYTES*newSize); + + memset(&pFieldInfo->pSqlExpr[oldSize], 0, inc * POINTER_BYTES); + memset(&pFieldInfo->pExpr[oldSize], 0, inc * POINTER_BYTES); + pFieldInfo->numOfAlloc = newSize; } } @@ -848,6 +848,15 @@ static void evic(SFieldInfo* pFieldInfo, int32_t index) { if (index < pFieldInfo->numOfOutputCols) { memmove(&pFieldInfo->pFields[index + 1], &pFieldInfo->pFields[index], sizeof(pFieldInfo->pFields[0]) * (pFieldInfo->numOfOutputCols - index)); + + memmove(&pFieldInfo->pVisibleCols[index + 1], &pFieldInfo->pVisibleCols[index], + sizeof(pFieldInfo->pVisibleCols[0]) * (pFieldInfo->numOfOutputCols - index)); + + memmove(&pFieldInfo->pSqlExpr[index + 1], &pFieldInfo->pSqlExpr[index], + sizeof(pFieldInfo->pSqlExpr[0]) * (pFieldInfo->numOfOutputCols - index)); + + memmove(&pFieldInfo->pExpr[index + 1], &pFieldInfo->pExpr[index], + sizeof(pFieldInfo->pExpr[0]) * (pFieldInfo->numOfOutputCols - index)); } } @@ -872,7 +881,6 @@ void tscFieldInfoSetValFromField(SFieldInfo* pFieldInfo, int32_t index, TAOS_FIE memcpy(&pFieldInfo->pFields[index], pField, sizeof(TAOS_FIELD)); pFieldInfo->pVisibleCols[index] = true; - pFieldInfo->numOfOutputCols++; } @@ -906,29 +914,49 @@ void tscFieldInfoSetValue(SFieldInfo* pFieldInfo, int32_t index, int8_t type, co pFieldInfo->numOfOutputCols++; } -void tscFieldInfoCalOffset(SQueryInfo* pQueryInfo) { - SFieldInfo* pFieldInfo = &pQueryInfo->fieldsInfo; - pFieldInfo->pOffset[0] = 0; +void tscFieldInfoSetExpr(SFieldInfo* pFieldInfo, int32_t index, SSqlExpr* pExpr) { + assert(index >= 0 && index < pFieldInfo->numOfOutputCols); + pFieldInfo->pSqlExpr[index] = pExpr; +} + +void tscFieldInfoSetBinExpr(SFieldInfo* pFieldInfo, int32_t index, SSqlFunctionExpr* pExpr) { + assert(index >= 0 && index < pFieldInfo->numOfOutputCols); + pFieldInfo->pExpr[index] = pExpr; +} - for (int32_t i = 1; i < pFieldInfo->numOfOutputCols; ++i) { - pFieldInfo->pOffset[i] = pFieldInfo->pOffset[i - 1] + pFieldInfo->pFields[i - 1].bytes; +void tscFieldInfoCalOffset(SQueryInfo* pQueryInfo) { + SSqlExprInfo* pExprInfo = &pQueryInfo->exprsInfo; + pExprInfo->pExprs[0]->offset = 0; + + for (int32_t i = 1; i < pExprInfo->numOfExprs; ++i) { + pExprInfo->pExprs[i]->offset = pExprInfo->pExprs[i - 1]->offset + pExprInfo->pExprs[i - 1]->resBytes; } } void tscFieldInfoUpdateOffsetForInterResult(SQueryInfo* pQueryInfo) { - SFieldInfo* pFieldInfo = &pQueryInfo->fieldsInfo; - if (pFieldInfo->numOfOutputCols == 0) { +// SFieldInfo* pFieldInfo = &pQueryInfo->fieldsInfo; +// if (pFieldInfo->numOfOutputCols == 0) { +// return; +// } +// +// pFieldInfo->pOffset[0] = 0; +// +// /* +// * the retTypeLen is used to store the intermediate result length +// * for potential secondary merge exists +// */ +// for (int32_t i = 1; i < pFieldInfo->numOfOutputCols; ++i) { +// pFieldInfo->pOffset[i] = pFieldInfo->pOffset[i - 1] + tscSqlExprGet(pQueryInfo, i - 1)->resBytes; +// } + SSqlExprInfo* pExprInfo = &pQueryInfo->exprsInfo; + if (pExprInfo->numOfExprs == 0) { return; } - - pFieldInfo->pOffset[0] = 0; - - /* - * the retTypeLen is used to store the intermediate result length - * for potential secondary merge exists - */ - for (int32_t i = 1; i < pFieldInfo->numOfOutputCols; ++i) { - pFieldInfo->pOffset[i] = pFieldInfo->pOffset[i - 1] + tscSqlExprGet(pQueryInfo, i - 1)->resBytes; + + pExprInfo->pExprs[0]->offset = 0; + + for (int32_t i = 1; i < pExprInfo->numOfExprs; ++i) { + pExprInfo->pExprs[i]->offset = pExprInfo->pExprs[i - 1]->offset + pExprInfo->pExprs[i - 1]->resBytes; } } @@ -944,6 +972,8 @@ void tscFieldInfoCopy(SFieldInfo* src, SFieldInfo* dst, const int32_t* indexList for (int32_t i = 0; i < size; ++i) { assert(indexList[i] >= 0 && indexList[i] <= src->numOfOutputCols); tscFieldInfoSetValFromField(dst, i, &src->pFields[indexList[i]]); + dst->pVisibleCols[i] = src->pVisibleCols[indexList[i]]; + dst->pSqlExpr[i] = src->pSqlExpr[indexList[i]]; } } } @@ -952,12 +982,14 @@ void tscFieldInfoCopyAll(SFieldInfo* dst, SFieldInfo* src) { *dst = *src; dst->pFields = malloc(sizeof(TAOS_FIELD) * dst->numOfAlloc); - dst->pOffset = malloc(sizeof(short) * dst->numOfAlloc); dst->pVisibleCols = malloc(sizeof(bool) * dst->numOfAlloc); + dst->pSqlExpr = malloc(POINTER_BYTES * dst->numOfAlloc); + dst->pExpr = malloc(POINTER_BYTES * dst->numOfAlloc); memcpy(dst->pFields, src->pFields, sizeof(TAOS_FIELD) * dst->numOfOutputCols); - memcpy(dst->pOffset, src->pOffset, sizeof(short) * dst->numOfOutputCols); memcpy(dst->pVisibleCols, src->pVisibleCols, sizeof(bool) * dst->numOfOutputCols); + memcpy(dst->pSqlExpr, src->pSqlExpr, POINTER_BYTES * dst->numOfOutputCols); + memcpy(dst->pExpr, src->pExpr, POINTER_BYTES * dst->numOfOutputCols); } TAOS_FIELD* tscFieldInfoGetField(SQueryInfo* pQueryInfo, int32_t index) { @@ -971,11 +1003,11 @@ TAOS_FIELD* tscFieldInfoGetField(SQueryInfo* pQueryInfo, int32_t index) { int32_t tscNumOfFields(SQueryInfo* pQueryInfo) { return pQueryInfo->fieldsInfo.numOfOutputCols; } int16_t tscFieldInfoGetOffset(SQueryInfo* pQueryInfo, int32_t index) { - if (index >= pQueryInfo->fieldsInfo.numOfOutputCols) { + if (index >= pQueryInfo->exprsInfo.numOfExprs) { return 0; } - return pQueryInfo->fieldsInfo.pOffset[index]; + return pQueryInfo->exprsInfo.pExprs[index]->offset; } int32_t tscFieldInfoCompare(SFieldInfo* pFieldInfo1, SFieldInfo* pFieldInfo2) { @@ -999,13 +1031,16 @@ int32_t tscFieldInfoCompare(SFieldInfo* pFieldInfo1, SFieldInfo* pFieldInfo2) { } int32_t tscGetResRowLength(SQueryInfo* pQueryInfo) { - SFieldInfo* pFieldInfo = &pQueryInfo->fieldsInfo; - if (pFieldInfo->numOfOutputCols <= 0) { + if (pQueryInfo->exprsInfo.numOfExprs <= 0) { return 0; } - - return pFieldInfo->pOffset[pFieldInfo->numOfOutputCols - 1] + - pFieldInfo->pFields[pFieldInfo->numOfOutputCols - 1].bytes; + + int32_t size = 0; + for(int32_t i = 0; i < pQueryInfo->exprsInfo.numOfExprs; ++i) { + size += pQueryInfo->exprsInfo.pExprs[i]->resBytes; + } + + return size; } void tscClearFieldInfo(SFieldInfo* pFieldInfo) { @@ -1013,10 +1048,19 @@ void tscClearFieldInfo(SFieldInfo* pFieldInfo) { return; } - tfree(pFieldInfo->pOffset); tfree(pFieldInfo->pFields); tfree(pFieldInfo->pVisibleCols); - + tfree(pFieldInfo->pSqlExpr); + + for(int32_t i = 0; i < pFieldInfo->numOfOutputCols; ++i) { + if (pFieldInfo->pExpr[i] != NULL) { + tSQLBinaryExprDestroy(&pFieldInfo->pExpr[i]->pBinExprInfo.pBinExpr, NULL); + tfree(pFieldInfo->pExpr[i]->pBinExprInfo.pReqColumns); + tfree(pFieldInfo->pExpr[i]); + } + } + + tfree(pFieldInfo->pExpr); memset(pFieldInfo, 0, sizeof(SFieldInfo)); } @@ -1054,11 +1098,12 @@ SSqlExpr* tscSqlExprInsertEmpty(SQueryInfo* pQueryInfo, int32_t index, int16_t f _exprCheckSpace(pExprInfo, pExprInfo->numOfExprs + 1); _exprEvic(pExprInfo, index); - - SSqlExpr* pExpr = &pExprInfo->pExprs[index]; + + SSqlExpr* pExpr = calloc(1, sizeof(SSqlExpr)); pExpr->functionId = functionId; - + pExprInfo->numOfExprs++; + pExprInfo->pExprs[index] = pExpr; return pExpr; } @@ -1071,8 +1116,9 @@ SSqlExpr* tscSqlExprInsert(SQueryInfo* pQueryInfo, int32_t index, int16_t functi _exprCheckSpace(pExprInfo, pExprInfo->numOfExprs + 1); _exprEvic(pExprInfo, index); - SSqlExpr* pExpr = &pExprInfo->pExprs[index]; - + SSqlExpr* pExpr = calloc(1, sizeof(SSqlExpr)); + pExprInfo->pExprs[index] = pExpr; + pExpr->functionId = functionId; int16_t numOfCols = pMeterMetaInfo->pMeterMeta->numOfColumns; @@ -1114,7 +1160,7 @@ SSqlExpr* tscSqlExprUpdate(SQueryInfo* pQueryInfo, int32_t index, int16_t functi return NULL; } - SSqlExpr* pExpr = &pExprInfo->pExprs[index]; + SSqlExpr* pExpr = pExprInfo->pExprs[index]; pExpr->functionId = functionId; @@ -1127,6 +1173,10 @@ SSqlExpr* tscSqlExprUpdate(SQueryInfo* pQueryInfo, int32_t index, int16_t functi return pExpr; } +int32_t tscSqlExprNumOfExprs(SQueryInfo* pQueryInfo) { + return pQueryInfo->exprsInfo.numOfExprs; +} + void addExprParams(SSqlExpr* pExpr, char* argument, int32_t type, int32_t bytes, int16_t tableIndex) { if (pExpr == NULL || argument == NULL || bytes == 0) { return; @@ -1145,7 +1195,7 @@ SSqlExpr* tscSqlExprGet(SQueryInfo* pQueryInfo, int32_t index) { return NULL; } - return &pQueryInfo->exprsInfo.pExprs[index]; + return pQueryInfo->exprsInfo.pExprs[index]; } void* tscSqlExprDestroy(SSqlExpr* pExpr) { @@ -1157,6 +1207,8 @@ void* tscSqlExprDestroy(SSqlExpr* pExpr) { tVariantDestroy(&pExpr->param[i]); } + tfree(pExpr); + return NULL; } @@ -1168,8 +1220,8 @@ void tscSqlExprInfoDestroy(SSqlExprInfo* pExprInfo) { return; } - for(int32_t i = 0; i < pExprInfo->numOfAlloc; ++i) { - tscSqlExprDestroy(&pExprInfo->pExprs[i]); + for(int32_t i = 0; i < pExprInfo->numOfExprs; ++i) { + tscSqlExprDestroy(pExprInfo->pExprs[i]); } tfree(pExprInfo->pExprs); @@ -1179,27 +1231,40 @@ void tscSqlExprInfoDestroy(SSqlExprInfo* pExprInfo) { } -void tscSqlExprCopy(SSqlExprInfo* dst, const SSqlExprInfo* src, uint64_t tableuid) { +void tscSqlExprCopy(SSqlExprInfo* dst, const SSqlExprInfo* src, uint64_t tableuid, bool deepcopy) { if (src == NULL) { return; } *dst = *src; - dst->pExprs = calloc(dst->numOfAlloc, sizeof(SSqlExpr)); + dst->pExprs = calloc(dst->numOfAlloc, POINTER_BYTES); + int16_t num = 0; for (int32_t i = 0; i < src->numOfExprs; ++i) { - if (src->pExprs[i].uid == tableuid) { - dst->pExprs[num++] = src->pExprs[i]; + if (src->pExprs[i]->uid == tableuid) { + + if (deepcopy) { + dst->pExprs[num] = calloc(1, sizeof(SSqlExpr)); + *dst->pExprs[num] = *src->pExprs[i]; + } else { + dst->pExprs[num] = src->pExprs[i]; + } + + num++; } } dst->numOfExprs = num; - for (int32_t i = 0; i < dst->numOfExprs; ++i) { - for (int32_t j = 0; j < src->pExprs[i].numOfParams; ++j) { - tVariantAssign(&dst->pExprs[i].param[j], &src->pExprs[i].param[j]); + + if (deepcopy) { + for (int32_t i = 0; i < dst->numOfExprs; ++i) { + for (int32_t j = 0; j < src->pExprs[i]->numOfParams; ++j) { + tVariantAssign(&dst->pExprs[i]->param[j], &src->pExprs[i]->param[j]); + } } } + } static void clearVal(SColumnBase* pBase) { @@ -1954,7 +2019,7 @@ SSqlObj* createSubqueryObj(SSqlObj* pSql, int16_t tableIndex, void (*fp)(), void } uint64_t uid = pMeterMetaInfo->pMeterMeta->uid; - tscSqlExprCopy(&pNewQueryInfo->exprsInfo, &pQueryInfo->exprsInfo, uid); + tscSqlExprCopy(&pNewQueryInfo->exprsInfo, &pQueryInfo->exprsInfo, uid, true); int32_t numOfOutputCols = pNewQueryInfo->exprsInfo.numOfExprs; @@ -1969,7 +2034,19 @@ SSqlObj* createSubqueryObj(SSqlObj* pSql, int16_t tableIndex, void (*fp)(), void tscFieldInfoCopy(&pQueryInfo->fieldsInfo, &pNewQueryInfo->fieldsInfo, indexList, numOfOutputCols); free(indexList); - + + // make sure the the sqlExpr for each fields is correct +// todo handle the agg arithmetic expression + for(int32_t f = 0; f < pNewQueryInfo->fieldsInfo.numOfOutputCols; ++f) { + char* name = pNewQueryInfo->fieldsInfo.pFields[f].name; + for(int32_t k1 = 0; k1 < pNewQueryInfo->exprsInfo.numOfExprs; ++k1) { + SSqlExpr* pExpr1 = tscSqlExprGet(pNewQueryInfo, k1); + if (strcmp(name, pExpr1->aliasName) == 0) { + pNewQueryInfo->fieldsInfo.pSqlExpr[f] = pExpr1; + } + } + } + tscFieldInfoUpdateOffsetForInterResult(pNewQueryInfo); } diff --git a/src/connector/jdbc/CMakeLists.txt b/src/connector/jdbc/CMakeLists.txt index 56a65a8ab526ad901941768938416f8bb10704c9..05c8bebafe79469466fa956c479aab80ccbc5943 100644 --- a/src/connector/jdbc/CMakeLists.txt +++ b/src/connector/jdbc/CMakeLists.txt @@ -8,7 +8,7 @@ IF (TD_MVN_INSTALLED) ADD_CUSTOM_COMMAND(OUTPUT ${JDBC_CMD_NAME} POST_BUILD COMMAND mvn -Dmaven.test.skip=true install -f ${CMAKE_CURRENT_SOURCE_DIR}/pom.xml - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/target/taos-jdbcdriver-1.0.2-dist.jar ${LIBRARY_OUTPUT_PATH} + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/target/taos-jdbcdriver-1.0.3-dist.jar ${LIBRARY_OUTPUT_PATH} COMMAND mvn -Dmaven.test.skip=true clean -f ${CMAKE_CURRENT_SOURCE_DIR}/pom.xml COMMENT "build jdbc driver") ADD_CUSTOM_TARGET(${JDBC_TARGET_NAME} ALL WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} DEPENDS ${JDBC_CMD_NAME}) diff --git a/src/connector/jdbc/pom.xml b/src/connector/jdbc/pom.xml index 75abea9edcd4b2f14d69feeb885669801b54700d..36f1a1010c372b319fab7fceaf13c9c44689dc6b 100755 --- a/src/connector/jdbc/pom.xml +++ b/src/connector/jdbc/pom.xml @@ -4,7 +4,7 @@ com.taosdata.jdbc taos-jdbcdriver - 1.0.2 + 1.0.3 jar JDBCDriver diff --git a/src/inc/taosmsg.h b/src/inc/taosmsg.h index cb2a286e64ece3b7c58bd7197d2fe10124cd27fe..f74bff7e57fa5a0e9773263d23ea536068ef866e 100644 --- a/src/inc/taosmsg.h +++ b/src/inc/taosmsg.h @@ -359,6 +359,7 @@ typedef struct SColIndexEx { int16_t colIdx; int16_t colIdxInBuf; uint16_t flag; // denote if it is a tag or not + char name[TSDB_COL_NAME_LEN]; } SColIndexEx; /* sql function msg, to describe the message to vnode about sql function @@ -456,7 +457,7 @@ typedef struct { int16_t numOfCols; // the number of columns will be load from vnode char intervalTimeUnit; // time interval type, for revisement of interval(1d) - int64_t nAggTimeInterval; // time interval for aggregation, in million second + int64_t intervalTime; // time interval for aggregation, in million second int64_t slidingTime; // value for sliding window // tag schema, used to parse tag information in pSidExtInfo diff --git a/src/inc/tresultBuf.h b/src/inc/tresultBuf.h index a464479af27a7e8515f4260c0ea6a73aed780933..b99c44e73fcbd834152640b80f8a59728c7cfd8f 100644 --- a/src/inc/tresultBuf.h +++ b/src/inc/tresultBuf.h @@ -14,7 +14,7 @@ typedef struct SIDList { int32_t* pData; } SIDList; -typedef struct SQueryResultBuf { +typedef struct SQueryDiskbasedResultBuf { int32_t numOfRowsPerPage; int32_t numOfPages; int64_t totalBufSize; @@ -27,7 +27,7 @@ typedef struct SQueryResultBuf { uint32_t numOfAllocGroupIds; // number of allocated id list void* idsTable; // id hash table SIDList* list; // for each id, there is a page id list -} SQueryResultBuf; +} SQueryDiskbasedResultBuf; /** * create disk-based result buffer @@ -36,7 +36,7 @@ typedef struct SQueryResultBuf { * @param rowSize * @return */ -int32_t createResultBuf(SQueryResultBuf** pResultBuf, int32_t size, int32_t rowSize); +int32_t createDiskbasedResultBuffer(SQueryDiskbasedResultBuf** pResultBuf, int32_t size, int32_t rowSize); /** * @@ -45,14 +45,14 @@ int32_t createResultBuf(SQueryResultBuf** pResultBuf, int32_t size, int32_t rowS * @param pageId * @return */ -tFilePage* getNewDataBuf(SQueryResultBuf* pResultBuf, int32_t groupId, int32_t* pageId); +tFilePage* getNewDataBuf(SQueryDiskbasedResultBuf* pResultBuf, int32_t groupId, int32_t* pageId); /** * * @param pResultBuf * @return */ -int32_t getNumOfRowsPerPage(SQueryResultBuf* pResultBuf); +int32_t getNumOfRowsPerPage(SQueryDiskbasedResultBuf* pResultBuf); /** * @@ -60,7 +60,7 @@ int32_t getNumOfRowsPerPage(SQueryResultBuf* pResultBuf); * @param groupId * @return */ -SIDList getDataBufPagesIdList(SQueryResultBuf* pResultBuf, int32_t groupId); +SIDList getDataBufPagesIdList(SQueryDiskbasedResultBuf* pResultBuf, int32_t groupId); /** * get the specified buffer page by id @@ -68,27 +68,27 @@ SIDList getDataBufPagesIdList(SQueryResultBuf* pResultBuf, int32_t groupId); * @param id * @return */ -tFilePage* getResultBufferPageById(SQueryResultBuf* pResultBuf, int32_t id); +tFilePage* getResultBufferPageById(SQueryDiskbasedResultBuf* pResultBuf, int32_t id); /** * get the total buffer size in the format of disk file * @param pResultBuf * @return */ -int32_t getResBufSize(SQueryResultBuf* pResultBuf); +int32_t getResBufSize(SQueryDiskbasedResultBuf* pResultBuf); /** * get the number of groups in the result buffer * @param pResultBuf * @return */ -int32_t getNumOfResultBufGroupId(SQueryResultBuf* pResultBuf); +int32_t getNumOfResultBufGroupId(SQueryDiskbasedResultBuf* pResultBuf); /** * destroy result buffer * @param pResultBuf */ -void destroyResultBuf(SQueryResultBuf* pResultBuf); +void destroyResultBuf(SQueryDiskbasedResultBuf* pResultBuf); /** * diff --git a/src/plugins/http/inc/httpHandle.h b/src/plugins/http/inc/httpHandle.h index c564337187088b9ced276984c1a5cdec210c6af8..9c6a263c5bd328ca0fc59eb5365f7722324ef729 100644 --- a/src/plugins/http/inc/httpHandle.h +++ b/src/plugins/http/inc/httpHandle.h @@ -37,7 +37,7 @@ #define HTTP_STEP_SIZE 1024 //http message get process step by step #define HTTP_MAX_URL 5 //http url stack size #define HTTP_METHOD_SCANNER_SIZE 7 //http method fp size -#define HTTP_GC_TARGET_SIZE 128 +#define HTTP_GC_TARGET_SIZE 512 #define HTTP_VERSION_10 0 #define HTTP_VERSION_11 1 diff --git a/src/plugins/http/src/gcJson.c b/src/plugins/http/src/gcJson.c index 1a86c5d24f23ec62bb1c51aabdd0639940edc54a..8f596337146a3937df72287f332917b3bffa21ac 100644 --- a/src/plugins/http/src/gcJson.c +++ b/src/plugins/http/src/gcJson.c @@ -127,42 +127,43 @@ bool gcBuildQueryJson(HttpContext *pContext, HttpSqlCmd *cmd, TAOS_RES *result, // for group by if (groupFields != -1) { char target[HTTP_GC_TARGET_SIZE]; + int len; + len = snprintf(target,HTTP_GC_TARGET_SIZE,"%s{",aliasBuffer); + for (int i = dataFields + 1; inum++; pObj->size++; - -// char key[512] = {0}; -// memcpy(key, pNode->key, MIN(512, pNode->keyLen)); -// pTrace("key:%s %p add to hash table", key, pNode); } int32_t taosNumElemsInHashTable(HashObj *pObj) { @@ -525,29 +521,3 @@ int32_t taosGetHashMaxOverflowLength(HashObj* pObj) { return num; } - -int32_t taosCheckHashTable(HashObj *pObj) { - for(int32_t i = 0; i < pObj->capacity; ++i) { - SHashEntry *pEntry = pObj->hashList[i]; - - SHashNode* pNode = pEntry->next; - if (pNode != NULL) { - assert(pEntry == pNode->prev1); - int32_t num = 1; - - SHashNode* pNext = pNode->next; - - while(pNext) { - assert(pNext->prev == pNode); - - pNode = pNext; - pNext = pNext->next; - num ++; - } - - assert(num == pEntry->num); - } - } - - return 0; -} diff --git a/src/util/src/textbuffer.c b/src/util/src/textbuffer.c index 860de6782be97ce83032cf60d3d2f303af18c795..8ce090d335ea8105d22d2342de9d9a3e61b4592f 100644 --- a/src/util/src/textbuffer.c +++ b/src/util/src/textbuffer.c @@ -468,8 +468,8 @@ int32_t compare_a(tOrderDescriptor *pDescriptor, int32_t numOfRows1, int32_t s1, return ret; } } else { - SSchema *pSchema = &pDescriptor->pColumnModel->pFields[colIdx]; - int32_t ret = columnValueAscendingComparator(f1, f2, pSchema->type, pSchema->bytes); + SSchemaEx *pSchema = &pDescriptor->pColumnModel->pFields[colIdx]; + int32_t ret = columnValueAscendingComparator(f1, f2, pSchema->field.type, pSchema->field.bytes); if (ret == 0) { continue; } else { @@ -500,8 +500,8 @@ int32_t compare_d(tOrderDescriptor *pDescriptor, int32_t numOfRows1, int32_t s1, return ret; } } else { - SSchema *pSchema = &pDescriptor->pColumnModel->pFields[colIdx]; - int32_t ret = columnValueAscendingComparator(f1, f2, pSchema->type, pSchema->bytes); + SSchemaEx *pSchema = &pDescriptor->pColumnModel->pFields[colIdx]; + int32_t ret = columnValueAscendingComparator(f1, f2, pSchema->field.type, pSchema->field.bytes); if (ret == 0) { continue; } else { diff --git a/src/util/src/tinterpolation.c b/src/util/src/tinterpolation.c index 82cc52cd42ef2a4c8c40d61d40aa6e956b96a1be..cb7c8854ce914d22680db5429871857ac445f1fe 100644 --- a/src/util/src/tinterpolation.c +++ b/src/util/src/tinterpolation.c @@ -13,9 +13,6 @@ * along with this program. If not, see . */ -#include -#include - #include "os.h" #include "taosmsg.h" #include "textbuffer.h" @@ -47,7 +44,7 @@ int64_t taosGetIntervalStartTimestamp(int64_t startTime, int64_t timeRange, char char** tzname = _tzname; #endif - int64_t t = (precision == TSDB_TIME_PRECISION_MILLI)?MILLISECOND_PER_SECOND:MILLISECOND_PER_SECOND*1000L; + int64_t t = (precision == TSDB_TIME_PRECISION_MILLI) ? MILLISECOND_PER_SECOND : MILLISECOND_PER_SECOND * 1000L; int64_t revStartime = (startTime / timeRange) * timeRange + timezone * t; int64_t revEndtime = revStartime + timeRange - 1; @@ -78,14 +75,14 @@ void taosInitInterpoInfo(SInterpolationInfo* pInterpoInfo, int32_t order, int64_ } // the SInterpolationInfo itself will not be released -void taosDestoryInterpoInfo(SInterpolationInfo *pInterpoInfo) { +void taosDestoryInterpoInfo(SInterpolationInfo* pInterpoInfo) { if (pInterpoInfo == NULL) { return; } - + tfree(pInterpoInfo->prevValues); tfree(pInterpoInfo->nextValues); - + tfree(pInterpoInfo->pTags); } @@ -94,7 +91,7 @@ void taosInterpoSetStartInfo(SInterpolationInfo* pInterpoInfo, int32_t numOfRawD return; } - pInterpoInfo->rowIdx = 0;//INTERPOL_IS_ASC_INTERPOL(pInterpoInfo) ? 0 : numOfRawDataInRows - 1; + pInterpoInfo->rowIdx = 0; pInterpoInfo->numOfRawDataInRows = numOfRawDataInRows; } @@ -118,14 +115,9 @@ int32_t taosGetNumOfResWithoutLimit(SInterpolationInfo* pInterpoInfo, int64_t* p if (numOfAvailRawData > 0) { int32_t finalNumOfResult = 0; -// if (pInterpoInfo->order == TSQL_SO_ASC) { - // get last timestamp, calculate the result size - int64_t lastKey = pPrimaryKeyArray[pInterpoInfo->numOfRawDataInRows - 1]; - finalNumOfResult = (int32_t)(labs(lastKey - pInterpoInfo->startTimestamp) / nInterval) + 1; -// } else { // todo error less than one!!! -// TSKEY lastKey = pPrimaryKeyArray[0]; -// finalNumOfResult = (int32_t)((pInterpoInfo->startTimestamp - lastKey) / nInterval) + 1; -// } + // get last timestamp, calculate the result size + int64_t lastKey = pPrimaryKeyArray[pInterpoInfo->numOfRawDataInRows - 1]; + finalNumOfResult = (int32_t)(labs(lastKey - pInterpoInfo->startTimestamp) / nInterval) + 1; assert(finalNumOfResult >= numOfAvailRawData); return finalNumOfResult; @@ -140,7 +132,9 @@ int32_t taosGetNumOfResWithoutLimit(SInterpolationInfo* pInterpoInfo, int64_t* p } } -bool taosHasRemainsDataForInterpolation(SInterpolationInfo* pInterpoInfo) { return taosNumOfRemainPoints(pInterpoInfo) > 0; } +bool taosHasRemainsDataForInterpolation(SInterpolationInfo* pInterpoInfo) { + return taosNumOfRemainPoints(pInterpoInfo) > 0; +} int32_t taosNumOfRemainPoints(SInterpolationInfo* pInterpoInfo) { if (pInterpoInfo->rowIdx == -1 || pInterpoInfo->numOfRawDataInRows == 0) { @@ -197,28 +191,22 @@ int taosDoLinearInterpolation(int32_t type, SPoint* point1, SPoint* point2, SPoi return 0; } -static char* getPos(char* data, int32_t bytes, int32_t order, int32_t capacity, int32_t index) { -// if (order == TSQL_SO_ASC) { - return data + index * bytes; -// } else { -// return data + (capacity - index - 1) * bytes; -// } -} +static char* getPos(char* data, int32_t bytes, int32_t index) { return data + index * bytes; } -static void setTagsValueInInterpolation(tFilePage** data, char** pTags, SColumnModel* pModel, int32_t order, int32_t start, - int32_t capacity, int32_t num) { +static void setTagsValueInInterpolation(tFilePage** data, char** pTags, SColumnModel* pModel, int32_t order, + int32_t start, int32_t capacity, int32_t num) { for (int32_t j = 0, i = start; i < pModel->numOfCols; ++i, ++j) { SSchema* pSchema = getColumnModelSchema(pModel, i); - - char* val1 = getPos(data[i]->data, pSchema->bytes, order, capacity, num); + + char* val1 = getPos(data[i]->data, pSchema->bytes, num); assignVal(val1, pTags[j], pSchema->bytes, pSchema->type); } } static void doInterpoResultImpl(SInterpolationInfo* pInterpoInfo, int16_t interpoType, tFilePage** data, - SColumnModel* pModel, int32_t* num, char** srcData, int64_t nInterval, int64_t* defaultVal, - int64_t currentTimestamp, int32_t capacity, int32_t numOfTags, char** pTags, - bool outOfBound) { + SColumnModel* pModel, int32_t* num, char** srcData, int64_t nInterval, + int64_t* defaultVal, int64_t currentTimestamp, int32_t capacity, int32_t numOfTags, + char** pTags, bool outOfBound) { char** prevValues = &pInterpoInfo->prevValues; char** nextValues = &pInterpoInfo->nextValues; @@ -226,7 +214,7 @@ static void doInterpoResultImpl(SInterpolationInfo* pInterpoInfo, int16_t interp int32_t step = GET_FORWARD_DIRECTION_FACTOR(pInterpoInfo->order); - char* val = getPos(data[0]->data, TSDB_KEYSIZE, pInterpoInfo->order, capacity, *num); + char* val = getPos(data[0]->data, TSDB_KEYSIZE, *num); *(TSKEY*)val = pInterpoInfo->startTimestamp; int32_t numOfValCols = pModel->numOfCols - numOfTags; @@ -237,9 +225,9 @@ static void doInterpoResultImpl(SInterpolationInfo* pInterpoInfo, int16_t interp if (pInterpolationData != NULL) { for (int32_t i = 1; i < numOfValCols; ++i) { SSchema* pSchema = getColumnModelSchema(pModel, i); - int16_t offset = getColumnModelOffset(pModel, i); - - char* val1 = getPos(data[i]->data, pSchema->bytes, pInterpoInfo->order, capacity, *num); + int16_t offset = getColumnModelOffset(pModel, i); + + char* val1 = getPos(data[i]->data, pSchema->bytes, *num); if (isNull(pInterpolationData + offset, pSchema->type)) { setNull(val1, pSchema->type, pSchema->bytes); @@ -250,8 +238,8 @@ static void doInterpoResultImpl(SInterpolationInfo* pInterpoInfo, int16_t interp } else { /* no prev value yet, set the value for null */ for (int32_t i = 1; i < numOfValCols; ++i) { SSchema* pSchema = getColumnModelSchema(pModel, i); - - char* val1 = getPos(data[i]->data, pSchema->bytes, pInterpoInfo->order, capacity, *num); + + char* val1 = getPos(data[i]->data, pSchema->bytes, *num); setNull(val1, pSchema->type, pSchema->bytes); } } @@ -262,10 +250,10 @@ static void doInterpoResultImpl(SInterpolationInfo* pInterpoInfo, int16_t interp if (*prevValues != NULL && !outOfBound) { for (int32_t i = 1; i < numOfValCols; ++i) { SSchema* pSchema = getColumnModelSchema(pModel, i); - int16_t offset = getColumnModelOffset(pModel, i); - + int16_t offset = getColumnModelOffset(pModel, i); + int16_t type = pSchema->type; - char* val1 = getPos(data[i]->data, pSchema->bytes, pInterpoInfo->order, capacity, *num); + char* val1 = getPos(data[i]->data, pSchema->bytes, *num); if (type == TSDB_DATA_TYPE_BINARY || type == TSDB_DATA_TYPE_NCHAR || type == TSDB_DATA_TYPE_BOOL) { setNull(val1, type, pSchema->bytes); @@ -283,8 +271,8 @@ static void doInterpoResultImpl(SInterpolationInfo* pInterpoInfo, int16_t interp } else { for (int32_t i = 1; i < numOfValCols; ++i) { SSchema* pSchema = getColumnModelSchema(pModel, i); - - char* val1 = getPos(data[i]->data, pSchema->bytes, pInterpoInfo->order, capacity, *num); + + char* val1 = getPos(data[i]->data, pSchema->bytes, *num); setNull(val1, pSchema->type, pSchema->bytes); } @@ -293,8 +281,8 @@ static void doInterpoResultImpl(SInterpolationInfo* pInterpoInfo, int16_t interp } else { /* default value interpolation */ for (int32_t i = 1; i < numOfValCols; ++i) { SSchema* pSchema = getColumnModelSchema(pModel, i); - - char* val1 = getPos(data[i]->data, pSchema->bytes, pInterpoInfo->order, capacity, *num); + + char* val1 = getPos(data[i]->data, pSchema->bytes, *num); assignVal(val1, (char*)&defaultVal[i], pSchema->bytes, pSchema->type); } @@ -307,6 +295,20 @@ static void doInterpoResultImpl(SInterpolationInfo* pInterpoInfo, int16_t interp (*num) += 1; } +static void initBeforeAfterDataBuf(SColumnModel* pModel, char** nextValues) { + if (*nextValues != NULL) { + return; + } + + *nextValues = calloc(1, pModel->rowSize); + for (int i = 1; i < pModel->numOfCols; i++) { + int16_t offset = getColumnModelOffset(pModel, i); + SSchema* pSchema = getColumnModelSchema(pModel, i); + + setNull(*nextValues + offset, pSchema->type, pSchema->bytes); + } +} + int32_t taosDoInterpoResult(SInterpolationInfo* pInterpoInfo, int16_t interpoType, tFilePage** data, int32_t numOfRawDataInRows, int32_t outputRows, int64_t nInterval, const int64_t* pPrimaryKeyArray, SColumnModel* pModel, char** srcData, int64_t* defaultVal, @@ -341,71 +343,58 @@ int32_t taosDoInterpoResult(SInterpolationInfo* pInterpoInfo, int16_t interpoTyp if ((pInterpoInfo->startTimestamp < currentTimestamp && INTERPOL_IS_ASC_INTERPOL(pInterpoInfo)) || (pInterpoInfo->startTimestamp > currentTimestamp && !INTERPOL_IS_ASC_INTERPOL(pInterpoInfo))) { /* set the next value for interpolation */ - if (*nextValues == NULL) { - *nextValues = calloc(1, pModel->rowSize); - for (int i = 1; i < pModel->numOfCols; i++) { - int16_t offset = getColumnModelOffset(pModel, i); - SSchema* pSchema = getColumnModelSchema(pModel, i); - - setNull(*nextValues + offset, pSchema->type, pSchema->bytes); - } - } - + initBeforeAfterDataBuf(pModel, nextValues); + int32_t offset = pInterpoInfo->rowIdx; for (int32_t tlen = 0, i = 0; i < pModel->numOfCols - numOfTags; ++i) { SSchema* pSchema = getColumnModelSchema(pModel, i); - + memcpy(*nextValues + tlen, srcData[i] + offset * pSchema->bytes, pSchema->bytes); tlen += pSchema->bytes; } } - while (((pInterpoInfo->startTimestamp < currentTimestamp && INTERPOL_IS_ASC_INTERPOL(pInterpoInfo)) || - (pInterpoInfo->startTimestamp > currentTimestamp && !INTERPOL_IS_ASC_INTERPOL(pInterpoInfo))) && - num < outputRows) { - doInterpoResultImpl(pInterpoInfo, interpoType, data, pModel, &num, srcData, nInterval, defaultVal, - currentTimestamp, bufSize, numOfTags, pTags, false); - } - - /* output buffer is full, abort */ - if ((num == outputRows && INTERPOL_IS_ASC_INTERPOL(pInterpoInfo)) || - (num < 0 && !INTERPOL_IS_ASC_INTERPOL(pInterpoInfo))) { - pInterpoInfo->numOfTotalInterpo += pInterpoInfo->numOfCurrentInterpo; - return outputRows; - } - - if (pInterpoInfo->startTimestamp == currentTimestamp) { - if (*prevValues == NULL) { - *prevValues = calloc(1, pModel->rowSize); - for (int i = 1; i < pModel->numOfCols; i++) { - int16_t offset = getColumnModelOffset(pModel, i); - SSchema* pSchema = getColumnModelSchema(pModel, i); - - setNull(*prevValues + offset, pSchema->type, pSchema->bytes); - } + if (((pInterpoInfo->startTimestamp < currentTimestamp && INTERPOL_IS_ASC_INTERPOL(pInterpoInfo)) || + (pInterpoInfo->startTimestamp > currentTimestamp && !INTERPOL_IS_ASC_INTERPOL(pInterpoInfo))) && + num < outputRows) { + while (((pInterpoInfo->startTimestamp < currentTimestamp && INTERPOL_IS_ASC_INTERPOL(pInterpoInfo)) || + (pInterpoInfo->startTimestamp > currentTimestamp && !INTERPOL_IS_ASC_INTERPOL(pInterpoInfo))) && + num < outputRows) { + doInterpoResultImpl(pInterpoInfo, interpoType, data, pModel, &num, srcData, nInterval, defaultVal, + currentTimestamp, bufSize, numOfTags, pTags, false); } + /* output buffer is full, abort */ + if ((num == outputRows && INTERPOL_IS_ASC_INTERPOL(pInterpoInfo)) || + (num < 0 && !INTERPOL_IS_ASC_INTERPOL(pInterpoInfo))) { + pInterpoInfo->numOfTotalInterpo += pInterpoInfo->numOfCurrentInterpo; + return outputRows; + } + } else { + assert(pInterpoInfo->startTimestamp == currentTimestamp); + + initBeforeAfterDataBuf(pModel, prevValues); + // assign rows to dst buffer int32_t i = 0; for (int32_t tlen = 0; i < pModel->numOfCols - numOfTags; ++i) { - int16_t offset = getColumnModelOffset(pModel, i); + int16_t offset = getColumnModelOffset(pModel, i); SSchema* pSchema = getColumnModelSchema(pModel, i); - - char* val1 = getPos(data[i]->data, pSchema->bytes, pInterpoInfo->order, bufSize, num); + char* val1 = getPos(data[i]->data, pSchema->bytes, num); + char* src = srcData[i] + pInterpoInfo->rowIdx * pSchema->bytes; + if (i == 0 || - (functionIDs[i] != TSDB_FUNC_COUNT && - !isNull(srcData[i] + pInterpoInfo->rowIdx * pSchema->bytes, pSchema->type)) || - (functionIDs[i] == TSDB_FUNC_COUNT && - *(int64_t*)(srcData[i] + pInterpoInfo->rowIdx * pSchema->bytes) != 0)) { - - assignVal(val1, srcData[i] + pInterpoInfo->rowIdx * pSchema->bytes, pSchema->bytes, pSchema->type); - memcpy(*prevValues + tlen, srcData[i] + pInterpoInfo->rowIdx * pSchema->bytes, pSchema->bytes); - } else { // i > 0 and isNULL, do interpolation + (functionIDs[i] != TSDB_FUNC_COUNT && !isNull(src, pSchema->type)) || + (functionIDs[i] == TSDB_FUNC_COUNT && *(int64_t*)(src) != 0)) { + assignVal(val1, src, pSchema->bytes, pSchema->type); + memcpy(*prevValues + tlen, src, pSchema->bytes); + } else { // i > 0 and data is null , do interpolation if (interpoType == TSDB_INTERPO_PREV) { assignVal(val1, *prevValues + offset, pSchema->bytes, pSchema->type); } else if (interpoType == TSDB_INTERPO_LINEAR) { - // TODO: + assignVal(val1, src, pSchema->bytes, pSchema->type); + memcpy(*prevValues + tlen, src, pSchema->bytes); } else { assignVal(val1, (char*)&defaultVal[i], pSchema->bytes, pSchema->type); } @@ -416,11 +405,11 @@ int32_t taosDoInterpoResult(SInterpolationInfo* pInterpoInfo, int16_t interpoTyp /* set the tag value for final result */ setTagsValueInInterpolation(data, pTags, pModel, pInterpoInfo->order, pModel->numOfCols - numOfTags, bufSize, num); - } - pInterpoInfo->startTimestamp += (nInterval * step); - pInterpoInfo->rowIdx += 1; - num += 1; + pInterpoInfo->startTimestamp += (nInterval * step); + pInterpoInfo->rowIdx += 1; + num += 1; + } if ((pInterpoInfo->rowIdx >= pInterpoInfo->numOfRawDataInRows && INTERPOL_IS_ASC_INTERPOL(pInterpoInfo)) || (pInterpoInfo->rowIdx < 0 && !INTERPOL_IS_ASC_INTERPOL(pInterpoInfo)) || num >= outputRows) { diff --git a/src/util/src/tresultBuf.c b/src/util/src/tresultBuf.c index 31218670acc0a95c865de27ea945d1ed5ee19e29..a7377f16575147934f68148adb2d16126288ffc9 100644 --- a/src/util/src/tresultBuf.c +++ b/src/util/src/tresultBuf.c @@ -7,8 +7,8 @@ #define DEFAULT_INTERN_BUF_SIZE 16384L -int32_t createResultBuf(SQueryResultBuf** pResultBuf, int32_t size, int32_t rowSize) { - SQueryResultBuf* pResBuf = calloc(1, sizeof(SQueryResultBuf)); +int32_t createDiskbasedResultBuffer(SQueryDiskbasedResultBuf** pResultBuf, int32_t size, int32_t rowSize) { + SQueryDiskbasedResultBuf* pResBuf = calloc(1, sizeof(SQueryDiskbasedResultBuf)); pResBuf->numOfRowsPerPage = (DEFAULT_INTERN_BUF_SIZE - sizeof(tFilePage)) / rowSize; pResBuf->numOfPages = size; @@ -50,17 +50,17 @@ int32_t createResultBuf(SQueryResultBuf** pResultBuf, int32_t size, int32_t rowS return TSDB_CODE_SUCCESS; } -tFilePage* getResultBufferPageById(SQueryResultBuf* pResultBuf, int32_t id) { +tFilePage* getResultBufferPageById(SQueryDiskbasedResultBuf* pResultBuf, int32_t id) { assert(id < pResultBuf->numOfPages && id >= 0); return (tFilePage*)(pResultBuf->pBuf + DEFAULT_INTERN_BUF_SIZE * id); } -int32_t getNumOfResultBufGroupId(SQueryResultBuf* pResultBuf) { return taosNumElemsInHashTable(pResultBuf->idsTable); } +int32_t getNumOfResultBufGroupId(SQueryDiskbasedResultBuf* pResultBuf) { return taosNumElemsInHashTable(pResultBuf->idsTable); } -int32_t getResBufSize(SQueryResultBuf* pResultBuf) { return pResultBuf->totalBufSize; } +int32_t getResBufSize(SQueryDiskbasedResultBuf* pResultBuf) { return pResultBuf->totalBufSize; } -static int32_t extendDiskFileSize(SQueryResultBuf* pResultBuf, int32_t numOfPages) { +static int32_t extendDiskFileSize(SQueryDiskbasedResultBuf* pResultBuf, int32_t numOfPages) { assert(pResultBuf->numOfPages * DEFAULT_INTERN_BUF_SIZE == pResultBuf->totalBufSize); int32_t ret = munmap(pResultBuf->pBuf, pResultBuf->totalBufSize); @@ -88,11 +88,11 @@ static int32_t extendDiskFileSize(SQueryResultBuf* pResultBuf, int32_t numOfPage return TSDB_CODE_SUCCESS; } -static bool noMoreAvailablePages(SQueryResultBuf* pResultBuf) { +static bool noMoreAvailablePages(SQueryDiskbasedResultBuf* pResultBuf) { return (pResultBuf->allocateId == pResultBuf->numOfPages - 1); } -static int32_t getGroupIndex(SQueryResultBuf* pResultBuf, int32_t groupId) { +static int32_t getGroupIndex(SQueryDiskbasedResultBuf* pResultBuf, int32_t groupId) { assert(pResultBuf != NULL); char* p = taosGetDataFromHashTable(pResultBuf->idsTable, (const char*)&groupId, sizeof(int32_t)); @@ -106,7 +106,7 @@ static int32_t getGroupIndex(SQueryResultBuf* pResultBuf, int32_t groupId) { return slot; } -static int32_t addNewGroupId(SQueryResultBuf* pResultBuf, int32_t groupId) { +static int32_t addNewGroupId(SQueryDiskbasedResultBuf* pResultBuf, int32_t groupId) { int32_t num = getNumOfResultBufGroupId(pResultBuf); // the num is the newest allocated group id slot if (pResultBuf->numOfAllocGroupIds <= num) { @@ -148,7 +148,7 @@ static int32_t doRegisterId(SIDList* pList, int32_t id) { return 0; } -static void registerPageId(SQueryResultBuf* pResultBuf, int32_t groupId, int32_t pageId) { +static void registerPageId(SQueryDiskbasedResultBuf* pResultBuf, int32_t groupId, int32_t pageId) { int32_t slot = getGroupIndex(pResultBuf, groupId); if (slot < 0) { slot = addNewGroupId(pResultBuf, groupId); @@ -158,7 +158,7 @@ static void registerPageId(SQueryResultBuf* pResultBuf, int32_t groupId, int32_t doRegisterId(pList, pageId); } -tFilePage* getNewDataBuf(SQueryResultBuf* pResultBuf, int32_t groupId, int32_t* pageId) { +tFilePage* getNewDataBuf(SQueryDiskbasedResultBuf* pResultBuf, int32_t groupId, int32_t* pageId) { if (noMoreAvailablePages(pResultBuf)) { if (extendDiskFileSize(pResultBuf, pResultBuf->incStep) != TSDB_CODE_SUCCESS) { return NULL; @@ -177,9 +177,9 @@ tFilePage* getNewDataBuf(SQueryResultBuf* pResultBuf, int32_t groupId, int32_t* return page; } -int32_t getNumOfRowsPerPage(SQueryResultBuf* pResultBuf) { return pResultBuf->numOfRowsPerPage; } +int32_t getNumOfRowsPerPage(SQueryDiskbasedResultBuf* pResultBuf) { return pResultBuf->numOfRowsPerPage; } -SIDList getDataBufPagesIdList(SQueryResultBuf* pResultBuf, int32_t groupId) { +SIDList getDataBufPagesIdList(SQueryDiskbasedResultBuf* pResultBuf, int32_t groupId) { SIDList list = {0}; int32_t slot = getGroupIndex(pResultBuf, groupId); if (slot < 0) { @@ -189,7 +189,7 @@ SIDList getDataBufPagesIdList(SQueryResultBuf* pResultBuf, int32_t groupId) { } } -void destroyResultBuf(SQueryResultBuf* pResultBuf) { +void destroyResultBuf(SQueryDiskbasedResultBuf* pResultBuf) { if (pResultBuf == NULL) { return; } diff --git a/src/vnode/detail/inc/vnode.h b/src/vnode/detail/inc/vnode.h index 481dbb19ddc0823b8be84b378fcaf8b6ae88f85e..ecd9e3f39275bb495a884442f221256e62ba5ee0 100644 --- a/src/vnode/detail/inc/vnode.h +++ b/src/vnode/detail/inc/vnode.h @@ -259,7 +259,7 @@ typedef struct SQuery { int64_t blockId; TSKEY skey; TSKEY ekey; - int64_t nAggTimeInterval; + int64_t intervalTime; int64_t slidingTime; // sliding time for sliding window query char intervalTimeUnit; // interval data type, used for daytime revise int8_t precision; diff --git a/src/vnode/detail/inc/vnodeQueryImpl.h b/src/vnode/detail/inc/vnodeQueryImpl.h index cce66786fd993b1b300a5a2abbe27e5f4eff37de..e3507d5f82e8c156ffdc5a3babae8ea5af079398 100644 --- a/src/vnode/detail/inc/vnodeQueryImpl.h +++ b/src/vnode/detail/inc/vnodeQueryImpl.h @@ -25,7 +25,7 @@ extern "C" { #include "hash.h" #include "hashutil.h" -#define GET_QINFO_ADDR(x) ((char*)(x)-offsetof(SQInfo, query)) +#define GET_QINFO_ADDR(x) ((char*)(x)-offsetof(SQInfo, query)) #define Q_STATUS_EQUAL(p, s) (((p) & (s)) != 0) /* @@ -33,10 +33,10 @@ extern "C" { * The page size should be sufficient for at least one output result or intermediate result. * Some intermediate results may be extremely large, such as top/bottom(100) query. */ -#define DEFAULT_INTERN_BUF_SIZE 16384L +#define DEFAULT_INTERN_BUF_SIZE 16384L -#define INIT_ALLOCATE_DISK_PAGES 60L -#define DEFAULT_DATA_FILE_MAPPING_PAGES 2L +#define INIT_ALLOCATE_DISK_PAGES 60L +#define DEFAULT_DATA_FILE_MAPPING_PAGES 2L #define DEFAULT_DATA_FILE_MMAP_WINDOW_SIZE (DEFAULT_DATA_FILE_MAPPING_PAGES * DEFAULT_INTERN_BUF_SIZE) #define IO_ENGINE_MMAP 0 @@ -56,7 +56,7 @@ typedef enum { * the program will call this function again, if this status is set. * used to transfer from QUERY_RESBUF_FULL */ - QUERY_NOT_COMPLETED = 0x1, + QUERY_NOT_COMPLETED = 0x1u, /* * output buffer is full, so, the next query will be employed, @@ -66,7 +66,7 @@ typedef enum { * this status is only exist in group-by clause and * diff/add/division/multiply/ query. */ - QUERY_RESBUF_FULL = 0x2, + QUERY_RESBUF_FULL = 0x2u, /* * query is over @@ -76,14 +76,13 @@ typedef enum { * 2. when the query range on timestamp is satisfied, it is also denoted as * query_compeleted */ - QUERY_COMPLETED = 0x4, + QUERY_COMPLETED = 0x4u, /* * all data has been scanned, so current search is stopped, * At last, the function will transfer this status to QUERY_COMPLETED */ - QUERY_NO_DATA_TO_CHECK = 0x8, - + QUERY_NO_DATA_TO_CHECK = 0x8u, } vnodeQueryStatus; typedef struct SPointInterpoSupporter { @@ -112,15 +111,15 @@ typedef enum { DISK_DATA_DISCARDED = 0x01, } vnodeDiskLoadStatus; -#define IS_MASTER_SCAN(runtime) ((runtime)->scanFlag == MASTER_SCAN) -#define IS_SUPPLEMENT_SCAN(runtime) (!IS_MASTER_SCAN(runtime)) +#define IS_MASTER_SCAN(runtime) (((runtime)->scanFlag & 1u) == MASTER_SCAN) +#define IS_SUPPLEMENT_SCAN(runtime) ((runtime)->scanFlag == SUPPLEMENTARY_SCAN) #define SET_SUPPLEMENT_SCAN_FLAG(runtime) ((runtime)->scanFlag = SUPPLEMENTARY_SCAN) #define SET_MASTER_SCAN_FLAG(runtime) ((runtime)->scanFlag = MASTER_SCAN) typedef int (*__block_search_fn_t)(char* data, int num, int64_t key, int order); static FORCE_INLINE SMeterObj* getMeterObj(void* hashHandle, int32_t sid) { - return *(SMeterObj**)taosGetDataFromHashTable(hashHandle, (const char*) &sid, sizeof(sid)); + return *(SMeterObj**)taosGetDataFromHashTable(hashHandle, (const char*)&sid, sizeof(sid)); } bool isQueryKilled(SQuery* pQuery); @@ -130,7 +129,7 @@ bool isSumAvgRateQuery(SQuery *pQuery); bool isTopBottomQuery(SQuery* pQuery); bool isFirstLastRowQuery(SQuery* pQuery); bool isTSCompQuery(SQuery* pQuery); -bool notHasQueryTimeRange(SQuery *pQuery); +bool notHasQueryTimeRange(SQuery* pQuery); bool needSupplementaryScan(SQuery* pQuery); bool onDemandLoadDatablock(SQuery* pQuery, int16_t queryRangeSet); @@ -149,16 +148,15 @@ void vnodeScanAllData(SQueryRuntimeEnv* pRuntimeEnv); int32_t vnodeQueryResultInterpolate(SQInfo* pQInfo, tFilePage** pDst, tFilePage** pDataSrc, int32_t numOfRows, int32_t* numOfInterpo); -void copyResToQueryResultBuf(SMeterQuerySupportObj* pSupporter, SQuery* pQuery); +void copyResToQueryResultBuf(STableQuerySupportObj* pSupporter, SQuery* pQuery); -void doSkipResults(SQueryRuntimeEnv* pRuntimeEnv); -void doFinalizeResult(SQueryRuntimeEnv* pRuntimeEnv); +void doSkipResults(SQueryRuntimeEnv* pRuntimeEnv); +void doFinalizeResult(SQueryRuntimeEnv* pRuntimeEnv); int64_t getNumOfResult(SQueryRuntimeEnv* pRuntimeEnv); -void forwardIntervalQueryRange(SMeterQuerySupportObj* pSupporter, SQueryRuntimeEnv* pRuntimeEnv); void forwardQueryStartPosition(SQueryRuntimeEnv* pRuntimeEnv); -bool normalizedFirstQueryRange(bool dataInDisk, bool dataInCache, SMeterQuerySupportObj* pSupporter, +bool normalizedFirstQueryRange(bool dataInDisk, bool dataInCache, STableQuerySupportObj* pSupporter, SPointInterpoSupporter* pPointInterpSupporter, int64_t* key); void pointInterpSupporterInit(SQuery* pQuery, SPointInterpoSupporter* pInterpoSupport); @@ -166,41 +164,42 @@ void pointInterpSupporterDestroy(SPointInterpoSupporter* pPointInterpSupport); void pointInterpSupporterSetData(SQInfo* pQInfo, SPointInterpoSupporter* pPointInterpSupport); int64_t loadRequiredBlockIntoMem(SQueryRuntimeEnv* pRuntimeEnv, SPositionInfo* position); -int32_t doCloseAllOpenedResults(SMeterQuerySupportObj* pSupporter); -void disableFunctForSuppleScan(SQueryRuntimeEnv* pRuntimeEnv, int32_t order); -void enableFunctForMasterScan(SQueryRuntimeEnv* pRuntimeEnv, int32_t order); +void disableFunctForSuppleScan(STableQuerySupportObj* pSupporter, int32_t order); +void enableFunctForMasterScan(SQueryRuntimeEnv* pRuntimeEnv, int32_t order); + +int32_t mergeMetersResultToOneGroups(STableQuerySupportObj* pSupporter); +void copyFromWindowResToSData(SQInfo* pQInfo, SWindowResult* result); -int32_t mergeMetersResultToOneGroups(SMeterQuerySupportObj* pSupporter); -void copyFromGroupBuf(SQInfo* pQInfo, SOutputRes* result); +SBlockInfo getBlockInfo(SQueryRuntimeEnv *pRuntimeEnv); +SBlockInfo getBlockBasicInfo(SQueryRuntimeEnv *pRuntimeEnv, void* pBlock, int32_t type); -SBlockInfo getBlockBasicInfo(SQueryRuntimeEnv* pRuntimeEnv, void* pBlock, int32_t blockType); SCacheBlock* getCacheDataBlock(SMeterObj* pMeterObj, SQueryRuntimeEnv* pRuntimeEnv, int32_t slot); -void queryOnBlock(SMeterQuerySupportObj* pSupporter, int64_t* primaryKeys, int32_t blockStatus, - SBlockInfo* pBlockBasicInfo, SMeterDataInfo* pDataHeadInfoEx, SField* pFields, - __block_search_fn_t searchFn); +void stableApplyFunctionsOnBlock(STableQuerySupportObj* pSupporter, SMeterDataInfo* pMeterDataInfo, + SBlockInfo* pBlockInfo, SField* pFields, __block_search_fn_t searchFn); -int32_t vnodeFilterQualifiedMeters(SQInfo *pQInfo, int32_t vid, tSidSet *pSidSet, SMeterDataInfo *pMeterDataInfo, - int32_t *numOfMeters, SMeterDataInfo ***pReqMeterDataInfo); -int32_t vnodeGetVnodeHeaderFileIdx(int32_t* fid, SQueryRuntimeEnv* pRuntimeEnv, int32_t order); +int32_t vnodeFilterQualifiedMeters(SQInfo* pQInfo, int32_t vid, tSidSet* pSidSet, SMeterDataInfo* pMeterDataInfo, + int32_t* numOfMeters, SMeterDataInfo*** pReqMeterDataInfo); +int32_t vnodeGetVnodeHeaderFileIndex(int32_t* fid, SQueryRuntimeEnv* pRuntimeEnv, int32_t order); int32_t createDataBlocksInfoEx(SMeterDataInfo** pMeterDataInfo, int32_t numOfMeters, SMeterDataBlockInfoEx** pDataBlockInfoEx, int32_t numOfCompBlocks, int32_t* nAllocBlocksInfoSize, int64_t addr); -void freeMeterBlockInfoEx(SMeterDataBlockInfoEx* pDataBlockInfoEx, int32_t len); +void freeMeterBlockInfoEx(SMeterDataBlockInfoEx* pDataBlockInfoEx, int32_t len); -void setExecutionContext(SMeterQuerySupportObj* pSupporter, SOutputRes* outputRes, int32_t meterIdx, int32_t groupIdx, - SMeterQueryInfo* sqinfo); -int32_t setIntervalQueryExecutionContext(SMeterQuerySupportObj* pSupporter, int32_t meterIdx, SMeterQueryInfo* sqinfo); +void setExecutionContext(STableQuerySupportObj* pSupporter, SMeterQueryInfo* pMeterQueryInfo, int32_t meterIdx, + int32_t groupIdx, TSKEY nextKey); +int32_t setAdditionalInfo(STableQuerySupportObj *pSupporter, int32_t meterIdx, SMeterQueryInfo *pMeterQueryInfo); +void doGetAlignedIntervalQueryRangeImpl(SQuery* pQuery, int64_t pKey, int64_t keyFirst, int64_t keyLast, + int64_t* actualSkey, int64_t* actualEkey, int64_t* skey, int64_t* ekey); int64_t getQueryStartPositionInCache(SQueryRuntimeEnv* pRuntimeEnv, int32_t* slot, int32_t* pos, bool ignoreQueryRange); -int64_t getNextAccessedKeyInData(SQuery* pQuery, int64_t* pPrimaryCol, SBlockInfo* pBlockInfo, int32_t blockStatus); -int32_t getDataBlocksForMeters(SMeterQuerySupportObj* pSupporter, SQuery* pQuery, int32_t numOfMeters, - const char* filePath, SMeterDataInfo** pMeterDataInfo, uint32_t* numOfBlocks); +int32_t getDataBlocksForMeters(STableQuerySupportObj* pSupporter, SQuery* pQuery, int32_t numOfMeters, + const char* filePath, SMeterDataInfo** pMeterDataInfo, uint32_t* numOfBlocks); int32_t LoadDatablockOnDemand(SCompBlock* pBlock, SField** pFields, uint8_t* blkStatus, SQueryRuntimeEnv* pRuntimeEnv, int32_t fileIdx, int32_t slotIdx, __block_search_fn_t searchFn, bool onDemand); -int32_t vnodeGetHeaderFile(SQueryRuntimeEnv *pRuntimeEnv, int32_t fileIndex); +int32_t vnodeGetHeaderFile(SQueryRuntimeEnv* pRuntimeEnv, int32_t fileIndex); /** * Create SMeterQueryInfo. @@ -210,14 +209,14 @@ int32_t vnodeGetHeaderFile(SQueryRuntimeEnv *pRuntimeEnv, int32_t fileIndex); * @param ekey * @return */ -SMeterQueryInfo* createMeterQueryInfo(SQuery* pQuery, int32_t sid, TSKEY skey, TSKEY ekey); +SMeterQueryInfo* createMeterQueryInfo(STableQuerySupportObj* pSupporter, int32_t sid, TSKEY skey, TSKEY ekey); /** * Destroy meter query info * @param pMeterQInfo * @param numOfCols */ -void destroyMeterQueryInfo(SMeterQueryInfo *pMeterQueryInfo, int32_t numOfCols); +void destroyMeterQueryInfo(SMeterQueryInfo* pMeterQueryInfo, int32_t numOfCols); /** * change the meter query info for supplement scan @@ -225,7 +224,8 @@ void destroyMeterQueryInfo(SMeterQueryInfo *pMeterQueryInfo, int32_t numOfCols); * @param skey * @param ekey */ -void changeMeterQueryInfoForSuppleQuery(SQueryResultBuf* pResultBuf, SMeterQueryInfo *pMeterQueryInfo, TSKEY skey, TSKEY ekey); +void changeMeterQueryInfoForSuppleQuery(SQuery* pQuery, SMeterQueryInfo* pMeterQueryInfo, + TSKEY skey, TSKEY ekey); /** * add the new allocated disk page to meter query info @@ -234,14 +234,8 @@ void changeMeterQueryInfoForSuppleQuery(SQueryResultBuf* pResultBuf, SMeterQuery * @param pMeterQueryInfo * @param pSupporter */ -tFilePage* addDataPageForMeterQueryInfo(SQuery* pQuery, SMeterQueryInfo *pMeterQueryInfo, SMeterQuerySupportObj *pSupporter); - -/** - * save the query range data into SMeterQueryInfo - * @param pRuntimeEnv - * @param pMeterQueryInfo - */ -void saveIntervalQueryRange(SQueryRuntimeEnv* pRuntimeEnv, SMeterQueryInfo* pMeterQueryInfo); +tFilePage* addDataPageForMeterQueryInfo(SQuery* pQuery, SMeterQueryInfo* pMeterQueryInfo, + STableQuerySupportObj* pSupporter); /** * restore the query range data from SMeterQueryInfo to runtime environment @@ -258,7 +252,7 @@ void restoreIntervalQueryRange(SQueryRuntimeEnv* pRuntimeEnv, SMeterQueryInfo* p * @param pSupporter * @param key */ -void setIntervalQueryRange(SMeterQueryInfo *pMeterQueryInfo, SMeterQuerySupportObj* pSupporter, int64_t key); +void setIntervalQueryRange(SMeterQueryInfo* pMeterQueryInfo, STableQuerySupportObj* pSupporter, int64_t key); /** * set the meter data information @@ -275,16 +269,22 @@ void vnodeCheckIfDataExists(SQueryRuntimeEnv* pRuntimeEnv, SMeterObj* pMeterObj, void displayInterResult(SData** pdata, SQuery* pQuery, int32_t numOfRows); -void vnodePrintQueryStatistics(SMeterQuerySupportObj* pSupporter); +void vnodePrintQueryStatistics(STableQuerySupportObj* pSupporter); + +void clearTimeWindowResBuf(SQueryRuntimeEnv* pRuntimeEnv, SWindowResult* pOneOutputRes); +void copyTimeWindowResBuf(SQueryRuntimeEnv* pRuntimeEnv, SWindowResult* dst, const SWindowResult* src); + +int32_t initWindowResInfo(SWindowResInfo* pWindowResInfo, SQueryRuntimeEnv* pRuntimeEnv, int32_t size, + int32_t threshold, int16_t type); -void clearGroupResultBuf(SQueryRuntimeEnv *pRuntimeEnv, SOutputRes *pOneOutputRes); -void copyGroupResultBuf(SQueryRuntimeEnv *pRuntimeEnv, SOutputRes* dst, const SOutputRes* src); +void cleanupTimeWindowInfo(SWindowResInfo* pWindowResInfo, SQueryRuntimeEnv* pRuntimeEnv); +void resetTimeWindowInfo(SQueryRuntimeEnv* pRuntimeEnv, SWindowResInfo* pWindowResInfo); +void clearFirstNTimeWindow(SQueryRuntimeEnv *pRuntimeEnv, int32_t num); -void resetSlidingWindowInfo(SQueryRuntimeEnv *pRuntimeEnv, SSlidingWindowInfo* pSlidingWindowInfo); -void clearCompletedSlidingWindows(SQueryRuntimeEnv* pRuntimeEnv); -int32_t numOfClosedSlidingWindow(SSlidingWindowInfo* pSlidingWindowInfo); -void closeSlidingWindow(SSlidingWindowInfo* pSlidingWindowInfo, int32_t slot); -void closeAllSlidingWindow(SSlidingWindowInfo* pSlidingWindowInfo); +void clearClosedTimeWindow(SQueryRuntimeEnv* pRuntimeEnv); +int32_t numOfClosedTimeWindow(SWindowResInfo* pWindowResInfo); +void closeTimeWindow(SWindowResInfo* pWindowResInfo, int32_t slot); +void closeAllTimeWindow(SWindowResInfo* pWindowResInfo); #ifdef __cplusplus } diff --git a/src/vnode/detail/inc/vnodeRead.h b/src/vnode/detail/inc/vnodeRead.h index 2765ff76fc5f120ca7f8ccc2214196b54dfd8507..2758cfe1d9610257c7ddf0658874a7ee57511fc0 100644 --- a/src/vnode/detail/inc/vnodeRead.h +++ b/src/vnode/detail/inc/vnodeRead.h @@ -86,16 +86,26 @@ typedef struct SQueryCostSummary { } SQueryCostSummary; typedef struct SPosInfo { - int64_t pageId; - int32_t rowId; + int16_t pageId; + int16_t rowId; } SPosInfo; -typedef struct SOutputRes { +typedef struct STimeWindow { + TSKEY skey; + TSKEY ekey; +} STimeWindow; + +typedef struct SWindowStatus { + bool closed; +} SWindowStatus; + +typedef struct SWindowResult { uint16_t numOfRows; - int32_t nAlloc; - SPosInfo pos; - SResultInfo* resultInfo; -} SOutputRes; + SPosInfo pos; // Position of current result in disk-based output buffer + SResultInfo* resultInfo; // For each result column, there is a resultInfo + STimeWindow window; // The time window that current result covers. + SWindowStatus status; +} SWindowResult; /* * header files info, avoid to iterate the directory, the data is acquired @@ -118,19 +128,8 @@ typedef struct SQueryFilesInfo { char dbFilePathPrefix[PATH_MAX]; } SQueryFilesInfo; -typedef struct STimeWindow { - TSKEY skey; - TSKEY ekey; -} STimeWindow; - -typedef struct SWindowStatus { - STimeWindow window; - bool closed; -} SWindowStatus; - -typedef struct SSlidingWindowInfo { - SOutputRes* pResult; // reference to SQuerySupporter->pResult - SWindowStatus* pStatus; // current query window closed or not? +typedef struct SWindowResInfo { + SWindowResult* pResult; // reference to SQuerySupporter->pResult void* hashList; // hash list for quick access int16_t type; // data type for hash key int32_t capacity; // max capacity @@ -140,14 +139,14 @@ typedef struct SSlidingWindowInfo { int64_t startTime; // start time of the first time window for sliding query int64_t prevSKey; // previous (not completed) sliding window start key int64_t threshold; // threshold for return completed results. -} SSlidingWindowInfo; +} SWindowResInfo; typedef struct SQueryRuntimeEnv { SPositionInfo startPos; /* the start position, used for secondary/third iteration */ SPositionInfo endPos; /* the last access position in query, served as the start pos of reversed order query */ SPositionInfo nextPos; /* start position of the next scan */ SData* colDataBuffer[TSDB_MAX_COLUMNS]; - SResultInfo* resultInfo; + SResultInfo* resultInfo; // todo refactor to merge with SWindowResInfo uint8_t blockStatus; // Indicate if data block is loaded, the block is first/last/internal block int32_t unzipBufSize; SData* primaryColBuffer; @@ -161,28 +160,25 @@ typedef struct SQueryRuntimeEnv { SQueryFilesInfo vnodeFileInfo; int16_t numOfRowsPerPage; int16_t offset[TSDB_MAX_COLUMNS]; - int16_t scanFlag; // denotes reversed scan of data or not + uint16_t scanFlag; // denotes reversed scan of data or not SInterpolationInfo interpoInfo; SData** pInterpoBuf; - SSlidingWindowInfo swindowResInfo; + SWindowResInfo windowResInfo; STSBuf* pTSBuf; STSCursor cur; SQueryCostSummary summary; - - STimeWindow intervalWindow; // the complete time window, not affected by the actual data distribution + bool stableQuery; // is super table query or not + SQueryDiskbasedResultBuf* pResultBuf; // query result buffer based on blocked-wised disk file /* * Temporarily hold the in-memory cache block info during scan cache blocks - * Here we do not use the cacheblock info from pMeterObj, simple because it may change anytime - * during the query by the subumit/insert handling threads. + * Here we do not use the cache block info from pMeterObj, simple because it may change anytime + * during the query by the submit/insert handling threads. * So we keep a copy of the support structure as well as the cache block data itself. */ SCacheBlock cacheBlock; - - SQueryResultBuf* pResultBuf; - bool stableQuery; // is super table query or not } SQueryRuntimeEnv; /* intermediate pos during multimeter query involves interval */ @@ -191,14 +187,12 @@ typedef struct SMeterQueryInfo { int64_t skey; int64_t ekey; int32_t numOfRes; - int32_t reverseIndex; // reversed output indicator, start from (numOfRes-1) - int16_t reverseFillRes; // denote if reverse fill the results in supplementary scan required or not int16_t queryRangeSet; // denote if the query range is set, only available for interval query - int16_t lastResRows; int64_t tag; STSCursor cur; - SResultInfo* resultInfo; int32_t sid; // for retrieve the page id list + + SWindowResInfo windowResInfo; } SMeterQueryInfo; typedef struct SMeterDataInfo { @@ -212,7 +206,7 @@ typedef struct SMeterDataInfo { SMeterQueryInfo* pMeterQInfo; } SMeterDataInfo; -typedef struct SMeterQuerySupportObj { +typedef struct STableQuerySupportObj { void* pMetersHashTable; // meter table hash list SMeterSidExtInfo** pMeterSidExtInfo; @@ -225,13 +219,11 @@ typedef struct SMeterQuerySupportObj { * rows may be generated by a specific subgroup. When query on all subgroups is executed, * the result is copy to output buffer. This attribution is not used during single meter query processing. */ - SOutputRes* pResult; SQueryRuntimeEnv runtimeEnv; int64_t rawSKey; int64_t rawEKey; int32_t subgroupIdx; int32_t offset; /* offset in group result set of subgroup */ - tSidSet* pSidSet; /* @@ -247,7 +239,7 @@ typedef struct SMeterQuerySupportObj { SMeterDataInfo* pMeterDataInfo; TSKEY* tsList; -} SMeterQuerySupportObj; +} STableQuerySupportObj; typedef struct _qinfo { uint64_t signature; @@ -273,18 +265,18 @@ typedef struct _qinfo { SMeterObj* pObj; sem_t dataReady; - SMeterQuerySupportObj* pMeterQuerySupporter; + STableQuerySupportObj* pTableQuerySupporter; int (*fp)(SMeterObj*, SQuery*); } SQInfo; -int32_t vnodeQuerySingleMeterPrepare(SQInfo* pQInfo, SMeterObj* pMeterObj, SMeterQuerySupportObj* pSMultiMeterObj, +int32_t vnodeQueryTablePrepare(SQInfo* pQInfo, SMeterObj* pMeterObj, STableQuerySupportObj* pSMultiMeterObj, void* param); void vnodeQueryFreeQInfoEx(SQInfo* pQInfo); bool vnodeParametersSafetyCheck(SQuery* pQuery); -int32_t vnodeMultiMeterQueryPrepare(SQInfo* pQInfo, SQuery* pQuery, void* param); +int32_t vnodeSTableQueryPrepare(SQInfo* pQInfo, SQuery* pQuery, void* param); /** * decrease the numofQuery of each table that is queried, enable the diff --git a/src/vnode/detail/src/vnodeQueryImpl.c b/src/vnode/detail/src/vnodeQueryImpl.c index 104e4b859e3009fd3741957b32583162a3f32ceb..f761205719c8020b871448942461b2df2dc265d9 100644 --- a/src/vnode/detail/src/vnodeQueryImpl.c +++ b/src/vnode/detail/src/vnodeQueryImpl.c @@ -13,9 +13,9 @@ * along with this program. If not, see . */ -#include "os.h" #include "hash.h" #include "hashutil.h" +#include "os.h" #include "taosmsg.h" #include "textbuffer.h" #include "ttime.h" @@ -55,7 +55,7 @@ static int32_t readDataFromDiskFile(int fd, SQInfo *pQInfo, SQueryFilesInfo *pQu static void vnodeInitLoadCompBlockInfo(SLoadCompBlockInfo *pCompBlockLoadInfo); static int32_t moveToNextBlock(SQueryRuntimeEnv *pRuntimeEnv, int32_t step, __block_search_fn_t searchFn, bool loadData); -static int32_t doMergeMetersResultsToGroupRes(SMeterQuerySupportObj *pSupporter, SQuery *pQuery, +static int32_t doMergeMetersResultsToGroupRes(STableQuerySupportObj *pSupporter, SQuery *pQuery, SQueryRuntimeEnv *pRuntimeEnv, SMeterDataInfo *pMeterDataInfo, int32_t start, int32_t end); @@ -65,25 +65,22 @@ static TSKEY getTimestampInDiskBlock(SQueryRuntimeEnv *pRuntimeEnv, int32_t inde static void savePointPosition(SPositionInfo *position, int32_t fileId, int32_t slot, int32_t pos); static int32_t getNextDataFileCompInfo(SQueryRuntimeEnv *pRuntimeEnv, SMeterObj *pMeterObj, int32_t step); -static void setGroupOutputBuffer(SQueryRuntimeEnv *pRuntimeEnv, SOutputRes *pResult); - -static void getAlignedIntervalQueryRange(SQueryRuntimeEnv *pRuntimeEnv, TSKEY keyInData, TSKEY skey, TSKEY ekey); - -static int32_t saveResult(SMeterQuerySupportObj *pSupporter, SMeterQueryInfo *pMeterQueryInfo, int32_t numOfResult); -static void applyIntervalQueryOnBlock(SMeterQuerySupportObj *pSupporter, SMeterDataInfo *pMeterDataInfo, - SBlockInfo *pBlockInfo, int32_t blockStatus, SField *pFields, - __block_search_fn_t searchFn); +static void setWindowResOutputBuf(SQueryRuntimeEnv *pRuntimeEnv, SWindowResult *pResult); -static void resetMergeResultBuf(SQuery *pQuery, SQLFunctionCtx *pCtx); -static int32_t flushFromResultBuf(SMeterQuerySupportObj *pSupporter, const SQuery *pQuery, +static void resetMergeResultBuf(SQuery *pQuery, SQLFunctionCtx *pCtx, SResultInfo *pResultInfo); +static int32_t flushFromResultBuf(STableQuerySupportObj *pSupporter, const SQuery *pQuery, const SQueryRuntimeEnv *pRuntimeEnv); -static void validateTimestampForSupplementResult(SQueryRuntimeEnv *pRuntimeEnv, int64_t numOfIncrementRes); static void getBasicCacheInfoSnapshot(SQuery *pQuery, SCacheInfo *pCacheInfo, int32_t vid); static TSKEY getQueryPositionForCacheInvalid(SQueryRuntimeEnv *pRuntimeEnv, __block_search_fn_t searchFn); static bool functionNeedToExecute(SQueryRuntimeEnv *pRuntimeEnv, SQLFunctionCtx *pCtx, int32_t functionId); -static void doGetAlignedIntervalQueryRangeImpl(SQuery *pQuery, int64_t pKey, int64_t keyFirst, int64_t keyLast, - int64_t *actualSkey, int64_t *actualEkey, int64_t *skey, int64_t *ekey); -static void getNextLogicalQueryRange(SQueryRuntimeEnv *pRuntimeEnv, STimeWindow* pTimeWindow); +static void getNextTimeWindow(SQuery *pQuery, STimeWindow *pTimeWindow); + +static int32_t getGroupResultId(int32_t groupIndex) { + int32_t base = 200000; + return base + (groupIndex * 10000); +} + +static FORCE_INLINE bool isIntervalQuery(SQuery *pQuery) { return pQuery->intervalTime > 0; } // check the offset value integrity static FORCE_INLINE int32_t validateHeaderOffsetSegment(SQInfo *pQInfo, char *filePath, int32_t vid, char *data, @@ -248,7 +245,7 @@ static void vnodeInitLoadCompBlockInfo(SLoadCompBlockInfo *pCompBlockLoadInfo) { } static int32_t vnodeIsDatablockLoaded(SQueryRuntimeEnv *pRuntimeEnv, SMeterObj *pMeterObj, int32_t fileIndex, - bool loadPrimaryTS) { + bool loadTS) { SQuery * pQuery = pRuntimeEnv->pQuery; SLoadDataBlockInfo *pLoadInfo = &pRuntimeEnv->loadBlockInfo; @@ -256,7 +253,7 @@ static int32_t vnodeIsDatablockLoaded(SQueryRuntimeEnv *pRuntimeEnv, SMeterObj * if (pLoadInfo->fileId == pQuery->fileId && pLoadInfo->slotIdx == pQuery->slot && pQuery->slot != -1 && pLoadInfo->sid == pMeterObj->sid && pLoadInfo->fileListIndex == fileIndex) { // previous load operation does not load the primary timestamp column, we only need to load the timestamp column - if (pLoadInfo->tsLoaded == false && pLoadInfo->tsLoaded != loadPrimaryTS) { + if (pLoadInfo->tsLoaded == false && pLoadInfo->tsLoaded != loadTS) { return DISK_BLOCK_LOAD_TS; } else { return DISK_BLOCK_NO_NEED_TO_LOAD; @@ -402,7 +399,6 @@ static void doCloseQueryFiles(SQueryFilesInfo *pVnodeFileInfo) { assert(pVnodeFileInfo->current < pVnodeFileInfo->numOfFiles && pVnodeFileInfo->current >= 0); pVnodeFileInfo->headerFileSize = -1; - doCloseQueryFileInfoFD(pVnodeFileInfo); } @@ -461,11 +457,12 @@ static int vnodeGetCompBlockInfo(SMeterObj *pMeterObj, SQueryRuntimeEnv *pRuntim SHeaderFileInfo *pHeadeFileInfo = &pRuntimeEnv->vnodeFileInfo.pFileInfo[fileIndex]; int64_t st = taosGetTimestampUs(); - - if (vnodeIsCompBlockInfoLoaded(pRuntimeEnv, pMeterObj, fileIndex)) { + + // if the corresponding data/header files are already closed, re-open them here + if (vnodeIsCompBlockInfoLoaded(pRuntimeEnv, pMeterObj, fileIndex) && + pRuntimeEnv->vnodeFileInfo.current == fileIndex) { dTrace("QInfo:%p vid:%d sid:%d id:%s, fileId:%d compBlock info is loaded, not reload", GET_QINFO_ADDR(pQuery), pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, pHeadeFileInfo->fileID); - return pQuery->numOfBlocks; } @@ -586,9 +583,9 @@ static void setExecParams(SQuery *pQuery, SQLFunctionCtx *pCtx, int64_t StartQue char *primaryColumnData, int32_t size, int32_t functionId, SField *pField, bool hasNull, int32_t blockStatus, void *param, int32_t scanFlag); -void createQueryResultBuf(SQueryRuntimeEnv *pRuntimeEnv, SOutputRes *pResultRow, bool isSTableQuery, SPosInfo *posInfo); +void createQueryResultInfo(SQuery *pQuery, SWindowResult *pResultRow, bool isSTableQuery, SPosInfo *posInfo); -static void destroyGroupResultBuf(SOutputRes *pOneOutputRes, int32_t nOutputCols); +static void destroyTimeWindowRes(SWindowResult *pOneOutputRes, int32_t nOutputCols); static int32_t binarySearchForBlockImpl(SCompBlock *pBlock, int32_t numOfBlocks, TSKEY skey, int32_t order) { int32_t firstSlot = 0; @@ -921,7 +918,7 @@ static int32_t loadDataBlockIntoMem(SCompBlock *pBlock, SField **pField, SQueryR int32_t ret = 0; /* the first round always be 1, the secondary round is determined by queried function */ - int32_t round = pRuntimeEnv->scanFlag; + int32_t round = (IS_MASTER_SCAN(pRuntimeEnv)) ? 0 : 1; while (j < pBlock->numOfCols && i < pQuery->numOfCols) { if ((*pField)[j].colId < pQuery->colList[i].data.colId) { @@ -988,7 +985,6 @@ static int32_t loadDataBlockIntoMem(SCompBlock *pBlock, SField **pField, SQueryR return ret; } -// todo ignore the blockType, pass the pQuery into this function SBlockInfo getBlockBasicInfo(SQueryRuntimeEnv *pRuntimeEnv, void *pBlock, int32_t blockType) { SBlockInfo blockInfo = {0}; if (IS_FILE_BLOCK(blockType)) { @@ -1010,22 +1006,6 @@ SBlockInfo getBlockBasicInfo(SQueryRuntimeEnv *pRuntimeEnv, void *pBlock, int32_ return blockInfo; } -static bool checkQueryRangeAgainstNextBlock(SBlockInfo *pBlockInfo, SQueryRuntimeEnv *pRuntimeEnv) { - SQuery *pQuery = pRuntimeEnv->pQuery; - - if ((QUERY_IS_ASC_QUERY(pQuery) && pBlockInfo->keyFirst > pQuery->ekey) || - (!QUERY_IS_ASC_QUERY(pQuery) && pBlockInfo->keyLast < pQuery->ekey)) { - int32_t pos = QUERY_IS_ASC_QUERY(pQuery) ? 0 : pBlockInfo->size - 1; - - savePointPosition(&pRuntimeEnv->nextPos, pQuery->fileId, pQuery->slot, pos); - setQueryStatus(pQuery, QUERY_COMPLETED); - - return false; - } - - return true; -} - /** * * @param pQuery @@ -1033,29 +1013,34 @@ static bool checkQueryRangeAgainstNextBlock(SBlockInfo *pBlockInfo, SQueryRuntim * @param forwardStep * @return TRUE means query not completed, FALSE means query is completed */ -static bool queryCompleteInBlock(SQuery *pQuery, SBlockInfo *pBlockInfo, int32_t forwardStep) { - if (Q_STATUS_EQUAL(pQuery->over, QUERY_RESBUF_FULL)) { - // assert(pQuery->checkBufferInLoop == 1 && pQuery->over == QUERY_RESBUF_FULL && pQuery->pointsOffset == 0); +static bool queryPausedInCurrentBlock(SQuery *pQuery, SBlockInfo *pBlockInfo, int32_t forwardStep) { + // current query completed + if ((pQuery->lastKey > pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) || + (pQuery->lastKey < pQuery->ekey && !QUERY_IS_ASC_QUERY(pQuery))) { + setQueryStatus(pQuery, QUERY_COMPLETED); + return true; + } + // output buffer is full, pause current query + if (Q_STATUS_EQUAL(pQuery->over, QUERY_RESBUF_FULL)) { assert((QUERY_IS_ASC_QUERY(pQuery) && forwardStep + pQuery->pos <= pBlockInfo->size) || (!QUERY_IS_ASC_QUERY(pQuery) && pQuery->pos - forwardStep + 1 >= 0)); - // current query completed - if ((pQuery->lastKey > pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) || - (pQuery->lastKey < pQuery->ekey && !QUERY_IS_ASC_QUERY(pQuery))) { - setQueryStatus(pQuery, QUERY_COMPLETED); - } + return true; + } + if (Q_STATUS_EQUAL(pQuery->over, QUERY_COMPLETED)) { return true; - } else { // query completed - if ((pQuery->ekey <= pBlockInfo->keyLast && QUERY_IS_ASC_QUERY(pQuery)) || - (pQuery->ekey >= pBlockInfo->keyFirst && !QUERY_IS_ASC_QUERY(pQuery))) { - setQueryStatus(pQuery, QUERY_COMPLETED); - return true; - } + } - return false; + // query completed + if ((pQuery->ekey <= pBlockInfo->keyLast && QUERY_IS_ASC_QUERY(pQuery)) || + (pQuery->ekey >= pBlockInfo->keyFirst && !QUERY_IS_ASC_QUERY(pQuery))) { + setQueryStatus(pQuery, QUERY_COMPLETED); + return true; } + + return false; } /** @@ -1072,7 +1057,7 @@ void savePointPosition(SPositionInfo *position, int32_t fileId, int32_t slot, in position->pos = pos; } -bool isCacheBlockValid(SQuery *pQuery, SCacheBlock *pBlock, SMeterObj *pMeterObj) { +bool isCacheBlockValid(SQuery *pQuery, SCacheBlock *pBlock, SMeterObj *pMeterObj, int32_t slot) { if (pMeterObj != pBlock->pMeterObj || pBlock->blockId > pQuery->blockId) { SMeterObj *pNewMeterObj = pBlock->pMeterObj; char * id = (pNewMeterObj != NULL) ? pNewMeterObj->meterId : NULL; @@ -1096,11 +1081,19 @@ bool isCacheBlockValid(SQuery *pQuery, SCacheBlock *pBlock, SMeterObj *pMeterObj dWarn( "QInfo:%p vid:%d sid:%d id:%s, cache block is empty. slot:%d first:%d, last:%d, numOfBlocks:%d," "allocated but not write data yet.", - GET_QINFO_ADDR(pQuery), pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, pQuery->slot, pQuery->firstSlot, + GET_QINFO_ADDR(pQuery), pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, slot, pQuery->firstSlot, pQuery->currentSlot, pQuery->numOfBlocks); return false; } + + SCacheInfo* pCacheInfo = (SCacheInfo*) pMeterObj->pCache; + if (pCacheInfo->commitPoint == pMeterObj->pointsPerBlock && pQuery->slot == pCacheInfo->currentSlot) { + dWarn("QInfo:%p vid:%d sid:%d id:%s, cache block is committed, ignore. slot:%d first:%d, last:%d, numOfBlocks:%d", + GET_QINFO_ADDR(pQuery), pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, slot, pQuery->firstSlot, + pQuery->currentSlot, pQuery->numOfBlocks); + return false; + } return true; } @@ -1114,6 +1107,7 @@ SCacheBlock *getCacheDataBlock(SMeterObj *pMeterObj, SQueryRuntimeEnv *pRuntimeE return NULL; } + vnodeFreeFields(pQuery); getBasicCacheInfoSnapshot(pQuery, pCacheInfo, pMeterObj->vnode); SCacheBlock *pBlock = pCacheInfo->cacheBlocks[slot]; @@ -1131,7 +1125,7 @@ SCacheBlock *getCacheDataBlock(SMeterObj *pMeterObj, SQueryRuntimeEnv *pRuntimeE } // block is empty or block does not belongs to current table, return NULL value - if (!isCacheBlockValid(pQuery, pBlock, pMeterObj)) { + if (!isCacheBlockValid(pQuery, pBlock, pMeterObj, slot)) { return NULL; } @@ -1217,7 +1211,7 @@ SCacheBlock *getCacheDataBlock(SMeterObj *pMeterObj, SQueryRuntimeEnv *pRuntimeE pQuery->fileId = -1; pQuery->slot = slot; - if (!isCacheBlockValid(pQuery, pNewBlock, pMeterObj)) { + if (!isCacheBlockValid(pQuery, pNewBlock, pMeterObj, slot)) { return NULL; } @@ -1252,6 +1246,16 @@ static void *getGenericDataBlock(SMeterObj *pMeterObj, SQueryRuntimeEnv *pRuntim } } +SBlockInfo getBlockInfo(SQueryRuntimeEnv *pRuntimeEnv) { + SQuery *pQuery = pRuntimeEnv->pQuery; + + void *pBlock = getGenericDataBlock(pRuntimeEnv->pMeterObj, pRuntimeEnv, pQuery->slot); + assert(pBlock != NULL); + + int32_t blockType = IS_DISK_DATA_BLOCK(pQuery) ? BLK_FILE_BLOCK : BLK_CACHE_BLOCK; + return getBlockBasicInfo(pRuntimeEnv, pBlock, blockType); +} + static int32_t getFileIdFromKey(int32_t vid, TSKEY key) { SVnodeObj *pVnode = &vnodeList[vid]; int64_t delta = (int64_t)pVnode->cfg.daysPerFile * tsMsPerDay[(uint8_t)pVnode->cfg.precision]; @@ -1438,403 +1442,737 @@ static char *getDataBlocks(SQueryRuntimeEnv *pRuntimeEnv, SArithmeticSupport *sa return dataBlock; } -/** - * - * @param pRuntimeEnv - * @param forwardStep - * @param primaryKeyCol - * @param pFields - * @param isDiskFileBlock - * @return the incremental number of output value, so it maybe 0 for fixed number of query, - * such as count/min/max etc. - */ -static int32_t blockwiseApplyAllFunctions(SQueryRuntimeEnv *pRuntimeEnv, int32_t forwardStep, TSKEY *primaryKeyCol, - SField *pFields, SBlockInfo *pBlockInfo) { - SQLFunctionCtx *pCtx = pRuntimeEnv->pCtx; - SQuery * pQuery = pRuntimeEnv->pQuery; - - bool isDiskFileBlock = IS_FILE_BLOCK(pRuntimeEnv->blockStatus); - int64_t prevNumOfRes = getNumOfResult(pRuntimeEnv); - - SArithmeticSupport *sasArray = calloc((size_t)pQuery->numOfOutputCols, sizeof(SArithmeticSupport)); +static SWindowResult *getWindowResult(SWindowResInfo *pWindowResInfo, int32_t slot) { + assert(pWindowResInfo != NULL && slot >= 0 && slot < pWindowResInfo->size); + return &pWindowResInfo->pResult[slot]; +} - for (int32_t k = 0; k < pQuery->numOfOutputCols; ++k) { - int32_t functionId = pQuery->pSelectExpr[k].pBase.functionId; +static bool isWindowResClosed(SWindowResInfo *pWindowResInfo, int32_t slot) { + return (getWindowResult(pWindowResInfo, slot)->status.closed == true); +} - SField dummyField = {0}; +static int32_t curTimeWindow(SWindowResInfo *pWindowResInfo) { + assert(pWindowResInfo->curIndex >= 0 && pWindowResInfo->curIndex < pWindowResInfo->size); + return pWindowResInfo->curIndex; +} - bool hasNull = hasNullVal(pQuery, k, pBlockInfo, pFields, isDiskFileBlock); - char *dataBlock = getDataBlocks(pRuntimeEnv, &sasArray[k], k, forwardStep); +static SWindowResult *doSetTimeWindowFromKey(SQueryRuntimeEnv *pRuntimeEnv, SWindowResInfo *pWindowResInfo, char *pData, + int16_t bytes) { + SQuery *pQuery = pRuntimeEnv->pQuery; - SField *tpField = NULL; + int32_t *p1 = (int32_t *)taosGetDataFromHashTable(pWindowResInfo->hashList, pData, bytes); + if (p1 != NULL) { + pWindowResInfo->curIndex = *p1; + } else { // more than the capacity, reallocate the resources + if (pWindowResInfo->size >= pWindowResInfo->capacity) { + int64_t newCap = pWindowResInfo->capacity * 2; - if (pFields != NULL) { - tpField = getFieldInfo(pQuery, pBlockInfo, pFields, k); - /* - * Field info not exist, the required column is not present in current block, - * so all data must be null value in current block. - */ - if (tpField == NULL) { - tpField = &dummyField; - tpField->numOfNullPoints = (int32_t)forwardStep; + char *t = realloc(pWindowResInfo->pResult, newCap * sizeof(SWindowResult)); + if (t != NULL) { + pWindowResInfo->pResult = (SWindowResult *)t; + memset(&pWindowResInfo->pResult[pWindowResInfo->capacity], 0, sizeof(SWindowResult) * pWindowResInfo->capacity); + } else { + // todo } - } - TSKEY ts = QUERY_IS_ASC_QUERY(pQuery) ? pRuntimeEnv->intervalWindow.skey : pRuntimeEnv->intervalWindow.ekey; - setExecParams(pQuery, &pCtx[k], ts, dataBlock, (char *)primaryKeyCol, forwardStep, functionId, tpField, hasNull, - pRuntimeEnv->blockStatus, &sasArray[k], pRuntimeEnv->scanFlag); - } + for (int32_t i = pWindowResInfo->capacity; i < newCap; ++i) { + SPosInfo pos = {-1, -1}; + createQueryResultInfo(pQuery, &pWindowResInfo->pResult[i], pRuntimeEnv->stableQuery, &pos); + } - /* - * the sqlfunctionCtx parameters should be set done before all functions are invoked, - * since the selectivity + tag_prj query needs all parameters been set done. - * tag_prj function are changed to be TSDB_FUNC_TAG_DUMMY - */ - for (int32_t k = 0; k < pQuery->numOfOutputCols; ++k) { - int32_t functionId = pQuery->pSelectExpr[k].pBase.functionId; - if (functionNeedToExecute(pRuntimeEnv, &pCtx[k], functionId)) { - aAggs[functionId].xFunction(&pCtx[k]); + pWindowResInfo->capacity = newCap; } - } - int64_t numOfIncrementRes = getNumOfResult(pRuntimeEnv) - prevNumOfRes; - validateTimestampForSupplementResult(pRuntimeEnv, numOfIncrementRes); - - tfree(sasArray); + // add a new result set for a new group + pWindowResInfo->curIndex = pWindowResInfo->size++; + taosAddToHashTable(pWindowResInfo->hashList, pData, bytes, (char *)&pWindowResInfo->curIndex, sizeof(int32_t)); + } - return (int32_t)numOfIncrementRes; + return getWindowResult(pWindowResInfo, pWindowResInfo->curIndex); } -/** - * if sfields is null - * 1. count(*)/spread(ts) is invoked - * 2. this column does not exists - * - * first filter the data block according to the value filter condition, then, if the top/bottom query applied, - * invoke the filter function to decide if the data block need to be accessed or not. - * TODO handle the whole data block is NULL situation - * @param pQuery - * @param pField - * @return - */ -static bool needToLoadDataBlock(SQuery *pQuery, SField *pField, SQLFunctionCtx *pCtx, int32_t numOfTotalPoints) { - if (pField == NULL) { - return false; // no need to load data - } +// get the correct time window according to the handled timestamp +static STimeWindow getActiveTimeWindow(SWindowResInfo *pWindowResInfo, int64_t ts, SQuery *pQuery) { + STimeWindow w = {0}; - for (int32_t k = 0; k < pQuery->numOfFilterCols; ++k) { - SSingleColumnFilterInfo *pFilterInfo = &pQuery->pFilterInfo[k]; - int32_t colIndex = pFilterInfo->info.colIdx; + if (pWindowResInfo->curIndex == -1) { // the first window, from the previous stored value + w.skey = pWindowResInfo->prevSKey; + w.ekey = w.skey + pQuery->intervalTime - 1; + } else { + int32_t slot = curTimeWindow(pWindowResInfo); + w = getWindowResult(pWindowResInfo, slot)->window; + } - // this column not valid in current data block - if (colIndex < 0 || pField[colIndex].colId != pFilterInfo->info.data.colId) { - continue; - } + if (w.skey > ts || w.ekey < ts) { + int64_t st = w.skey; - // not support pre-filter operation on binary/nchar data type - if (!vnodeSupportPrefilter(pFilterInfo->info.data.type)) { - continue; + if (st > ts) { + st -= ((st - ts + pQuery->slidingTime - 1) / pQuery->slidingTime) * pQuery->slidingTime; } - // all points in current column are NULL, no need to check its boundary value - if (pField[colIndex].numOfNullPoints == numOfTotalPoints) { - continue; + int64_t et = st + pQuery->intervalTime - 1; + if (et < ts) { + st += ((ts - et + pQuery->slidingTime - 1) / pQuery->slidingTime) * pQuery->slidingTime; } - if (pFilterInfo->info.data.type == TSDB_DATA_TYPE_FLOAT) { - float minval = *(double *)(&pField[colIndex].min); - float maxval = *(double *)(&pField[colIndex].max); - - for (int32_t i = 0; i < pFilterInfo->numOfFilters; ++i) { - if (pFilterInfo->pFilters[i].fp(&pFilterInfo->pFilters[i], (char *)&minval, (char *)&maxval)) { - return true; - } - } - } else { - for (int32_t i = 0; i < pFilterInfo->numOfFilters; ++i) { - if (pFilterInfo->pFilters[i].fp(&pFilterInfo->pFilters[i], (char *)&pField[colIndex].min, - (char *)&pField[colIndex].max)) { - return true; - } - } - } + w.skey = st; + w.ekey = w.skey + pQuery->intervalTime - 1; } - for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { - int32_t functId = pQuery->pSelectExpr[i].pBase.functionId; - if (functId == TSDB_FUNC_TOP || functId == TSDB_FUNC_BOTTOM) { - return top_bot_datablock_filter(&pCtx[i], functId, (char *)&pField[i].min, (char *)&pField[i].max); - } + /* + * query border check, skey should not be bounded by the query time range, since the value skey will + * be used as the time window index value. So we only change ekey of time window accordingly. + */ + if (w.ekey > pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) { + w.ekey = pQuery->ekey; } - return true; -} + assert(ts >= w.skey && ts <= w.ekey && w.skey != 0); -static SOutputRes *doSetSlidingWindowFromKey(SSlidingWindowInfo *pSlidingWindowInfo, char *pData, int16_t bytes, - SWindowStatus **pStatus) { - int32_t p = -1; + return w; +} - int32_t *p1 = (int32_t *)taosGetDataFromHashTable(pSlidingWindowInfo->hashList, pData, bytes); - if (p1 != NULL) { - p = *p1; +static int32_t addNewWindowResultBuf(SWindowResult *pWindowRes, SQueryDiskbasedResultBuf *pResultBuf, int32_t sid, + int32_t numOfRowsPerPage) { + if (pWindowRes->pos.pageId != -1) { + return 0; + } - pSlidingWindowInfo->curIndex = p; - if (pStatus != NULL) { - *pStatus = &pSlidingWindowInfo->pStatus[p]; - } - } else { // more than the capacity, reallocate the resources - if (pSlidingWindowInfo->size >= pSlidingWindowInfo->capacity) { - int64_t newCap = pSlidingWindowInfo->capacity * 2; + tFilePage *pData = NULL; - char *t = realloc(pSlidingWindowInfo->pStatus, newCap * sizeof(SWindowStatus)); - if (t != NULL) { - pSlidingWindowInfo->pStatus = (SWindowStatus *)t; - memset(&pSlidingWindowInfo->pStatus[pSlidingWindowInfo->capacity], 0, sizeof(SWindowStatus) * pSlidingWindowInfo->capacity); - } else { - // todo - } + // in the first scan, new space needed for results + int32_t pageId = -1; + SIDList list = getDataBufPagesIdList(pResultBuf, sid); - pSlidingWindowInfo->capacity = newCap; - } + if (list.size == 0) { + pData = getNewDataBuf(pResultBuf, sid, &pageId); + } else { + pageId = getLastPageId(&list); + pData = getResultBufferPageById(pResultBuf, pageId); - // add a new result set for a new group - if (pStatus != NULL) { - *pStatus = &pSlidingWindowInfo->pStatus[pSlidingWindowInfo->size]; + if (pData->numOfElems >= numOfRowsPerPage) { + pData = getNewDataBuf(pResultBuf, sid, &pageId); + if (pData != NULL) { + assert(pData->numOfElems == 0); // number of elements must be 0 for new allocated buffer + } } + } - p = pSlidingWindowInfo->size; - pSlidingWindowInfo->curIndex = pSlidingWindowInfo->size; + if (pData == NULL) { + return -1; + } - pSlidingWindowInfo->size += 1; - taosAddToHashTable(pSlidingWindowInfo->hashList, pData, bytes, (char *)&pSlidingWindowInfo->curIndex, sizeof(int32_t)); + // set the number of rows in current disk page + if (pWindowRes->pos.pageId == -1) { // not allocated yet, allocate new buffer + pWindowRes->pos.pageId = pageId; + pWindowRes->pos.rowId = pData->numOfElems++; } - return &pSlidingWindowInfo->pResult[p]; + return 0; } -static int32_t initSlidingWindowInfo(SSlidingWindowInfo *pSlidingWindowInfo, int32_t threshold, int16_t type, int32_t rowSizes, - SOutputRes *pRes) { - pSlidingWindowInfo->capacity = threshold; - pSlidingWindowInfo->threshold = threshold; +static int32_t setWindowOutputBufByKey(SQueryRuntimeEnv *pRuntimeEnv, SWindowResInfo *pWindowResInfo, int32_t sid, + STimeWindow *win) { + assert(win->skey <= win->ekey); + SQueryDiskbasedResultBuf *pResultBuf = pRuntimeEnv->pResultBuf; - pSlidingWindowInfo->type = type; + SWindowResult *pWindowRes = doSetTimeWindowFromKey(pRuntimeEnv, pWindowResInfo, (char *)&win->skey, TSDB_KEYSIZE); + if (pWindowRes == NULL) { + return -1; + } - _hash_fn_t fn = taosGetDefaultHashFunction(type); - pSlidingWindowInfo->hashList = taosInitHashTable(threshold, fn, false); + // not assign result buffer yet, add new result buffer + if (pWindowRes->pos.pageId == -1) { + int32_t ret = addNewWindowResultBuf(pWindowRes, pResultBuf, sid, pRuntimeEnv->numOfRowsPerPage); + if (ret != 0) { + return -1; + } + } - pSlidingWindowInfo->curIndex = -1; - pSlidingWindowInfo->size = 0; - pSlidingWindowInfo->pResult = pRes; + // set time window for current result + pWindowRes->window = *win; -// createResultBuf(&pSlidingWindowInfo->pResultBuf, 10, rowSizes); - - pSlidingWindowInfo->pStatus = calloc(threshold, sizeof(SWindowStatus)); -// pSlidingWindowInfo->pResultInfo = calloc(threshold, POINTER_BYTES); - -// for(int32_t i = 0; i < threshold; ++i) { -// pSlidingWindowInfo->pResultInfo[i] = calloc((size_t)numOfOutput, sizeof(SResultInfo)); - - -// } - - if (pSlidingWindowInfo->pStatus == NULL || pSlidingWindowInfo->hashList == NULL) { - return -1; - } + setWindowResOutputBuf(pRuntimeEnv, pWindowRes); + initCtxOutputBuf(pRuntimeEnv); return TSDB_CODE_SUCCESS; } -static void destroySlidingWindowInfo(SSlidingWindowInfo *pSlidingWindowInfo) { - if (pSlidingWindowInfo == NULL || pSlidingWindowInfo->capacity == 0) { - assert(pSlidingWindowInfo->hashList == NULL && pSlidingWindowInfo->pResult == NULL); - return; +static SWindowStatus *getTimeWindowResStatus(SWindowResInfo *pWindowResInfo, int32_t slot) { + assert(slot >= 0 && slot < pWindowResInfo->size); + return &pWindowResInfo->pResult[slot].status; +} + +static int32_t getForwardStepsInBlock(int32_t numOfPoints, __block_search_fn_t searchFn, TSKEY ekey, int16_t pos, + int16_t order, int64_t *pData) { + int32_t endPos = searchFn((char *)pData, numOfPoints, ekey, order); + int32_t forwardStep = 0; + + if (endPos >= 0) { + forwardStep = (order == TSQL_SO_ASC) ? (endPos - pos) : (pos - endPos); + assert(forwardStep >= 0); + + // endPos data is equalled to the key so, we do need to read the element in endPos + if (pData[endPos] == ekey) { + forwardStep += 1; + } } - taosCleanUpHashTable(pSlidingWindowInfo->hashList); -// destroyResultBuf(pSlidingWindowInfo->pResultBuf); - - tfree(pSlidingWindowInfo->pStatus); + return forwardStep; } -void resetSlidingWindowInfo(SQueryRuntimeEnv *pRuntimeEnv, SSlidingWindowInfo *pSlidingWindowInfo) { - if (pSlidingWindowInfo == NULL || pSlidingWindowInfo->capacity == 0) { +/** + * NOTE: the query status only set for the first scan of master scan. + */ +static void doCheckQueryCompleted(SQueryRuntimeEnv *pRuntimeEnv, TSKEY lastKey, SWindowResInfo *pWindowResInfo) { + SQuery *pQuery = pRuntimeEnv->pQuery; + if (pRuntimeEnv->scanFlag != MASTER_SCAN || (!isIntervalQuery(pQuery))) { return; } - - for (int32_t i = 0; i < pSlidingWindowInfo->size; ++i) { - SOutputRes *pOneRes = &pSlidingWindowInfo->pResult[i]; - clearGroupResultBuf(pRuntimeEnv, pOneRes); + + // no qualified results exist, abort check + if (pWindowResInfo->size == 0) { + return; } - memset(pSlidingWindowInfo->pStatus, 0, sizeof(SWindowStatus) * pSlidingWindowInfo->capacity); + // query completed + if ((lastKey >= pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) || + (lastKey <= pQuery->ekey && !QUERY_IS_ASC_QUERY(pQuery))) { + closeAllTimeWindow(pWindowResInfo); - pSlidingWindowInfo->curIndex = -1; - taosCleanUpHashTable(pSlidingWindowInfo->hashList); - pSlidingWindowInfo->size = 0; - - _hash_fn_t fn = taosGetDefaultHashFunction(pSlidingWindowInfo->type); - pSlidingWindowInfo->hashList = taosInitHashTable(pSlidingWindowInfo->capacity, fn, false); + pWindowResInfo->curIndex = pWindowResInfo->size - 1; + setQueryStatus(pQuery, QUERY_COMPLETED | QUERY_RESBUF_FULL); + } else { // set the current index to be the last unclosed window + int32_t i = 0; + int64_t skey = 0; - pSlidingWindowInfo->startTime = 0; - pSlidingWindowInfo->prevSKey = 0; -} + for (i = 0; i < pWindowResInfo->size; ++i) { + SWindowResult *pResult = &pWindowResInfo->pResult[i]; + if (pResult->status.closed) { + continue; + } -void clearCompletedSlidingWindows(SQueryRuntimeEnv* pRuntimeEnv) { - SSlidingWindowInfo* pSlidingWindowInfo = &pRuntimeEnv->swindowResInfo; - if (pSlidingWindowInfo == NULL || pSlidingWindowInfo->capacity == 0 || pSlidingWindowInfo->size == 0) { - return; - } + if ((pResult->window.ekey <= lastKey && QUERY_IS_ASC_QUERY(pQuery)) || + (pResult->window.skey >= lastKey && !QUERY_IS_ASC_QUERY(pQuery))) { + closeTimeWindow(pWindowResInfo, i); + } else { + skey = pResult->window.skey; + break; + } + } - int32_t i = 0; - for (i = 0; i < pSlidingWindowInfo->size; ++i) { - SWindowStatus *pStatus = &pSlidingWindowInfo->pStatus[i]; - if (pStatus->closed) { // remove the window slot from hash table - taosDeleteFromHashTable(pSlidingWindowInfo->hashList, (const char *)&pStatus->window.skey, TSDB_KEYSIZE); + // all windows are closed, set the last one to be the skey + if (skey == 0) { + assert(i == pWindowResInfo->size); + pWindowResInfo->curIndex = pWindowResInfo->size - 1; } else { - break; + pWindowResInfo->curIndex = i; } - } - if (i == 0) { - return; - } - - int32_t remain = pSlidingWindowInfo->size - i; - - //clear remain list - memmove(pSlidingWindowInfo->pStatus, &pSlidingWindowInfo->pStatus[i], remain * sizeof(SWindowStatus)); - memset(&pSlidingWindowInfo->pStatus[remain], 0, (pSlidingWindowInfo->capacity - remain) * sizeof(SWindowStatus)); - - for(int32_t k = 0; k < remain; ++k) { - copyGroupResultBuf(pRuntimeEnv, &pSlidingWindowInfo->pResult[k], &pSlidingWindowInfo->pResult[i + k]); - } - - for(int32_t k = remain; k < pSlidingWindowInfo->size; ++k) { - SOutputRes *pOneRes = &pSlidingWindowInfo->pResult[k]; - clearGroupResultBuf(pRuntimeEnv, pOneRes); - } + pWindowResInfo->prevSKey = pWindowResInfo->pResult[pWindowResInfo->curIndex].window.skey; - pSlidingWindowInfo->size = remain; + // the number of completed slots are larger than the threshold, dump to client immediately. + int32_t n = numOfClosedTimeWindow(pWindowResInfo); + if (n > pWindowResInfo->threshold) { + setQueryStatus(pQuery, QUERY_RESBUF_FULL); + } - for(int32_t k = 0; k < pSlidingWindowInfo->size; ++k) { - SWindowStatus* pStatus = &pSlidingWindowInfo->pStatus[k]; - int32_t *p = (int32_t*) taosGetDataFromHashTable(pSlidingWindowInfo->hashList, (const char*)&pStatus->window.skey, TSDB_KEYSIZE); - int32_t v = *p; - v = (v - i); - - taosDeleteFromHashTable(pSlidingWindowInfo->hashList, (const char *)&pStatus->window.skey, TSDB_KEYSIZE); - - taosAddToHashTable(pSlidingWindowInfo->hashList, (const char*)&pStatus->window.skey, TSDB_KEYSIZE, - (char *)&v, sizeof(int32_t)); + dTrace("QInfo:%p total window:%d, closed:%d", GET_QINFO_ADDR(pQuery), pWindowResInfo->size, n); } - - pSlidingWindowInfo->curIndex = -1; -} -int32_t numOfClosedSlidingWindow(SSlidingWindowInfo *pSlidingWindowInfo) { - int32_t i = 0; - while(i < pSlidingWindowInfo->size && pSlidingWindowInfo->pStatus[i].closed) { - ++i; - } - - return i; + assert(pWindowResInfo->prevSKey != 0); } -void closeSlidingWindow(SSlidingWindowInfo* pSlidingWindowInfo, int32_t slot) { - assert(slot >= 0 && slot < pSlidingWindowInfo->size); - SWindowStatus* pStatus = &pSlidingWindowInfo->pStatus[slot]; - pStatus->closed = true; -} +static int32_t getNumOfRowsInTimeWindow(SQuery *pQuery, SBlockInfo *pBlockInfo, TSKEY *pPrimaryColumn, int32_t startPos, + TSKEY ekey, __block_search_fn_t searchFn, bool updateLastKey) { + assert(startPos >= 0 && startPos < pBlockInfo->size); -void closeAllSlidingWindow(SSlidingWindowInfo* pSlidingWindowInfo) { - assert(pSlidingWindowInfo->size >=0 && pSlidingWindowInfo->capacity >= pSlidingWindowInfo->size); - - for(int32_t i = 0; i < pSlidingWindowInfo->size; ++i) { - SWindowStatus* pStatus = &pSlidingWindowInfo->pStatus[i]; - pStatus->closed = true; + int32_t num = -1; + int32_t order = pQuery->order.order; + + int32_t step = GET_FORWARD_DIRECTION_FACTOR(order); + + if (QUERY_IS_ASC_QUERY(pQuery)) { + if (ekey < pBlockInfo->keyLast) { + num = getForwardStepsInBlock(pBlockInfo->size, searchFn, ekey, startPos, order, pPrimaryColumn); + if (num == 0) { // no qualified data in current block, do not update the lastKey value + assert(ekey < pPrimaryColumn[startPos]); + } else { + if (updateLastKey) { + pQuery->lastKey = pPrimaryColumn[startPos + (num - 1)] + step; + } + } + } else { + num = pBlockInfo->size - startPos; + if (updateLastKey) { + pQuery->lastKey = pBlockInfo->keyLast + step; + } + } + } else { // desc + if (ekey > pBlockInfo->keyFirst) { + num = getForwardStepsInBlock(pBlockInfo->size, searchFn, ekey, startPos, order, pPrimaryColumn); + if (num == 0) { // no qualified data in current block, do not update the lastKey value + assert(ekey > pPrimaryColumn[startPos]); + } else { + if (updateLastKey) { + pQuery->lastKey = pPrimaryColumn[startPos - (num - 1)] + step; + } + } + } else { + num = startPos + 1; + if (updateLastKey) { + pQuery->lastKey = pBlockInfo->keyFirst + step; + } + } } + + assert(num >= 0); + return num; } -static SWindowStatus* getSlidingWindowStatus(SSlidingWindowInfo *pSlidingWindowInfo, int32_t slot) { - return &pSlidingWindowInfo->pStatus[slot]; +static void doBlockwiseApplyFunctions(SQueryRuntimeEnv *pRuntimeEnv, SWindowStatus *pStatus, STimeWindow *pWin, + int32_t startPos, int32_t forwardStep) { + SQuery * pQuery = pRuntimeEnv->pQuery; + SQLFunctionCtx *pCtx = pRuntimeEnv->pCtx; + + if (IS_MASTER_SCAN(pRuntimeEnv) || pStatus->closed) { + for (int32_t k = 0; k < pQuery->numOfOutputCols; ++k) { + pCtx[k].nStartQueryTimestamp = pWin->skey; + pCtx[k].size = forwardStep; + pCtx[k].startOffset = (QUERY_IS_ASC_QUERY(pQuery)) ? startPos : startPos - (forwardStep - 1); + + int32_t functionId = pQuery->pSelectExpr[k].pBase.functionId; + if (functionNeedToExecute(pRuntimeEnv, &pCtx[k], functionId)) { + aAggs[functionId].xFunction(&pCtx[k]); + } + } + } } -static bool slidingWindowClosed(SSlidingWindowInfo* pSlidingWindowInfo, int32_t slot) { - return (pSlidingWindowInfo->pStatus[slot].closed == true); +static void doRowwiseApplyFunctions(SQueryRuntimeEnv *pRuntimeEnv, SWindowStatus *pStatus, STimeWindow *pWin, + int32_t offset) { + SQuery * pQuery = pRuntimeEnv->pQuery; + SQLFunctionCtx *pCtx = pRuntimeEnv->pCtx; + + if (IS_MASTER_SCAN(pRuntimeEnv) || pStatus->closed) { + for (int32_t k = 0; k < pQuery->numOfOutputCols; ++k) { + pCtx[k].nStartQueryTimestamp = pWin->skey; + + int32_t functionId = pQuery->pSelectExpr[k].pBase.functionId; + if (functionNeedToExecute(pRuntimeEnv, &pCtx[k], functionId)) { + aAggs[functionId].xFunctionF(&pCtx[k], offset); + } + } + } } -static int32_t curSlidingWindow(SSlidingWindowInfo *pSlidingWindowInfo) { - assert(pSlidingWindowInfo->curIndex >= 0 && pSlidingWindowInfo->curIndex < pSlidingWindowInfo->size); - - return pSlidingWindowInfo->curIndex; +static int32_t getNextQualifiedWindow(SQueryRuntimeEnv *pRuntimeEnv, STimeWindow *pNextWin, + SWindowResInfo *pWindowResInfo, SBlockInfo *pBlockInfo, TSKEY *primaryKeys, + __block_search_fn_t searchFn) { + SQuery *pQuery = pRuntimeEnv->pQuery; + + while (1) { + getNextTimeWindow(pQuery, pNextWin); + + if (pWindowResInfo->startTime > pNextWin->skey || (pNextWin->skey > pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) || + (pNextWin->ekey < pQuery->ekey && !QUERY_IS_ASC_QUERY(pQuery))) { + return -1; + } + + // next time window is not in current block + if ((pNextWin->skey > pBlockInfo->keyLast && QUERY_IS_ASC_QUERY(pQuery)) || + (pNextWin->ekey < pBlockInfo->keyFirst && !QUERY_IS_ASC_QUERY(pQuery))) { + return -1; + } + + TSKEY startKey = QUERY_IS_ASC_QUERY(pQuery) ? pNextWin->skey : pNextWin->ekey; + int32_t startPos = searchFn((char *)primaryKeys, pBlockInfo->size, startKey, pQuery->order.order); + + /* + * This time window does not cover any data, try next time window, + * this case may happen when the time window is too small + */ + if ((primaryKeys[startPos] > pNextWin->ekey && QUERY_IS_ASC_QUERY(pQuery)) || + (primaryKeys[startPos] < pNextWin->skey && !QUERY_IS_ASC_QUERY(pQuery))) { + continue; + } + +// if (pNextWin->ekey > pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) { +// pNextWin->ekey = pQuery->ekey; +// } +// if (pNextWin->skey < pQuery->ekey && !QUERY_IS_ASC_QUERY(pQuery)) { +// pNextWin->skey = pQuery->ekey; +// } + + return startPos; + } } -// get the correct sliding window according to the handled timestamp -static STimeWindow getActiveSlidingWindow(SSlidingWindowInfo* pSlidingWindowInfo, int64_t ts, SQuery* pQuery) { - STimeWindow w = {0}; - - if (pSlidingWindowInfo->curIndex == -1) { // the first window, from the prevous stored value - w.skey = pSlidingWindowInfo->prevSKey; - w.ekey = w.skey + pQuery->nAggTimeInterval - 1; - +static TSKEY reviseWindowEkey(SQuery *pQuery, STimeWindow *pWindow) { + TSKEY ekey = -1; + if (QUERY_IS_ASC_QUERY(pQuery)) { + ekey = pWindow->ekey; + if (ekey > pQuery->ekey) { + ekey = pQuery->ekey; + } } else { - SWindowStatus* pStatus = getSlidingWindowStatus(pSlidingWindowInfo, curSlidingWindow(pSlidingWindowInfo)); - - if (pStatus->window.skey <= ts && pStatus->window.ekey >= ts) { - w = pStatus->window; - } else { - int64_t st = pStatus->window.skey; - - while (st > ts) { - st -= pQuery->slidingTime; + ekey = pWindow->skey; + if (ekey < pQuery->ekey) { + ekey = pQuery->ekey; + } + } + + return ekey; +} + +/** + * + * @param pRuntimeEnv + * @param forwardStep + * @param primaryKeyCol + * @param pFields + * @param isDiskFileBlock + * @return the incremental number of output value, so it maybe 0 for fixed number of query, + * such as count/min/max etc. + */ +static int32_t blockwiseApplyAllFunctions(SQueryRuntimeEnv *pRuntimeEnv, int32_t forwardStep, SField *pFields, + SBlockInfo *pBlockInfo, SWindowResInfo *pWindowResInfo, + __block_search_fn_t searchFn) { + SQLFunctionCtx *pCtx = pRuntimeEnv->pCtx; + SQuery * pQuery = pRuntimeEnv->pQuery; + TSKEY * primaryKeyCol = (TSKEY *)pRuntimeEnv->primaryColBuffer->data; + + bool isDiskFileBlock = IS_FILE_BLOCK(pRuntimeEnv->blockStatus); + int64_t prevNumOfRes = getNumOfResult(pRuntimeEnv); + + SArithmeticSupport *sasArray = calloc((size_t)pQuery->numOfOutputCols, sizeof(SArithmeticSupport)); + + for (int32_t k = 0; k < pQuery->numOfOutputCols; ++k) { + int32_t functionId = pQuery->pSelectExpr[k].pBase.functionId; + + SField dummyField = {0}; + + bool hasNull = hasNullVal(pQuery, k, pBlockInfo, pFields, isDiskFileBlock); + char *dataBlock = getDataBlocks(pRuntimeEnv, &sasArray[k], k, forwardStep); + + SField *tpField = NULL; + + if (pFields != NULL) { + tpField = getFieldInfo(pQuery, pBlockInfo, pFields, k); + /* + * Field info not exist, the required column is not present in current block, + * so all data must be null value in current block. + */ + if (tpField == NULL) { + tpField = &dummyField; + tpField->numOfNullPoints = (int32_t)forwardStep; } - - while ((st + pQuery->nAggTimeInterval - 1) < ts) { - st += pQuery->slidingTime; + } + + setExecParams(pQuery, &pCtx[k], pQuery->skey, dataBlock, (char *)primaryKeyCol, forwardStep, functionId, tpField, + hasNull, pRuntimeEnv->blockStatus, &sasArray[k], pRuntimeEnv->scanFlag); + } + + int32_t step = GET_FORWARD_DIRECTION_FACTOR(pQuery->order.order); + if (isIntervalQuery(pQuery)) { + int32_t offset = GET_COL_DATA_POS(pQuery, 0, step); + TSKEY ts = primaryKeyCol[offset]; + + STimeWindow win = getActiveTimeWindow(pWindowResInfo, ts, pQuery); + if (setWindowOutputBufByKey(pRuntimeEnv, pWindowResInfo, pRuntimeEnv->pMeterObj->sid, &win) != TSDB_CODE_SUCCESS) { + return 0; + } + + TSKEY ekey = reviseWindowEkey(pQuery, &win); + forwardStep = getNumOfRowsInTimeWindow(pQuery, pBlockInfo, primaryKeyCol, pQuery->pos, ekey, searchFn, true); + + SWindowStatus *pStatus = getTimeWindowResStatus(pWindowResInfo, curTimeWindow(pWindowResInfo)); + doBlockwiseApplyFunctions(pRuntimeEnv, pStatus, &win, pQuery->pos, forwardStep); + + int32_t index = pWindowResInfo->curIndex; + STimeWindow nextWin = win; + + while (1) { + int32_t startPos = + getNextQualifiedWindow(pRuntimeEnv, &nextWin, pWindowResInfo, pBlockInfo, primaryKeyCol, searchFn); + if (startPos < 0) { + break; + } + + // null data, failed to allocate more memory buffer + int32_t sid = pRuntimeEnv->pMeterObj->sid; + if (setWindowOutputBufByKey(pRuntimeEnv, pWindowResInfo, sid, &nextWin) != TSDB_CODE_SUCCESS) { + break; + } + + ekey = reviseWindowEkey(pQuery, &nextWin); + forwardStep = getNumOfRowsInTimeWindow(pQuery, pBlockInfo, primaryKeyCol, startPos, ekey, searchFn, true); + + pStatus = getTimeWindowResStatus(pWindowResInfo, curTimeWindow(pWindowResInfo)); + doBlockwiseApplyFunctions(pRuntimeEnv, pStatus, &nextWin, startPos, forwardStep); + } + + pWindowResInfo->curIndex = index; + } else { + /* + * the sqlfunctionCtx parameters should be set done before all functions are invoked, + * since the selectivity + tag_prj query needs all parameters been set done. + * tag_prj function are changed to be TSDB_FUNC_TAG_DUMMY + */ + for (int32_t k = 0; k < pQuery->numOfOutputCols; ++k) { + int32_t functionId = pQuery->pSelectExpr[k].pBase.functionId; + if (functionNeedToExecute(pRuntimeEnv, &pCtx[k], functionId)) { + aAggs[functionId].xFunction(&pCtx[k]); } - - w.skey = st; - w.ekey = w.skey + pQuery->nAggTimeInterval - 1; } } - - assert(ts >= w.skey && ts <= w.ekey); - return w; + + /* + * No need to calculate the number of output results for group-by normal columns, interval query + * because the results of group by normal column is put into intermediate buffer. + */ + int32_t num = 0; + if (!isIntervalQuery(pQuery)) { + num = getNumOfResult(pRuntimeEnv) - prevNumOfRes; + } + + tfree(sasArray); + return (int32_t)num; } -static int32_t setGroupResultFromKey(SQueryRuntimeEnv *pRuntimeEnv, char *pData, int16_t type, int16_t bytes) { - if (isNull(pData, type)) { // ignore the null value - return -1; +/** + * if sfields is null + * 1. count(*)/spread(ts) is invoked + * 2. this column does not exists + * + * first filter the data block according to the value filter condition, then, if the top/bottom query applied, + * invoke the filter function to decide if the data block need to be accessed or not. + * TODO handle the whole data block is NULL situation + * @param pQuery + * @param pField + * @return + */ +static bool needToLoadDataBlock(SQuery *pQuery, SField *pField, SQLFunctionCtx *pCtx, int32_t numOfTotalPoints) { + if (pField == NULL) { + return false; // no need to load data } - SOutputRes *pOutputRes = doSetSlidingWindowFromKey(&pRuntimeEnv->swindowResInfo, pData, bytes, NULL); - if (pOutputRes == NULL) { - return -1; + for (int32_t k = 0; k < pQuery->numOfFilterCols; ++k) { + SSingleColumnFilterInfo *pFilterInfo = &pQuery->pFilterInfo[k]; + int32_t colIndex = pFilterInfo->info.colIdx; + + // this column not valid in current data block + if (colIndex < 0 || pField[colIndex].colId != pFilterInfo->info.data.colId) { + continue; + } + + // not support pre-filter operation on binary/nchar data type + if (!vnodeSupportPrefilter(pFilterInfo->info.data.type)) { + continue; + } + + // all points in current column are NULL, no need to check its boundary value + if (pField[colIndex].numOfNullPoints == numOfTotalPoints) { + continue; + } + + if (pFilterInfo->info.data.type == TSDB_DATA_TYPE_FLOAT) { + float minval = *(double *)(&pField[colIndex].min); + float maxval = *(double *)(&pField[colIndex].max); + + for (int32_t i = 0; i < pFilterInfo->numOfFilters; ++i) { + if (pFilterInfo->pFilters[i].fp(&pFilterInfo->pFilters[i], (char *)&minval, (char *)&maxval)) { + return true; + } + } + } else { + for (int32_t i = 0; i < pFilterInfo->numOfFilters; ++i) { + if (pFilterInfo->pFilters[i].fp(&pFilterInfo->pFilters[i], (char *)&pField[colIndex].min, + (char *)&pField[colIndex].max)) { + return true; + } + } + } } - setGroupOutputBuffer(pRuntimeEnv, pOutputRes); - initCtxOutputBuf(pRuntimeEnv); + // todo disable this opt code block temporarily + // for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { + // int32_t functId = pQuery->pSelectExpr[i].pBase.functionId; + // if (functId == TSDB_FUNC_TOP || functId == TSDB_FUNC_BOTTOM) { + // return top_bot_datablock_filter(&pCtx[i], functId, (char *)&pField[i].min, (char *)&pField[i].max); + // } + // } + + return true; +} + +int32_t initWindowResInfo(SWindowResInfo *pWindowResInfo, SQueryRuntimeEnv *pRuntimeEnv, int32_t size, + int32_t threshold, int16_t type) { + if (size < threshold) { + size = threshold; + } + + pWindowResInfo->capacity = size; + pWindowResInfo->threshold = threshold; + + pWindowResInfo->type = type; + + _hash_fn_t fn = taosGetDefaultHashFunction(type); + pWindowResInfo->hashList = taosInitHashTable(threshold, fn, false); + + pWindowResInfo->curIndex = -1; + pWindowResInfo->size = 0; + + // use the pointer arraylist + pWindowResInfo->pResult = calloc(threshold, sizeof(SWindowResult)); + for (int32_t i = 0; i < threshold; ++i) { + SPosInfo posInfo = {-1, -1}; + createQueryResultInfo(pRuntimeEnv->pQuery, &pWindowResInfo->pResult[i], pRuntimeEnv->stableQuery, &posInfo); + } return TSDB_CODE_SUCCESS; } -static int32_t setSlidingWindowFromKey(SQueryRuntimeEnv *pRuntimeEnv, STimeWindow *pTimeWindow) { - assert(pTimeWindow->skey < pTimeWindow->ekey); - - int64_t st = pTimeWindow->skey; - - SWindowStatus *pStatus = NULL; - SOutputRes* pOutputRes = doSetSlidingWindowFromKey(&pRuntimeEnv->swindowResInfo, (char *)&st, TSDB_KEYSIZE, - &pStatus); - - if (pOutputRes == NULL) { +void cleanupTimeWindowInfo(SWindowResInfo *pWindowResInfo, SQueryRuntimeEnv *pRuntimeEnv) { + if (pWindowResInfo == NULL || pWindowResInfo->capacity == 0) { + assert(pWindowResInfo->hashList == NULL && pWindowResInfo->pResult == NULL); + return; + } + + for (int32_t i = 0; i < pWindowResInfo->size; ++i) { + SWindowResult *pResult = &pWindowResInfo->pResult[i]; + destroyTimeWindowRes(pResult, pRuntimeEnv->pQuery->numOfOutputCols); + } + + taosCleanUpHashTable(pWindowResInfo->hashList); + tfree(pWindowResInfo->pResult); +} + +void resetTimeWindowInfo(SQueryRuntimeEnv *pRuntimeEnv, SWindowResInfo *pWindowResInfo) { + if (pWindowResInfo == NULL || pWindowResInfo->capacity == 0) { + return; + } + + for (int32_t i = 0; i < pWindowResInfo->size; ++i) { + SWindowResult *pWindowRes = &pWindowResInfo->pResult[i]; + clearTimeWindowResBuf(pRuntimeEnv, pWindowRes); + } + + pWindowResInfo->curIndex = -1; + taosCleanUpHashTable(pWindowResInfo->hashList); + pWindowResInfo->size = 0; + + _hash_fn_t fn = taosGetDefaultHashFunction(pWindowResInfo->type); + pWindowResInfo->hashList = taosInitHashTable(pWindowResInfo->capacity, fn, false); + + pWindowResInfo->startTime = 0; + pWindowResInfo->prevSKey = 0; +} + +void clearFirstNTimeWindow(SQueryRuntimeEnv *pRuntimeEnv, int32_t num) { + SWindowResInfo *pWindowResInfo = &pRuntimeEnv->windowResInfo; + if (pWindowResInfo == NULL || pWindowResInfo->capacity == 0 || pWindowResInfo->size == 0 || num == 0) { + return; + } + + int32_t numOfClosed = numOfClosedTimeWindow(pWindowResInfo); + assert(num >= 0 && num <= numOfClosed); + + for (int32_t i = 0; i < num; ++i) { + SWindowResult *pResult = &pWindowResInfo->pResult[i]; + if (pResult->status.closed) { // remove the window slot from hash table + taosDeleteFromHashTable(pWindowResInfo->hashList, (const char *)&pResult->window.skey, TSDB_KEYSIZE); + } else { + break; + } + } + + int32_t remain = pWindowResInfo->size - num; + + // clear all the closed windows from the window list + for (int32_t k = 0; k < remain; ++k) { + copyTimeWindowResBuf(pRuntimeEnv, &pWindowResInfo->pResult[k], &pWindowResInfo->pResult[num + k]); + } + + // move the unclosed window in the front of the window list + for (int32_t k = remain; k < pWindowResInfo->size; ++k) { + SWindowResult *pWindowRes = &pWindowResInfo->pResult[k]; + clearTimeWindowResBuf(pRuntimeEnv, pWindowRes); + } + + pWindowResInfo->size = remain; + + for (int32_t k = 0; k < pWindowResInfo->size; ++k) { + SWindowResult *pResult = &pWindowResInfo->pResult[k]; + int32_t *p = (int32_t *)taosGetDataFromHashTable(pWindowResInfo->hashList, (const char *)&pResult->window.skey, + TSDB_KEYSIZE); + int32_t v = (*p - num); + assert(v >= 0 && v <= pWindowResInfo->size); + + // todo add the update function for hash table + taosDeleteFromHashTable(pWindowResInfo->hashList, (const char *)&pResult->window.skey, TSDB_KEYSIZE); + taosAddToHashTable(pWindowResInfo->hashList, (const char *)&pResult->window.skey, TSDB_KEYSIZE, (char *)&v, + sizeof(int32_t)); + } + + pWindowResInfo->curIndex = -1; +} + +void clearClosedTimeWindow(SQueryRuntimeEnv *pRuntimeEnv) { + SWindowResInfo *pWindowResInfo = &pRuntimeEnv->windowResInfo; + if (pWindowResInfo == NULL || pWindowResInfo->capacity == 0 || pWindowResInfo->size == 0) { + return; + } + + int32_t numOfClosed = numOfClosedTimeWindow(pWindowResInfo); + clearFirstNTimeWindow(pRuntimeEnv, numOfClosed); +} + +int32_t numOfClosedTimeWindow(SWindowResInfo *pWindowResInfo) { + int32_t i = 0; + while (i < pWindowResInfo->size && pWindowResInfo->pResult[i].status.closed) { + ++i; + } + + return i; +} + +void closeTimeWindow(SWindowResInfo *pWindowResInfo, int32_t slot) { + getWindowResult(pWindowResInfo, slot)->status.closed = true; +} + +void closeAllTimeWindow(SWindowResInfo *pWindowResInfo) { + assert(pWindowResInfo->size >= 0 && pWindowResInfo->capacity >= pWindowResInfo->size); + + for (int32_t i = 0; i < pWindowResInfo->size; ++i) { + pWindowResInfo->pResult[i].status.closed = true; + } +} + +static int32_t setGroupResultOutputBuf(SQueryRuntimeEnv *pRuntimeEnv, char *pData, int16_t type, int16_t bytes) { + if (isNull(pData, type)) { // ignore the null value return -1; } - pStatus->window = *pTimeWindow; - setGroupOutputBuffer(pRuntimeEnv, pOutputRes); - initCtxOutputBuf(pRuntimeEnv); + int32_t GROUPRESULTID = 1; + + SQueryDiskbasedResultBuf *pResultBuf = pRuntimeEnv->pResultBuf; + + SWindowResult *pWindowRes = doSetTimeWindowFromKey(pRuntimeEnv, &pRuntimeEnv->windowResInfo, pData, bytes); + if (pWindowRes == NULL) { + return -1; + } + // not assign result buffer yet, add new result buffer + if (pWindowRes->pos.pageId == -1) { + int32_t ret = addNewWindowResultBuf(pWindowRes, pResultBuf, GROUPRESULTID, pRuntimeEnv->numOfRowsPerPage); + if (ret != 0) { + return -1; + } + } + + setWindowResOutputBuf(pRuntimeEnv, pWindowRes); + initCtxOutputBuf(pRuntimeEnv); return TSDB_CODE_SUCCESS; } @@ -1915,7 +2253,7 @@ static bool functionNeedToExecute(SQueryRuntimeEnv *pRuntimeEnv, SQLFunctionCtx } // in the supplementary scan, only the following functions need to be executed - if (!IS_MASTER_SCAN(pRuntimeEnv) && + if (IS_SUPPLEMENT_SCAN(pRuntimeEnv) && !(functionId == TSDB_FUNC_LAST_DST || functionId == TSDB_FUNC_FIRST_DST || functionId == TSDB_FUNC_FIRST || functionId == TSDB_FUNC_LAST || functionId == TSDB_FUNC_TAG || functionId == TSDB_FUNC_TS)) { return false; @@ -1924,10 +2262,11 @@ static bool functionNeedToExecute(SQueryRuntimeEnv *pRuntimeEnv, SQLFunctionCtx return true; } -static int32_t rowwiseApplyAllFunctions(SQueryRuntimeEnv *pRuntimeEnv, int32_t *forwardStep, TSKEY *primaryKeyCol, - SField *pFields, SBlockInfo *pBlockInfo) { +static int32_t rowwiseApplyAllFunctions(SQueryRuntimeEnv *pRuntimeEnv, int32_t *forwardStep, SField *pFields, + SBlockInfo *pBlockInfo, SWindowResInfo *pWindowResInfo) { SQLFunctionCtx *pCtx = pRuntimeEnv->pCtx; SQuery * pQuery = pRuntimeEnv->pQuery; + TSKEY * primaryKeyCol = (TSKEY *)pRuntimeEnv->primaryColBuffer->data; bool isDiskFileBlock = IS_FILE_BLOCK(pRuntimeEnv->blockStatus); SData **data = pRuntimeEnv->colDataBuffer; @@ -1955,7 +2294,8 @@ static int32_t rowwiseApplyAllFunctions(SQueryRuntimeEnv *pRuntimeEnv, int32_t * bool hasNull = hasNullVal(pQuery, k, pBlockInfo, pFields, isDiskFileBlock); char *dataBlock = getDataBlocks(pRuntimeEnv, &sasArray[k], k, *forwardStep); - TSKEY ts = QUERY_IS_ASC_QUERY(pQuery) ? pRuntimeEnv->intervalWindow.skey : pRuntimeEnv->intervalWindow.ekey; + TSKEY ts = pQuery->skey; // QUERY_IS_ASC_QUERY(pQuery) ? pRuntimeEnv->intervalWindow.skey : + // pRuntimeEnv->intervalWindow.ekey; setExecParams(pQuery, &pCtx[k], ts, dataBlock, (char *)primaryKeyCol, (*forwardStep), functionId, pFields, hasNull, pRuntimeEnv->blockStatus, &sasArray[k], pRuntimeEnv->scanFlag); } @@ -1982,14 +2322,13 @@ static int32_t rowwiseApplyAllFunctions(SQueryRuntimeEnv *pRuntimeEnv, int32_t * } int32_t j = 0; - int64_t lastKey = 0; - + TSKEY lastKey = -1; + for (j = 0; j < (*forwardStep); ++j) { int32_t offset = GET_COL_DATA_POS(pQuery, j, step); if (pRuntimeEnv->pTSBuf != NULL) { int32_t r = doTSJoinFilter(pRuntimeEnv, offset); - if (r == TS_JOIN_TAG_NOT_EQUALS) { break; } else if (r == TS_JOIN_TS_NOT_EQUALS) { @@ -2003,15 +2342,13 @@ static int32_t rowwiseApplyAllFunctions(SQueryRuntimeEnv *pRuntimeEnv, int32_t * continue; } - // sliding window query - if (pQuery->slidingTime > 0 && pQuery->nAggTimeInterval > 0) { + // interval window query + if (isIntervalQuery(pQuery)) { // decide the time window according to the primary timestamp - int64_t ts = primaryKeyCol[offset]; - - SSlidingWindowInfo* pSlidingWindowInfo = &pRuntimeEnv->swindowResInfo; - STimeWindow win = getActiveSlidingWindow(pSlidingWindowInfo, ts, pQuery); + int64_t ts = primaryKeyCol[offset]; + STimeWindow win = getActiveTimeWindow(pWindowResInfo, ts, pQuery); - int32_t ret = setSlidingWindowFromKey(pRuntimeEnv, &win); + int32_t ret = setWindowOutputBufByKey(pRuntimeEnv, pWindowResInfo, pRuntimeEnv->pMeterObj->sid, &win); if (ret != TSDB_CODE_SUCCESS) { // null data, too many state code continue; } @@ -2019,73 +2356,49 @@ static int32_t rowwiseApplyAllFunctions(SQueryRuntimeEnv *pRuntimeEnv, int32_t * // all startOffset are identical offset -= pCtx[0].startOffset; - for (int32_t k = 0; k < pQuery->numOfOutputCols; ++k) { - int32_t functionId = pQuery->pSelectExpr[k].pBase.functionId; - pCtx[k].nStartQueryTimestamp = win.skey; - - SWindowStatus* pStatus = getSlidingWindowStatus(pSlidingWindowInfo, curSlidingWindow(pSlidingWindowInfo)); - - if (!IS_MASTER_SCAN(pRuntimeEnv) && !pStatus->closed) { -// qTrace("QInfo:%p not completed in supplementary scan, ignore funcId:%d, window:%lld-%lld", -// GET_QINFO_ADDR(pQuery), functionId, pStatus->window.skey, pStatus->window.ekey); - continue; - } - - if (functionNeedToExecute(pRuntimeEnv, &pCtx[k], functionId)) { - aAggs[functionId].xFunctionF(&pCtx[k], offset); - } - } + SWindowStatus *pStatus = getTimeWindowResStatus(pWindowResInfo, curTimeWindow(pWindowResInfo)); + doRowwiseApplyFunctions(pRuntimeEnv, pStatus, &win, offset); lastKey = ts; - int32_t index = pRuntimeEnv->swindowResInfo.curIndex; - STimeWindow nextWin = win; + int32_t index = pWindowResInfo->curIndex; + int32_t sid = pRuntimeEnv->pMeterObj->sid; + while (1) { - getNextLogicalQueryRange(pRuntimeEnv, &nextWin); - if (pSlidingWindowInfo->startTime > nextWin.skey || (nextWin.skey > pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) || + getNextTimeWindow(pQuery, &nextWin); + if (pWindowResInfo->startTime > nextWin.skey || (nextWin.skey > pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) || (nextWin.skey > pQuery->skey && !QUERY_IS_ASC_QUERY(pQuery))) { - pRuntimeEnv->swindowResInfo.curIndex = index; break; } - if (ts >= nextWin.skey && ts <= nextWin.ekey) { - // null data, failed to allocate more memory buffer - if (setSlidingWindowFromKey(pRuntimeEnv, &nextWin) != TSDB_CODE_SUCCESS) { - pRuntimeEnv->swindowResInfo.curIndex = index; - break; - } + if (ts < nextWin.skey || ts > nextWin.ekey) { + break; + } - for (int32_t k = 0; k < pQuery->numOfOutputCols; ++k) { - int32_t functionId = pQuery->pSelectExpr[k].pBase.functionId; - pCtx[k].nStartQueryTimestamp = nextWin.skey; - - SWindowStatus* pStatus = getSlidingWindowStatus(pSlidingWindowInfo, curSlidingWindow(pSlidingWindowInfo)); - if (!IS_MASTER_SCAN(pRuntimeEnv) && !pStatus->closed) { -// qTrace("QInfo:%p not completed in supplementary scan, ignore funcId:%d, window:%lld-%lld", -// GET_QINFO_ADDR(pQuery), functionId, pStatus->window.skey, pStatus->window.ekey); - continue; - } - - if (functionNeedToExecute(pRuntimeEnv, &pCtx[k], functionId)) { - aAggs[functionId].xFunctionF(&pCtx[k], offset); - } - } - } else { - pRuntimeEnv->swindowResInfo.curIndex = index; + // null data, failed to allocate more memory buffer + if (setWindowOutputBufByKey(pRuntimeEnv, pWindowResInfo, sid, &nextWin) != TSDB_CODE_SUCCESS) { break; } + + pStatus = getTimeWindowResStatus(pWindowResInfo, curTimeWindow(pWindowResInfo)); + doRowwiseApplyFunctions(pRuntimeEnv, pStatus, &nextWin, offset); } + + pWindowResInfo->curIndex = index; } else { // other queries // decide which group this rows belongs to according to current state value if (groupbyStateValue) { char *stateVal = groupbyColumnData + bytes * offset; - int32_t ret = setGroupResultFromKey(pRuntimeEnv, stateVal, type, bytes); + int32_t ret = setGroupResultOutputBuf(pRuntimeEnv, stateVal, type, bytes); if (ret != TSDB_CODE_SUCCESS) { // null data, too many state code continue; } } + // update the lastKey + lastKey = primaryKeyCol[offset]; + // all startOffset are identical offset -= pCtx[0].startOffset; @@ -2110,7 +2423,7 @@ static int32_t rowwiseApplyAllFunctions(SQueryRuntimeEnv *pRuntimeEnv, int32_t * * requires checking buffer during loop */ if ((pQuery->checkBufferInLoop == 1) && (++numOfRes) >= pQuery->pointsOffset) { - pQuery->lastKey = primaryKeyCol[pQuery->pos + j * step] + step; + pQuery->lastKey = lastKey + step; *forwardStep = j + 1; break; } @@ -2118,72 +2431,18 @@ static int32_t rowwiseApplyAllFunctions(SQueryRuntimeEnv *pRuntimeEnv, int32_t * free(sasArray); - if (pQuery->slidingTime > 0 && pQuery->nAggTimeInterval > 0 && IS_MASTER_SCAN(pRuntimeEnv)) { - SSlidingWindowInfo *pSlidingWindowInfo = &pRuntimeEnv->swindowResInfo; - - // query completed - if ((lastKey >= pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) || - (lastKey <= pQuery->ekey && !QUERY_IS_ASC_QUERY(pQuery))) { - closeAllSlidingWindow(pSlidingWindowInfo); - - pSlidingWindowInfo->curIndex = pSlidingWindowInfo->size - 1; - setQueryStatus(pQuery, QUERY_COMPLETED | QUERY_RESBUF_FULL); - } else { - int32_t i = 0; - int64_t skey = 0; - - for (i = 0; i < pSlidingWindowInfo->size; ++i) { - SWindowStatus *pStatus = &pSlidingWindowInfo->pStatus[i]; - if ((pStatus->window.ekey <= lastKey && QUERY_IS_ASC_QUERY(pQuery)) || - (pStatus->window.skey >= lastKey && !QUERY_IS_ASC_QUERY(pQuery))) { - closeSlidingWindow(pSlidingWindowInfo, i); - } else { - skey = pStatus->window.skey; - break; - } - } - - pSlidingWindowInfo->prevSKey = skey; - - // the number of completed slots are larger than the threshold, dump to client immediately. - int32_t v = numOfClosedSlidingWindow(pSlidingWindowInfo); - if (v > pSlidingWindowInfo->threshold) { - setQueryStatus(pQuery, QUERY_RESBUF_FULL); - } - - dTrace("QInfo:%p total window:%d, closed:%d", GET_QINFO_ADDR(pQuery), pSlidingWindowInfo->size, v); - } - } - /* - * No need to calculate the number of output results for groupby normal columns + * No need to calculate the number of output results for group-by normal columns, interval query * because the results of group by normal column is put into intermediate buffer. */ int32_t num = 0; - if (!groupbyStateValue && !(pQuery->nAggTimeInterval > 0 && pQuery->slidingTime > 0)) { + if (!groupbyStateValue && !isIntervalQuery(pQuery)) { num = getNumOfResult(pRuntimeEnv) - prevNumOfRes; } return num; } -static int32_t getForwardStepsInBlock(int32_t numOfPoints, __block_search_fn_t searchFn, SQuery *pQuery, - int64_t *pData) { - int32_t endPos = searchFn((char *)pData, numOfPoints, pQuery->ekey, pQuery->order.order); - int32_t forwardStep = 0; - - if (endPos >= 0) { - forwardStep = QUERY_IS_ASC_QUERY(pQuery) ? (endPos - pQuery->pos) : (pQuery->pos - endPos); - assert(forwardStep >= 0); - - // endPos data is equalled to the key so, we do need to read the element in endPos - if (pData[endPos] == pQuery->ekey) { - forwardStep += 1; - } - } - return forwardStep; -} - static int32_t reviseForwardSteps(SQueryRuntimeEnv *pRuntimeEnv, int32_t forwardStep) { /* * 1. If value filter exists, we try all data in current block, and do not set the QUERY_RESBUF_FULL flag. @@ -2229,51 +2488,18 @@ static void validateQueryRangeAndData(SQueryRuntimeEnv *pRuntimeEnv, const TSKEY !QUERY_IS_ASC_QUERY(pQuery))); } -static int32_t applyFunctionsOnBlock(SQueryRuntimeEnv *pRuntimeEnv, SBlockInfo *pBlockInfo, int64_t *pPrimaryColumn, - SField *pFields, __block_search_fn_t searchFn, int32_t *numOfRes) { - int32_t forwardStep = 0; +static int32_t tableApplyFunctionsOnBlock(SQueryRuntimeEnv *pRuntimeEnv, SBlockInfo *pBlockInfo, SField *pFields, + __block_search_fn_t searchFn, int32_t *numOfRes, + SWindowResInfo *pWindowResInfo) { SQuery *pQuery = pRuntimeEnv->pQuery; - - int32_t step = GET_FORWARD_DIRECTION_FACTOR(pQuery->order.order); + TSKEY * pPrimaryColumn = (TSKEY *)pRuntimeEnv->primaryColBuffer->data; validateQueryRangeAndData(pRuntimeEnv, pPrimaryColumn, pBlockInfo); - if (QUERY_IS_ASC_QUERY(pQuery)) { - if (pQuery->ekey < pBlockInfo->keyLast) { - forwardStep = getForwardStepsInBlock(pBlockInfo->size, searchFn, pQuery, pPrimaryColumn); - assert(forwardStep >= 0); - - if (forwardStep == 0) { - // no qualified data in current block, do not update the lastKey value - assert(pQuery->ekey < pPrimaryColumn[pQuery->pos]); - } else { - pQuery->lastKey = pQuery->ekey + step;//pPrimaryColumn[pQuery->pos + (forwardStep - 1)] + step; - } - - } else { - forwardStep = pBlockInfo->size - pQuery->pos; - assert(forwardStep > 0); - - pQuery->lastKey = pBlockInfo->keyLast + step; - } - } else { // desc - if (pQuery->ekey > pBlockInfo->keyFirst) { - forwardStep = getForwardStepsInBlock(pBlockInfo->size, searchFn, pQuery, pPrimaryColumn); - assert(forwardStep >= 0); - - if (forwardStep == 0) { - // no qualified data in current block, do not update the lastKey value - assert(pQuery->ekey > pPrimaryColumn[pQuery->pos]); - } else { - pQuery->lastKey = pQuery->ekey + step;//pPrimaryColumn[pQuery->pos - (forwardStep - 1)] + step; - } - } else { - forwardStep = pQuery->pos + 1; - assert(forwardStep > 0); - - pQuery->lastKey = pBlockInfo->keyFirst + step; - } - } + int32_t step = GET_FORWARD_DIRECTION_FACTOR(pQuery->order.order); + int32_t forwardStep = + getNumOfRowsInTimeWindow(pQuery, pBlockInfo, pPrimaryColumn, pQuery->pos, pQuery->ekey, searchFn, true); + assert(forwardStep >= 0); int32_t newForwardStep = reviseForwardSteps(pRuntimeEnv, forwardStep); assert(newForwardStep <= forwardStep && newForwardStep >= 0); @@ -2283,11 +2509,20 @@ static int32_t applyFunctionsOnBlock(SQueryRuntimeEnv *pRuntimeEnv, SBlockInfo * pQuery->lastKey = pPrimaryColumn[pQuery->pos + (newForwardStep - 1) * step] + step; } - if (pQuery->numOfFilterCols > 0 || pRuntimeEnv->pTSBuf != NULL || isGroupbyNormalCol(pQuery->pGroupbyExpr) || - (pQuery->slidingTime != -1 && pQuery->nAggTimeInterval > 0)) { - *numOfRes = rowwiseApplyAllFunctions(pRuntimeEnv, &newForwardStep, pPrimaryColumn, pFields, pBlockInfo); + if (pQuery->numOfFilterCols > 0 || pRuntimeEnv->pTSBuf != NULL || isGroupbyNormalCol(pQuery->pGroupbyExpr)) { + *numOfRes = rowwiseApplyAllFunctions(pRuntimeEnv, &newForwardStep, pFields, pBlockInfo, pWindowResInfo); } else { - *numOfRes = blockwiseApplyAllFunctions(pRuntimeEnv, newForwardStep, pPrimaryColumn, pFields, pBlockInfo); + *numOfRes = blockwiseApplyAllFunctions(pRuntimeEnv, newForwardStep, pFields, pBlockInfo, pWindowResInfo, searchFn); + } + + TSKEY lastKey = (QUERY_IS_ASC_QUERY(pQuery)) ? pBlockInfo->keyLast : pBlockInfo->keyFirst; + doCheckQueryCompleted(pRuntimeEnv, lastKey, pWindowResInfo); // todo refactor merge + + // interval query with limit applied + if (isIntervalQuery(pQuery) && pQuery->limit.limit > 0 && + (pQuery->limit.limit + pQuery->limit.offset) <= numOfClosedTimeWindow(pWindowResInfo) && + pRuntimeEnv->scanFlag == MASTER_SCAN) { + setQueryStatus(pQuery, QUERY_COMPLETED); } assert(*numOfRes >= 0); @@ -2304,7 +2539,7 @@ static int32_t applyFunctionsOnBlock(SQueryRuntimeEnv *pRuntimeEnv, SBlockInfo * return newForwardStep; } -int32_t vnodeGetVnodeHeaderFileIdx(int32_t *fid, SQueryRuntimeEnv *pRuntimeEnv, int32_t order) { +int32_t vnodeGetVnodeHeaderFileIndex(int32_t *fid, SQueryRuntimeEnv *pRuntimeEnv, int32_t order) { if (pRuntimeEnv->vnodeFileInfo.numOfFiles == 0) { return -1; } @@ -2365,7 +2600,7 @@ int32_t getNextDataFileCompInfo(SQueryRuntimeEnv *pRuntimeEnv, SMeterObj *pMeter int32_t fileIndex = 0; int32_t order = (step == QUERY_ASC_FORWARD_STEP) ? TSQL_SO_ASC : TSQL_SO_DESC; while (1) { - fileIndex = vnodeGetVnodeHeaderFileIdx(&pQuery->fileId, pRuntimeEnv, order); + fileIndex = vnodeGetVnodeHeaderFileIndex(&pQuery->fileId, pRuntimeEnv, order); // no files left, abort if (fileIndex < 0) { @@ -2438,9 +2673,8 @@ void setExecParams(SQuery *pQuery, SQLFunctionCtx *pCtx, int64_t startQueryTimes // store the first&last timestamp into the intermediate buffer [1], the true // value may be null but timestamp will never be null pCtx->ptsList = (int64_t *)(primaryColumnData + startOffset * TSDB_KEYSIZE); - } else if (functionId == TSDB_FUNC_TOP || functionId == TSDB_FUNC_BOTTOM || - functionId == TSDB_FUNC_TWA || functionId == TSDB_FUNC_DIFF || - (functionId >= TSDB_FUNC_RATE && functionId <= TSDB_FUNC_AVG_IRATE)) { + } else if (functionId == TSDB_FUNC_TOP || functionId == TSDB_FUNC_BOTTOM || functionId == TSDB_FUNC_TWA || + functionId == TSDB_FUNC_DIFF || (functionId >= TSDB_FUNC_RATE && functionId <= TSDB_FUNC_AVG_IRATE)) { /* * leastsquares function needs two columns of input, currently, the x value of linear equation is set to * timestamp column, and the y-value is the column specified in pQuery->pSelectExpr[i].colIdxInBuffer @@ -2484,8 +2718,8 @@ static void setCtxTagColumnInfo(SQuery *pQuery, SQLFunctionCtx *pCtx) { if (isSelectivityWithTagsQuery(pQuery)) { int32_t num = 0; SQLFunctionCtx *p = NULL; - - int16_t tagLen = 0; + + int16_t tagLen = 0; SQLFunctionCtx **pTagCtx = calloc(pQuery->numOfOutputCols, POINTER_BYTES); for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { @@ -2510,6 +2744,12 @@ static void setCtxTagColumnInfo(SQuery *pQuery, SQLFunctionCtx *pCtx) { } } +static void setWindowResultInfo(SResultInfo *pResultInfo, SQuery *pQuery, bool isStableQuery) { + for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { + setResultInfoBuf(&pResultInfo[i], pQuery->pSelectExpr[i].interResBytes, isStableQuery); + } +} + static int32_t setupQueryRuntimeEnv(SMeterObj *pMeterObj, SQuery *pQuery, SQueryRuntimeEnv *pRuntimeEnv, SColumnModel *pTagsSchema, int16_t order, bool isSTableQuery) { dTrace("QInfo:%p setup runtime env", GET_QINFO_ADDR(pQuery)); @@ -2532,8 +2772,8 @@ static int32_t setupQueryRuntimeEnv(SMeterObj *pMeterObj, SQuery *pQuery, SQuery SQLFunctionCtx *pCtx = &pRuntimeEnv->pCtx[i]; if (TSDB_COL_IS_TAG(pSqlFuncMsg->colInfo.flag)) { // process tag column info - SSchema* pSchema = getColumnModelSchema(pTagsSchema, pColIndexEx->colIdx); - + SSchema *pSchema = getColumnModelSchema(pTagsSchema, pColIndexEx->colIdx); + pCtx->inputType = pSchema->type; pCtx->inputBytes = pSchema->bytes; } else { @@ -2578,12 +2818,11 @@ static int32_t setupQueryRuntimeEnv(SMeterObj *pMeterObj, SQuery *pQuery, SQuery if (i > 0) { pRuntimeEnv->offset[i] = pRuntimeEnv->offset[i - 1] + pRuntimeEnv->pCtx[i - 1].outputBytes; } - - // set the intermediate result output buffer - SResultInfo *pResInfo = &pRuntimeEnv->resultInfo[i]; - setResultInfoBuf(pResInfo, pQuery->pSelectExpr[i].interResBytes, isSTableQuery); } + // set the intermediate result output buffer + setWindowResultInfo(pRuntimeEnv->resultInfo, pQuery, isSTableQuery); + // if it is group by normal column, do not set output buffer, the output buffer is pResult if (!isGroupbyNormalCol(pQuery->pGroupbyExpr) && !isSTableQuery) { resetCtxOutputBuf(pRuntimeEnv); @@ -2613,7 +2852,7 @@ static void teardownQueryRuntimeEnv(SQueryRuntimeEnv *pRuntimeEnv) { } tfree(pRuntimeEnv->secondaryUnzipBuffer); - destroySlidingWindowInfo(&pRuntimeEnv->swindowResInfo); + cleanupTimeWindowInfo(&pRuntimeEnv->windowResInfo, pRuntimeEnv); if (pRuntimeEnv->pCtx != NULL) { for (int32_t i = 0; i < pRuntimeEnv->pQuery->numOfOutputCols; ++i) { @@ -2665,7 +2904,6 @@ static int64_t getOldestKey(int32_t numOfFiles, int64_t fileId, SVnodeCfg *pCfg) } bool isQueryKilled(SQuery *pQuery) { - return false; SQInfo *pQInfo = (SQInfo *)GET_QINFO_ADDR(pQuery); /* @@ -2682,7 +2920,7 @@ bool isQueryKilled(SQuery *pQuery) { } bool isFixedOutputQuery(SQuery *pQuery) { - if (pQuery->nAggTimeInterval != 0) { + if (pQuery->intervalTime != 0) { return false; } @@ -2731,8 +2969,8 @@ bool isSumAvgRateQuery(SQuery *pQuery) { continue; } - if (functionId == TSDB_FUNC_SUM_RATE || functionId == TSDB_FUNC_SUM_IRATE || - functionId == TSDB_FUNC_AVG_RATE || functionId == TSDB_FUNC_AVG_IRATE) { + if (functionId == TSDB_FUNC_SUM_RATE || functionId == TSDB_FUNC_SUM_IRATE || functionId == TSDB_FUNC_AVG_RATE || + functionId == TSDB_FUNC_AVG_IRATE) { return true; } } @@ -3060,17 +3298,17 @@ void vnodeCheckIfDataExists(SQueryRuntimeEnv *pRuntimeEnv, SMeterObj *pMeterObj, setQueryStatus(pQuery, QUERY_NOT_COMPLETED); } -static void doGetAlignedIntervalQueryRangeImpl(SQuery *pQuery, int64_t pKey, int64_t keyFirst, int64_t keyLast, - int64_t *actualSkey, int64_t *actualEkey, int64_t *skey, int64_t *ekey) { +void doGetAlignedIntervalQueryRangeImpl(SQuery *pQuery, int64_t pKey, int64_t keyFirst, int64_t keyLast, + int64_t *actualSkey, int64_t *actualEkey, int64_t *skey, int64_t *ekey) { assert(pKey >= keyFirst && pKey <= keyLast); - *skey = taosGetIntervalStartTimestamp(pKey, pQuery->nAggTimeInterval, pQuery->intervalTimeUnit, pQuery->precision); + *skey = taosGetIntervalStartTimestamp(pKey, pQuery->intervalTime, pQuery->intervalTimeUnit, pQuery->precision); - if (keyFirst > (INT64_MAX - pQuery->nAggTimeInterval)) { + if (keyFirst > (INT64_MAX - pQuery->intervalTime)) { /* - * if the actualSkey > INT64_MAX - pQuery->nAggTimeInterval, the query duration between + * if the actualSkey > INT64_MAX - pQuery->intervalTime, the query duration between * actualSkey and actualEkey must be less than one interval.Therefore, no need to adjust the query ranges. */ - assert(keyLast - keyFirst < pQuery->nAggTimeInterval); + assert(keyLast - keyFirst < pQuery->intervalTime); *actualSkey = keyFirst; *actualEkey = keyLast; @@ -3079,7 +3317,7 @@ static void doGetAlignedIntervalQueryRangeImpl(SQuery *pQuery, int64_t pKey, int return; } - *ekey = *skey + pQuery->nAggTimeInterval - 1; + *ekey = *skey + pQuery->intervalTime - 1; if (*skey < keyFirst) { *actualSkey = keyFirst; @@ -3094,42 +3332,6 @@ static void doGetAlignedIntervalQueryRangeImpl(SQuery *pQuery, int64_t pKey, int } } -static void getAlignedIntervalQueryRange(SQueryRuntimeEnv *pRuntimeEnv, TSKEY key, TSKEY skey, TSKEY ekey) { - SQuery *pQuery = pRuntimeEnv->pQuery; - if (pQuery->nAggTimeInterval == 0 || (pQuery->nAggTimeInterval > 0 && pQuery->slidingTime > 0)) { - return; - } - - TSKEY skey2 = MIN(skey, ekey); - TSKEY ekey2 = MAX(skey, ekey); - - // the actual first query range in skey1 and ekey1 - TSKEY skey1, ekey1; - - TSKEY windowSKey = 0, windowEKey = 0; - doGetAlignedIntervalQueryRangeImpl(pQuery, key, skey2, ekey2, &skey1, &ekey1, &windowSKey, &windowEKey); - - if (QUERY_IS_ASC_QUERY(pQuery)) { - pQuery->skey = skey1; - pQuery->ekey = ekey1; - - pRuntimeEnv->intervalWindow = (STimeWindow) {.skey = windowSKey, .ekey = windowEKey}; - - assert(pQuery->skey <= pQuery->ekey && - pRuntimeEnv->intervalWindow.skey + (pQuery->nAggTimeInterval - 1) == pRuntimeEnv->intervalWindow.ekey); - } else { - pQuery->skey = ekey1; - pQuery->ekey = skey1; - - pRuntimeEnv->intervalWindow = (STimeWindow) {.skey = windowEKey, .ekey = windowSKey}; - - assert(pQuery->skey >= pQuery->ekey && - pRuntimeEnv->intervalWindow.skey - (pQuery->nAggTimeInterval - 1) == pRuntimeEnv->intervalWindow.ekey); - } - - pQuery->lastKey = pQuery->skey; -} - static void getOneRowFromDataBlock(SQueryRuntimeEnv *pRuntimeEnv, char **dst, int32_t pos) { SQuery *pQuery = pRuntimeEnv->pQuery; @@ -3139,7 +3341,7 @@ static void getOneRowFromDataBlock(SQueryRuntimeEnv *pRuntimeEnv, char **dst, in } } -static bool getNeighborPoints(SMeterQuerySupportObj *pSupporter, SMeterObj *pMeterObj, +static bool getNeighborPoints(STableQuerySupportObj *pSupporter, SMeterObj *pMeterObj, SPointInterpoSupporter *pPointInterpSupporter) { SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; SQuery * pQuery = pRuntimeEnv->pQuery; @@ -3244,7 +3446,7 @@ static bool getNeighborPoints(SMeterQuerySupportObj *pSupporter, SMeterObj *pMet return true; } -static bool doGetQueryPos(TSKEY key, SMeterQuerySupportObj *pSupporter, SPointInterpoSupporter *pPointInterpSupporter) { +static bool doGetQueryPos(TSKEY key, STableQuerySupportObj *pSupporter, SPointInterpoSupporter *pPointInterpSupporter) { SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; SQuery * pQuery = pRuntimeEnv->pQuery; SMeterObj * pMeterObj = pRuntimeEnv->pMeterObj; @@ -3254,7 +3456,6 @@ static bool doGetQueryPos(TSKEY key, SMeterQuerySupportObj *pSupporter, SPointIn if (isPointInterpoQuery(pQuery)) { /* no qualified data in this query range */ return getNeighborPoints(pSupporter, pMeterObj, pPointInterpSupporter); } else { - getAlignedIntervalQueryRange(pRuntimeEnv, key, pQuery->skey, pQuery->ekey); return true; } } else { // key > pQuery->ekey, abort for normal query, continue for interp query @@ -3266,7 +3467,7 @@ static bool doGetQueryPos(TSKEY key, SMeterQuerySupportObj *pSupporter, SPointIn } } -static bool doSetDataInfo(SMeterQuerySupportObj *pSupporter, SPointInterpoSupporter *pPointInterpSupporter, +static bool doSetDataInfo(STableQuerySupportObj *pSupporter, SPointInterpoSupporter *pPointInterpSupporter, SMeterObj *pMeterObj, TSKEY nextKey) { SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; SQuery * pQuery = pRuntimeEnv->pQuery; @@ -3286,13 +3487,12 @@ static bool doSetDataInfo(SMeterQuerySupportObj *pSupporter, SPointInterpoSuppor return getNeighborPoints(pSupporter, pMeterObj, pPointInterpSupporter); } else { - getAlignedIntervalQueryRange(pRuntimeEnv, nextKey, pQuery->skey, pQuery->ekey); return true; } } // TODO refactor code, the best way to implement the last_row is utilizing the iterator -bool normalizeUnBoundLastRowQuery(SMeterQuerySupportObj *pSupporter, SPointInterpoSupporter *pPointInterpSupporter) { +bool normalizeUnBoundLastRowQuery(STableQuerySupportObj *pSupporter, SPointInterpoSupporter *pPointInterpSupporter) { SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; SQuery * pQuery = pRuntimeEnv->pQuery; @@ -3354,12 +3554,49 @@ bool normalizeUnBoundLastRowQuery(SMeterQuerySupportObj *pSupporter, SPointInter return getNeighborPoints(pSupporter, pMeterObj, pPointInterpSupporter); } +static int64_t getGreaterEqualTimestamp(SQueryRuntimeEnv *pRuntimeEnv) { + SQuery * pQuery = pRuntimeEnv->pQuery; + SMeterObj * pMeterObj = pRuntimeEnv->pMeterObj; + __block_search_fn_t searchFn = vnodeSearchKeyFunc[pMeterObj->searchAlgorithm]; + + if (QUERY_IS_ASC_QUERY(pQuery)) { + return -1; + } + + TSKEY key = -1; + + SPositionInfo p = {0}; + { // todo refactor save the context + savePointPosition(&p, pQuery->fileId, pQuery->slot, pQuery->pos); + } + + SWAP(pQuery->skey, pQuery->ekey, TSKEY); + pQuery->lastKey = pQuery->skey; + pQuery->order.order ^= 1u; + + if (getQualifiedDataBlock(pMeterObj, pRuntimeEnv, QUERY_RANGE_GREATER_EQUAL, searchFn)) { + key = getTimestampInDiskBlock(pRuntimeEnv, pQuery->pos); + } else { // set no data in file + key = getQueryStartPositionInCache(pRuntimeEnv, &pQuery->slot, &pQuery->pos, false); + } + + SWAP(pQuery->skey, pQuery->ekey, TSKEY); + pQuery->order.order ^= 1u; + pQuery->lastKey = pQuery->skey; + + pQuery->fileId = p.fileId; + pQuery->pos = p.pos; + pQuery->slot = p.slot; + + return key; +} + /** * determine the first query range, according to raw query range [skey, ekey] and group-by interval. * the time interval for aggregating is not enforced to check its validation, the minimum interval is not less than * 10ms, which is guaranteed by parser at client-side */ -bool normalizedFirstQueryRange(bool dataInDisk, bool dataInCache, SMeterQuerySupportObj *pSupporter, +bool normalizedFirstQueryRange(bool dataInDisk, bool dataInCache, STableQuerySupportObj *pSupporter, SPointInterpoSupporter *pPointInterpSupporter, int64_t *key) { SQueryRuntimeEnv * pRuntimeEnv = &pSupporter->runtimeEnv; SQuery * pQuery = pRuntimeEnv->pQuery; @@ -3473,7 +3710,7 @@ int64_t loadRequiredBlockIntoMem(SQueryRuntimeEnv *pRuntimeEnv, SPositionInfo *p * load the file metadata into buffer first, then the specific data block. * currently opened file is not the start file, reset to the start file */ - int32_t fileIdx = vnodeGetVnodeHeaderFileIdx(&pQuery->fileId, pRuntimeEnv, pQuery->order.order); + int32_t fileIdx = vnodeGetVnodeHeaderFileIndex(&pQuery->fileId, pRuntimeEnv, pQuery->order.order); if (fileIdx < 0) { // ignore the files on disk dError("QInfo:%p failed to get data file:%d", GET_QINFO_ADDR(pQuery), pQuery->fileId); position->fileId = -1; @@ -3565,7 +3802,7 @@ static void vnodeRecordAllFiles(SQInfo *pQInfo, int32_t vnodeId) { struct dirent *pEntry = NULL; size_t alloc = 4; // default allocated size - SQueryFilesInfo *pVnodeFilesInfo = &(pQInfo->pMeterQuerySupporter->runtimeEnv.vnodeFileInfo); + SQueryFilesInfo *pVnodeFilesInfo = &(pQInfo->pTableQuerySupporter->runtimeEnv.vnodeFileInfo); pVnodeFilesInfo->vnodeId = vnodeId; sprintf(pVnodeFilesInfo->dbFilePathPrefix, "%s/vnode%d/db/", tsDirectory, vnodeId); @@ -3721,9 +3958,9 @@ static void changeExecuteScanOrder(SQuery *pQuery, bool metricQuery) { // in case of point-interpolation query, use asc order scan char msg[] = "QInfo:%p scan order changed for %s query, old:%d, new:%d, qrange exchanged, old qrange:%" PRId64 "-%" PRId64 - ", " - "new qrange:%" PRId64 "-%" PRId64; + ", new qrange:%" PRId64 "-%" PRId64; + // todo handle the case the the order irrelevant query type mixed up with order critical query type // descending order query for last_row query if (isFirstLastRowQuery(pQuery)) { dTrace("QInfo:%p scan order changed for last_row query, old:%d, new:%d", GET_QINFO_ADDR(pQuery), @@ -3740,7 +3977,7 @@ static void changeExecuteScanOrder(SQuery *pQuery, bool metricQuery) { return; } - if (isPointInterpoQuery(pQuery) && pQuery->nAggTimeInterval == 0) { + if (isPointInterpoQuery(pQuery) && pQuery->intervalTime == 0) { if (!QUERY_IS_ASC_QUERY(pQuery)) { dTrace(msg, GET_QINFO_ADDR(pQuery), "interp", pQuery->order.order, TSQL_SO_ASC, pQuery->skey, pQuery->ekey, pQuery->ekey, pQuery->skey); @@ -3751,7 +3988,7 @@ static void changeExecuteScanOrder(SQuery *pQuery, bool metricQuery) { return; } - if (pQuery->nAggTimeInterval == 0) { + if (pQuery->intervalTime == 0) { if (onlyFirstQuery(pQuery)) { if (!QUERY_IS_ASC_QUERY(pQuery)) { dTrace(msg, GET_QINFO_ADDR(pQuery), "only-first", pQuery->order.order, TSQL_SO_ASC, pQuery->skey, pQuery->ekey, @@ -3812,8 +4049,7 @@ static int32_t doSkipDataBlock(SQueryRuntimeEnv *pRuntimeEnv) { void *pBlock = getGenericDataBlock(pMeterObj, pRuntimeEnv, pQuery->slot); assert(pBlock != NULL); - int32_t blockType = IS_DISK_DATA_BLOCK(pQuery) ? BLK_FILE_BLOCK : BLK_CACHE_BLOCK; - SBlockInfo blockInfo = getBlockBasicInfo(pRuntimeEnv, pBlock, blockType); + SBlockInfo blockInfo = getBlockInfo(pRuntimeEnv); int32_t maxReads = (QUERY_IS_ASC_QUERY(pQuery)) ? blockInfo.size - pQuery->pos : pQuery->pos + 1; assert(maxReads >= 0); @@ -3843,9 +4079,9 @@ void forwardQueryStartPosition(SQueryRuntimeEnv *pRuntimeEnv) { } void *pBlock = getGenericDataBlock(pMeterObj, pRuntimeEnv, pQuery->slot); + assert(pBlock != NULL); - int32_t blockType = (IS_DISK_DATA_BLOCK(pQuery)) ? BLK_FILE_BLOCK : BLK_CACHE_BLOCK; - SBlockInfo blockInfo = getBlockBasicInfo(pRuntimeEnv, pBlock, blockType); + SBlockInfo blockInfo = getBlockInfo(pRuntimeEnv); // get the qualified data that can be skipped int32_t maxReads = (QUERY_IS_ASC_QUERY(pQuery)) ? blockInfo.size - pQuery->pos : pQuery->pos + 1; @@ -3855,71 +4091,186 @@ void forwardQueryStartPosition(SQueryRuntimeEnv *pRuntimeEnv) { updateOffsetVal(pRuntimeEnv, &blockInfo, pBlock); } else { pQuery->limit.offset -= maxReads; + // update the lastkey, since the following skip operation may traverse to another media. update the lastkey first. pQuery->lastKey = (QUERY_IS_ASC_QUERY(pQuery)) ? blockInfo.keyLast + 1 : blockInfo.keyFirst - 1; doSkipDataBlock(pRuntimeEnv); } } -static bool forwardQueryStartPosIfNeeded(SQInfo *pQInfo, SMeterQuerySupportObj *pSupporter, bool dataInDisk, +static bool forwardQueryStartPosIfNeeded(SQInfo *pQInfo, STableQuerySupportObj *pSupporter, bool dataInDisk, bool dataInCache) { - SQuery *pQuery = &pQInfo->query; + SQuery * pQuery = &pQInfo->query; + SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; /* if queried with value filter, do NOT forward query start position */ - if (pQuery->numOfFilterCols > 0 || pSupporter->runtimeEnv.pTSBuf != NULL) { + if (pQuery->numOfFilterCols > 0 || pRuntimeEnv->pTSBuf != NULL) { return true; } if (pQuery->limit.offset > 0 && (!isTopBottomQuery(pQuery)) && pQuery->interpoType == TSDB_INTERPO_NONE) { /* * 1. for top/bottom query, the offset applies to the final result, not here - * 2. for interval without interpolation query we forward pQuery->nAggTimeInterval at a time for - * pQuery->limit.offset times. Since hole exists, pQuery->nAggTimeInterval*pQuery->limit.offset value is + * 2. for interval without interpolation query we forward pQuery->intervalTime at a time for + * pQuery->limit.offset times. Since hole exists, pQuery->intervalTime*pQuery->limit.offset value is * not valid. otherwise, we only forward pQuery->limit.offset number of points */ - if (pQuery->nAggTimeInterval > 0) { - while (1) { - /* - * the skey may not be the aligned start time - * 1. it is the value of first existed data point, therefore, the range - * between skey and ekey may be less than the interval value. - * 2. the ekey may not be the actual end value of time interval, in case of the - */ - if (QUERY_IS_ASC_QUERY(pQuery)) { - pQuery->skey = pQuery->ekey + 1; - } else { - pQuery->skey = pQuery->ekey - 1; - } + if (isIntervalQuery(pQuery)) { + int16_t step = GET_FORWARD_DIRECTION_FACTOR(pQuery->order.order); + __block_search_fn_t searchFn = vnodeSearchKeyFunc[pRuntimeEnv->pMeterObj->searchAlgorithm]; + SWindowResInfo * pWindowResInfo = &pRuntimeEnv->windowResInfo; - // boundary check - if ((pQuery->skey > pSupporter->rawEKey && QUERY_IS_ASC_QUERY(pQuery)) || - (pQuery->skey < pSupporter->rawEKey && !QUERY_IS_ASC_QUERY(pQuery))) { - setQueryStatus(pQuery, QUERY_COMPLETED); + TSKEY * primaryKey = (TSKEY *)pRuntimeEnv->primaryColBuffer->data; + STimeWindow win = getActiveTimeWindow(pWindowResInfo, pWindowResInfo->prevSKey, pQuery); - sem_post(&pQInfo->dataReady); - pQInfo->over = 1; - return false; - } + while (pQuery->limit.offset > 0) { + SBlockInfo blockInfo = getBlockInfo(pRuntimeEnv); + + STimeWindow tw = win; + getNextTimeWindow(pQuery, &tw); + + // next time window starts from current data block + if ((tw.skey <= blockInfo.keyLast && QUERY_IS_ASC_QUERY(pQuery)) || + (tw.ekey >= blockInfo.keyFirst && !QUERY_IS_ASC_QUERY(pQuery))) { + + // query completed + if ((tw.skey > pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) || + (tw.ekey < pQuery->ekey && !QUERY_IS_ASC_QUERY(pQuery))) { + setQueryStatus(pQuery, QUERY_COMPLETED); + break; + } - /* - * NOTE: the end key must be set the last value, to cover all possible - * data. Otherwise, it may contain no data with only one interval time range - */ - pQuery->ekey = pSupporter->rawEKey; - pQuery->lastKey = pQuery->skey; - - // todo opt performance - if (normalizedFirstQueryRange(dataInDisk, dataInCache, pSupporter, NULL, NULL) == false) { - sem_post(&pQInfo->dataReady); // hack for next read for empty return - pQInfo->over = 1; - return false; + // check its position in this block to make sure this time window covers data. + if (IS_DISK_DATA_BLOCK(pQuery)) { + getTimestampInDiskBlock(pRuntimeEnv, 0); + } + + tw = win; + int32_t startPos = getNextQualifiedWindow(pRuntimeEnv, &tw, pWindowResInfo, &blockInfo, primaryKey, searchFn); + assert(startPos >= 0); + + pQuery->limit.offset -= 1; + + // set the abort info + pQuery->pos = startPos; + pQuery->lastKey = primaryKey[startPos]; + pWindowResInfo->prevSKey = tw.skey; + win = tw; + continue; + } else { + moveToNextBlock(pRuntimeEnv, step, searchFn, false); + if (Q_STATUS_EQUAL(pQuery->over, QUERY_NO_DATA_TO_CHECK)) { + break; + } + + blockInfo = getBlockInfo(pRuntimeEnv); + if ((blockInfo.keyFirst > pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) || + (blockInfo.keyLast < pQuery->ekey && !QUERY_IS_ASC_QUERY(pQuery))) { + setQueryStatus(pQuery, QUERY_COMPLETED); + break; + } + + // set the window that start from the next data block + TSKEY key = (QUERY_IS_ASC_QUERY(pQuery))? blockInfo.keyFirst:blockInfo.keyLast; + STimeWindow n = getActiveTimeWindow(pWindowResInfo, key, pQuery); + + // next data block are still covered by current time window + if (n.skey == win.skey && n.ekey == win.ekey) { + // do nothing + } else { + pQuery->limit.offset -= 1; + + // query completed + if ((n.skey > pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) || + (n.ekey < pQuery->ekey && !QUERY_IS_ASC_QUERY(pQuery))) { + setQueryStatus(pQuery, QUERY_COMPLETED); + break; + } + + // set the abort info + pQuery->pos = QUERY_IS_ASC_QUERY(pQuery)? 0:blockInfo.size-1; + pQuery->lastKey = QUERY_IS_ASC_QUERY(pQuery)? blockInfo.keyFirst:blockInfo.keyLast; + pWindowResInfo->prevSKey = n.skey; + + win = n; + + if (pQuery->limit.offset == 0 && IS_DISK_DATA_BLOCK(pQuery)) { + getTimestampInDiskBlock(pRuntimeEnv, 0); + } + } } + +// if (win.ekey <= blockInfo.keyLast) { +// pQuery->limit.offset -= 1; +// +// if (win.ekey == blockInfo.keyLast) { +// moveToNextBlock(pRuntimeEnv, step, searchFn, false); +// if (Q_STATUS_EQUAL(pQuery->over, QUERY_NO_DATA_TO_CHECK)) { +// break; +// } +// +// // next block does not included in time range, abort query +// blockInfo = getBlockInfo(pRuntimeEnv); +// if ((blockInfo.keyFirst > pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) || +// (blockInfo.keyLast < pQuery->ekey && !QUERY_IS_ASC_QUERY(pQuery))) { +// setQueryStatus(pQuery, QUERY_COMPLETED); +// break; +// } +// +// // set the window that start from the next data block +// win = getActiveTimeWindow(pWindowResInfo, blockInfo.keyFirst, pQuery); +// } else { +// // the time window is closed in current data block, load disk file block into memory to +// // check the next time window +// if (IS_DISK_DATA_BLOCK(pQuery)) { +// getTimestampInDiskBlock(pRuntimeEnv, 0); +// } +// +// STimeWindow nextWin = win; +// int32_t startPos = +// getNextQualifiedWindow(pRuntimeEnv, &nextWin, pWindowResInfo, &blockInfo, primaryKey, searchFn); +// +// if (startPos < 0) { // failed to find the qualified time window +// assert((nextWin.skey > pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) || +// (nextWin.ekey < pQuery->ekey && !QUERY_IS_ASC_QUERY(pQuery))); +// +// setQueryStatus(pQuery, QUERY_COMPLETED); +// break; +// } else { // set the abort info +// pQuery->pos = startPos; +// pQuery->lastKey = primaryKey[startPos]; +// win = nextWin; +// } +// } +// +// continue; +// } +// +// moveToNextBlock(pRuntimeEnv, step, searchFn, false); +// if (Q_STATUS_EQUAL(pQuery->over, QUERY_NO_DATA_TO_CHECK)) { +// break; +// } +// +// blockInfo = getBlockInfo(pRuntimeEnv); +// if ((blockInfo.keyFirst > pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) || +// (blockInfo.keyLast < pQuery->ekey && !QUERY_IS_ASC_QUERY(pQuery))) { +// setQueryStatus(pQuery, QUERY_COMPLETED); +// break; +// } + } - if (--pQuery->limit.offset == 0) { - break; + if (Q_STATUS_EQUAL(pQuery->over, QUERY_NO_DATA_TO_CHECK | QUERY_COMPLETED) || pQuery->limit.offset > 0) { + setQueryStatus(pQuery, QUERY_COMPLETED); + + sem_post(&pQInfo->dataReady); // hack for next read for empty return; + pQInfo->over = 1; + return false; + } else { + if (IS_DISK_DATA_BLOCK(pQuery)) { + getTimestampInDiskBlock(pRuntimeEnv, 0); } } - } else { + } else { // forward the start position for projection query forwardQueryStartPosition(&pSupporter->runtimeEnv); if (Q_STATUS_EQUAL(pQuery->over, QUERY_NO_DATA_TO_CHECK)) { setQueryStatus(pQuery, QUERY_COMPLETED); @@ -4005,7 +4356,7 @@ void pointInterpSupporterSetData(SQInfo *pQInfo, SPointInterpoSupporter *pPointI } SQuery * pQuery = &pQInfo->query; - SMeterQuerySupportObj *pSupporter = pQInfo->pMeterQuerySupporter; + STableQuerySupportObj *pSupporter = pQInfo->pTableQuerySupporter; SQueryRuntimeEnv * pRuntimeEnv = &pSupporter->runtimeEnv; int32_t count = 1; @@ -4136,71 +4487,37 @@ void pointInterpSupporterDestroy(SPointInterpoSupporter *pPointInterpSupport) { pPointInterpSupport->numOfCols = 0; } -static void allocMemForInterpo(SMeterQuerySupportObj *pSupporter, SQuery *pQuery, SMeterObj *pMeterObj) { - if (pQuery->interpoType != TSDB_INTERPO_NONE) { - assert(pQuery->nAggTimeInterval > 0 || (pQuery->nAggTimeInterval == 0 && isPointInterpoQuery(pQuery))); - - if (pQuery->nAggTimeInterval > 0) { - pSupporter->runtimeEnv.pInterpoBuf = malloc(POINTER_BYTES * pQuery->numOfOutputCols); - - for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { - pSupporter->runtimeEnv.pInterpoBuf[i] = - calloc(1, sizeof(tFilePage) + pQuery->pSelectExpr[i].resBytes * pMeterObj->pointsPerFileBlock); - } - } - } -} - -static int32_t createQueryOutputBuffer(SMeterQuerySupportObj *pSupporter, SQuery *pQuery, bool isSTableQuery) { - SQueryRuntimeEnv* pRuntimeEnv = &pSupporter->runtimeEnv; - - int32_t numOfRows = 0; - - if (isGroupbyNormalCol(pQuery->pGroupbyExpr) || (pQuery->nAggTimeInterval > 0 && pQuery->slidingTime > 0)) { - numOfRows = 10000; - } else { - numOfRows = pSupporter->pSidSet->numOfSubSet; - } - - createResultBuf(&pRuntimeEnv->pResultBuf, 100, pQuery->rowSize); - - // total number of initial results - pSupporter->pResult = calloc(numOfRows, sizeof(SOutputRes)); - if (pSupporter->pResult == NULL) { - return TSDB_CODE_SERV_OUT_OF_MEMORY; - } - - int32_t pageId = -1; - tFilePage* page = NULL; - - for (int32_t k = 0; k < numOfRows; ++k) { - SOutputRes *pOneRes = &pSupporter->pResult[k]; - pOneRes->nAlloc = 1; +static void allocMemForInterpo(STableQuerySupportObj *pSupporter, SQuery *pQuery, SMeterObj *pMeterObj) { + if (pQuery->interpoType != TSDB_INTERPO_NONE) { + assert(isIntervalQuery(pQuery) || (pQuery->intervalTime == 0 && isPointInterpoQuery(pQuery))); - /* - * for single table top/bottom query, the output for group by normal column, the output rows is - * equals to the maximum rows, instead of 1. - */ - if (!isSTableQuery && isTopBottomQuery(pQuery)) { - assert(pQuery->numOfOutputCols > 1); + if (isIntervalQuery(pQuery)) { + pSupporter->runtimeEnv.pInterpoBuf = malloc(POINTER_BYTES * pQuery->numOfOutputCols); - SSqlFunctionExpr *pExpr = &pQuery->pSelectExpr[1]; - pOneRes->nAlloc = pExpr->pBase.arg[0].argValue.i64; + for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { + pSupporter->runtimeEnv.pInterpoBuf[i] = + calloc(1, sizeof(tFilePage) + pQuery->pSelectExpr[i].resBytes * pMeterObj->pointsPerFileBlock); + } } + } +} - if (page == NULL || page->numOfElems >= pRuntimeEnv->numOfRowsPerPage) { - page = getNewDataBuf(pRuntimeEnv->pResultBuf, 0, &pageId); - } - - assert(pageId >= 0); - - SPosInfo posInfo = {.pageId = pageId, .rowId = page->numOfElems}; - - createQueryResultBuf(pRuntimeEnv, pOneRes, isSTableQuery, &posInfo); - page->numOfElems += 1; // next row is available +static int32_t getInitialPageNum(STableQuerySupportObj *pSupporter) { + SQuery *pQuery = pSupporter->runtimeEnv.pQuery; + + int32_t num = 0; + + if (isGroupbyNormalCol(pQuery->pGroupbyExpr)) { + num = 128; + } else if (isIntervalQuery(pQuery)) { // time window query, allocate one page for each table + num = pSupporter->numOfMeters; + } else { // for super table query, one page for each subset + num = pSupporter->pSidSet->numOfSubSet; } - return TSDB_CODE_SUCCESS; + assert(num > 0); + + return num; } static int32_t allocateRuntimeEnvBuf(SQueryRuntimeEnv *pRuntimeEnv, SMeterObj *pMeterObj) { @@ -4259,34 +4576,35 @@ _error_clean: return TSDB_CODE_SERV_OUT_OF_MEMORY; } -static int32_t getRowParamForMultiRowsOutput(SQuery* pQuery, bool isSTableQuery) { +static int32_t getRowParamForMultiRowsOutput(SQuery *pQuery, bool isSTableQuery) { int32_t rowparam = 1; - + if (isTopBottomQuery(pQuery) && (!isSTableQuery)) { rowparam = pQuery->pSelectExpr[1].pBase.arg->argValue.i64; } - + return rowparam; } -static int32_t getNumOfRowsInResultPage(SQuery* pQuery, bool isSTableQuery) { +static int32_t getNumOfRowsInResultPage(SQuery *pQuery, bool isSTableQuery) { int32_t rowSize = pQuery->rowSize * getRowParamForMultiRowsOutput(pQuery, isSTableQuery); return (DEFAULT_INTERN_BUF_SIZE - sizeof(tFilePage)) / rowSize; } -static char* getPosInResultPage(SQueryRuntimeEnv* pRuntimeEnv, int32_t columnIndex, SOutputRes* pResult) { - SQuery* pQuery = pRuntimeEnv->pQuery; - tFilePage* page = getResultBufferPageById(pRuntimeEnv->pResultBuf, pResult->pos.pageId); - +static char *getPosInResultPage(SQueryRuntimeEnv *pRuntimeEnv, int32_t columnIndex, SWindowResult *pResult) { + assert(pResult != NULL && pRuntimeEnv != NULL); + + SQuery * pQuery = pRuntimeEnv->pQuery; + tFilePage *page = getResultBufferPageById(pRuntimeEnv->pResultBuf, pResult->pos.pageId); + int32_t numOfRows = getNumOfRowsInResultPage(pQuery, pRuntimeEnv->stableQuery); int32_t realRowId = pResult->pos.rowId * getRowParamForMultiRowsOutput(pQuery, pRuntimeEnv->stableQuery); - - return ((char*)page->data) + pRuntimeEnv->offset[columnIndex] * numOfRows + - pQuery->pSelectExpr[columnIndex].resBytes * realRowId; + + return ((char *)page->data) + pRuntimeEnv->offset[columnIndex] * numOfRows + + pQuery->pSelectExpr[columnIndex].resBytes * realRowId; } -int32_t vnodeQuerySingleMeterPrepare(SQInfo *pQInfo, SMeterObj *pMeterObj, SMeterQuerySupportObj *pSupporter, - void *param) { +int32_t vnodeQueryTablePrepare(SQInfo *pQInfo, SMeterObj *pMeterObj, STableQuerySupportObj *pSupporter, void *param) { SQuery *pQuery = &pQInfo->query; int32_t code = TSDB_CODE_SUCCESS; @@ -4354,10 +4672,13 @@ int32_t vnodeQuerySingleMeterPrepare(SQInfo *pQInfo, SMeterObj *pMeterObj, SMete } vnodeRecordAllFiles(pQInfo, pMeterObj->vnode); - + pRuntimeEnv->numOfRowsPerPage = getNumOfRowsInResultPage(pQuery, false); - if (isGroupbyNormalCol(pQuery->pGroupbyExpr) || (pQuery->nAggTimeInterval > 0 && pQuery->slidingTime > 0)) { - if ((code = createQueryOutputBuffer(pSupporter, pQuery, false)) != TSDB_CODE_SUCCESS) { + if (isGroupbyNormalCol(pQuery->pGroupbyExpr) || isIntervalQuery(pQuery)) { + int32_t rows = getInitialPageNum(pSupporter); + + code = createDiskbasedResultBuffer(&pRuntimeEnv->pResultBuf, rows, pQuery->rowSize); + if (code != TSDB_CODE_SUCCESS) { return code; } @@ -4368,7 +4689,7 @@ int32_t vnodeQuerySingleMeterPrepare(SQInfo *pQInfo, SMeterObj *pMeterObj, SMete type = TSDB_DATA_TYPE_TIMESTAMP; } - initSlidingWindowInfo(&pRuntimeEnv->swindowResInfo, 3, type, pQuery->rowSize, pSupporter->pResult); + initWindowResInfo(&pRuntimeEnv->windowResInfo, pRuntimeEnv, rows, 4096, type); } pSupporter->rawSKey = pQuery->skey; @@ -4394,17 +4715,20 @@ int32_t vnodeQuerySingleMeterPrepare(SQInfo *pQInfo, SMeterObj *pMeterObj, SMete pointInterpSupporterDestroy(&interpInfo); return TSDB_CODE_SUCCESS; } - } else { - // find the skey and ekey in case of sliding query - // todo refactor - if (pQuery->slidingTime > 0 && pQuery->nAggTimeInterval > 0) { - int64_t skey = 0; + } else { // find the skey and ekey in case of sliding query + if (isIntervalQuery(pQuery)) { + STimeWindow win = {0}; - SWAP(pQuery->skey, pQuery->ekey, int64_t); - pQuery->order.order ^= 1; - pQuery->lastKey = pQuery->skey; + // find the minimum value for descending order query + TSKEY minKey = -1; + if (!QUERY_IS_ASC_QUERY(pQuery)) { + minKey = getGreaterEqualTimestamp(pRuntimeEnv); + } - if (normalizedFirstQueryRange(dataInDisk, dataInCache, pSupporter, &interpInfo, &skey) == false) { + int64_t skey = 0; + if ((normalizedFirstQueryRange(dataInDisk, dataInCache, pSupporter, &interpInfo, &skey) == false) || + (isFixedOutputQuery(pQuery) && !isTopBottomQuery(pQuery) && (pQuery->limit.offset > 0)) || + (isTopBottomQuery(pQuery) && pQuery->limit.offset >= pQuery->pSelectExpr[1].pBase.arg[0].argValue.i64)) { sem_post(&pQInfo->dataReady); pQInfo->over = 1; @@ -4412,36 +4736,29 @@ int32_t vnodeQuerySingleMeterPrepare(SQInfo *pQInfo, SMeterObj *pMeterObj, SMete return TSDB_CODE_SUCCESS; } - pQuery->skey = skey; - - pQuery->order.order ^= 1; - SWAP(pQuery->skey, pQuery->ekey, int64_t); - - int64_t ekey = 0; - pQuery->lastKey = pQuery->skey; - if (normalizedFirstQueryRange(dataInDisk, dataInCache, pSupporter, &interpInfo, &ekey) == false) { - // + if (!QUERY_IS_ASC_QUERY(pQuery)) { + win.skey = minKey; + win.ekey = skey; + } else { + win.skey = skey; + win.ekey = pQuery->ekey; } - pQuery->skey = ekey; - TSKEY skey1, ekey1; TSKEY windowSKey = 0, windowEKey = 0; - TSKEY minKey = MIN(pQuery->skey, pQuery->ekey); - TSKEY maxKey = MAX(pQuery->skey, pQuery->ekey); - - doGetAlignedIntervalQueryRangeImpl(pQuery, minKey, minKey, maxKey, &skey1, &ekey1, &windowSKey, &windowEKey); - pRuntimeEnv->swindowResInfo.startTime = windowSKey; - - pSupporter->rawSKey = pQuery->skey; - pSupporter->rawEKey = pQuery->ekey; + doGetAlignedIntervalQueryRangeImpl(pQuery, win.skey, win.skey, win.ekey, &skey1, &ekey1, &windowSKey, + &windowEKey); + pRuntimeEnv->windowResInfo.startTime = windowSKey; if (QUERY_IS_ASC_QUERY(pQuery)) { - pRuntimeEnv->swindowResInfo.prevSKey = windowSKey; + pRuntimeEnv->windowResInfo.prevSKey = windowSKey; } else { - pRuntimeEnv->swindowResInfo.prevSKey = windowSKey + ((pQuery->skey - windowSKey) / pQuery->slidingTime) * pQuery->slidingTime; + pRuntimeEnv->windowResInfo.prevSKey = + windowSKey + ((win.ekey - windowSKey) / pQuery->slidingTime) * pQuery->slidingTime; } + + pQuery->over = QUERY_NOT_COMPLETED; } else { int64_t ekey = 0; if ((normalizedFirstQueryRange(dataInDisk, dataInCache, pSupporter, &interpInfo, &ekey) == false) || @@ -4467,7 +4784,7 @@ int32_t vnodeQuerySingleMeterPrepare(SQInfo *pQInfo, SMeterObj *pMeterObj, SMete return TSDB_CODE_SUCCESS; } - int64_t rs = taosGetIntervalStartTimestamp(pSupporter->rawSKey, pQuery->nAggTimeInterval, pQuery->intervalTimeUnit, + int64_t rs = taosGetIntervalStartTimestamp(pSupporter->rawSKey, pQuery->intervalTime, pQuery->intervalTimeUnit, pQuery->precision); taosInitInterpoInfo(&pRuntimeEnv->interpoInfo, pQuery->order.order, rs, 0, 0); allocMemForInterpo(pSupporter, pQuery, pMeterObj); @@ -4479,17 +4796,17 @@ int32_t vnodeQuerySingleMeterPrepare(SQInfo *pQInfo, SMeterObj *pMeterObj, SMete // the pQuery->skey is changed during normalizedFirstQueryRange, so set the newest lastkey value pQuery->lastKey = pQuery->skey; pRuntimeEnv->stableQuery = false; - + return TSDB_CODE_SUCCESS; } void vnodeQueryFreeQInfoEx(SQInfo *pQInfo) { - if (pQInfo == NULL || pQInfo->pMeterQuerySupporter == NULL) { + if (pQInfo == NULL || pQInfo->pTableQuerySupporter == NULL) { return; } SQuery * pQuery = &pQInfo->query; - SMeterQuerySupportObj *pSupporter = pQInfo->pMeterQuerySupporter; + STableQuerySupportObj *pSupporter = pQInfo->pTableQuerySupporter; teardownQueryRuntimeEnv(&pSupporter->runtimeEnv); tfree(pSupporter->pMeterSidExtInfo); @@ -4500,16 +4817,16 @@ void vnodeQueryFreeQInfoEx(SQInfo *pQInfo) { } if (pSupporter->pSidSet != NULL || isGroupbyNormalCol(pQInfo->query.pGroupbyExpr) || - (pQuery->nAggTimeInterval > 0 && pQuery->slidingTime > 0)) { + isIntervalQuery(pQuery)) { int32_t size = 0; - if (isGroupbyNormalCol(pQInfo->query.pGroupbyExpr) || (pQuery->nAggTimeInterval > 0 && pQuery->slidingTime > 0)) { + if (isGroupbyNormalCol(pQInfo->query.pGroupbyExpr) || isIntervalQuery(pQuery)) { size = 10000; } else if (pSupporter->pSidSet != NULL) { size = pSupporter->pSidSet->numOfSubSet; } for (int32_t i = 0; i < size; ++i) { - destroyGroupResultBuf(&pSupporter->pResult[i], pQInfo->query.numOfOutputCols); + // destroyTimeWindowRes(&pSupporter->pResult[i], pQInfo->query.numOfOutputCols); } } @@ -4524,12 +4841,11 @@ void vnodeQueryFreeQInfoEx(SQInfo *pQInfo) { tfree(pSupporter->pMeterDataInfo); - tfree(pSupporter->pResult); - tfree(pQInfo->pMeterQuerySupporter); + tfree(pQInfo->pTableQuerySupporter); } -int32_t vnodeMultiMeterQueryPrepare(SQInfo *pQInfo, SQuery *pQuery, void *param) { - SMeterQuerySupportObj *pSupporter = pQInfo->pMeterQuerySupporter; +int32_t vnodeSTableQueryPrepare(SQInfo *pQInfo, SQuery *pQuery, void *param) { + STableQuerySupportObj *pSupporter = pQInfo->pTableQuerySupporter; if ((QUERY_IS_ASC_QUERY(pQuery) && (pQuery->skey > pQuery->ekey)) || (!QUERY_IS_ASC_QUERY(pQuery) && (pQuery->ekey > pQuery->skey))) { @@ -4592,35 +4908,36 @@ int32_t vnodeMultiMeterQueryPrepare(SQInfo *pQInfo, SQuery *pQuery, void *param) tSidSetSort(pSupporter->pSidSet); vnodeRecordAllFiles(pQInfo, pTable->vnode); - if ((ret = createQueryOutputBuffer(pSupporter, pQuery, true)) != TSDB_CODE_SUCCESS) { + int32_t size = getInitialPageNum(pSupporter); + ret = createDiskbasedResultBuffer(&pRuntimeEnv->pResultBuf, size, pQuery->rowSize); + if (ret != TSDB_CODE_SUCCESS) { return ret; } - if (isGroupbyNormalCol(pQuery->pGroupbyExpr)) { // group by columns not tags; - int16_t type = getGroupbyColumnType(pQuery, pQuery->pGroupbyExpr); - initSlidingWindowInfo(&pRuntimeEnv->swindowResInfo, 4096, type, pQuery->rowSize, pSupporter->pResult); - } + if (pQuery->intervalTime == 0) { + int16_t type = TSDB_DATA_TYPE_NULL; - if (pQuery->nAggTimeInterval != 0 || isSumAvgRateQuery(pQuery)) { - // one page for each table at least - ret = createResultBuf(&pRuntimeEnv->pResultBuf, pSupporter->numOfMeters, pQuery->rowSize); - if (ret != TSDB_CODE_SUCCESS) { - return ret; + if (isGroupbyNormalCol(pQuery->pGroupbyExpr)) { // group by columns not tags; + type = getGroupbyColumnType(pQuery, pQuery->pGroupbyExpr); + } else { + type = TSDB_DATA_TYPE_INT; // group id } + + initWindowResInfo(&pRuntimeEnv->windowResInfo, pRuntimeEnv, 512, 4096, type); } - + pRuntimeEnv->numOfRowsPerPage = getNumOfRowsInResultPage(pQuery, true); - + // metric query do not invoke interpolation, it will be done at the second-stage merge if (!isPointInterpoQuery(pQuery)) { pQuery->interpoType = TSDB_INTERPO_NONE; } - TSKEY revisedStime = taosGetIntervalStartTimestamp(pSupporter->rawSKey, pQuery->nAggTimeInterval, + TSKEY revisedStime = taosGetIntervalStartTimestamp(pSupporter->rawSKey, pQuery->intervalTime, pQuery->intervalTimeUnit, pQuery->precision); taosInitInterpoInfo(&pRuntimeEnv->interpoInfo, pQuery->order.order, revisedStime, 0, 0); pRuntimeEnv->stableQuery = true; - + return TSDB_CODE_SUCCESS; } @@ -4629,7 +4946,7 @@ int32_t vnodeMultiMeterQueryPrepare(SQInfo *pQInfo, SQuery *pQuery, void *param) * @param pQInfo */ void vnodeDecMeterRefcnt(SQInfo *pQInfo) { - SMeterQuerySupportObj *pSupporter = pQInfo->pMeterQuerySupporter; + STableQuerySupportObj *pSupporter = pQInfo->pTableQuerySupporter; if (pSupporter == NULL || pSupporter->numOfMeters == 1) { atomic_fetch_sub_32(&pQInfo->pObj->numOfQueries, 1); @@ -4685,7 +5002,7 @@ TSKEY getTimestampInDiskBlock(SQueryRuntimeEnv *pRuntimeEnv, int32_t index) { SMeterObj *pMeterObj = pRuntimeEnv->pMeterObj; - int32_t fileIndex = vnodeGetVnodeHeaderFileIdx(&pQuery->fileId, pRuntimeEnv, pQuery->order.order); + int32_t fileIndex = vnodeGetVnodeHeaderFileIndex(&pQuery->fileId, pRuntimeEnv, pQuery->order.order); dTrace("QInfo:%p vid:%d sid:%d id:%s, fileId:%d, slot:%d load data block due to primary key required", GET_QINFO_ADDR(pQuery), pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, pQuery->fileId, pQuery->slot); @@ -4902,7 +5219,7 @@ static int32_t moveToNextBlock(SQueryRuntimeEnv *pRuntimeEnv, int32_t step, __bl } } else { // next block in the same file int32_t fid = pQuery->fileId; - fileIndex = vnodeGetVnodeHeaderFileIdx(&fid, pRuntimeEnv, pQuery->order.order); + fileIndex = vnodeGetVnodeHeaderFileIndex(&fid, pRuntimeEnv, pQuery->order.order); pQuery->slot += step; pQuery->pos = (step == QUERY_ASC_FORWARD_STEP) ? 0 : pQuery->pBlock[pQuery->slot].numOfPoints - 1; @@ -4929,59 +5246,58 @@ static int32_t moveToNextBlock(SQueryRuntimeEnv *pRuntimeEnv, int32_t step, __bl return DISK_DATA_LOADED; } -static void doHandleDataBlockImpl(SQueryRuntimeEnv *pRuntimeEnv, SBlockInfo *pblockInfo, __block_search_fn_t searchFn, - int32_t *numOfRes, int32_t blockLoadStatus, int32_t *forwardStep) { +static int32_t doHandleDataBlockImpl(SQueryRuntimeEnv *pRuntimeEnv, SBlockInfo *pBlockInfo, + __block_search_fn_t searchFn, int32_t blockLoadStatus, int32_t *forwardStep) { SQuery * pQuery = pRuntimeEnv->pQuery; SQueryCostSummary *pSummary = &pRuntimeEnv->summary; + int32_t numOfRes = 0; - TSKEY * primaryKeys = (TSKEY *)pRuntimeEnv->primaryColBuffer->data; - int64_t start = taosGetTimestampUs(); + if (IS_DISK_DATA_BLOCK(pQuery) && blockLoadStatus != DISK_DATA_LOADED) { + *forwardStep = pBlockInfo->size; + return numOfRes; + } + SField *pFields = NULL; if (IS_DISK_DATA_BLOCK(pQuery)) { - SCompBlock *pBlock = getDiskDataBlock(pQuery, pQuery->slot); - *pblockInfo = getBlockBasicInfo(pRuntimeEnv, pBlock, BLK_FILE_BLOCK); - - if (blockLoadStatus == DISK_DATA_LOADED) { - *forwardStep = applyFunctionsOnBlock(pRuntimeEnv, pblockInfo, primaryKeys, pQuery->pFields[pQuery->slot], - searchFn, numOfRes); - } else { - *forwardStep = pblockInfo->size; - } - - pSummary->fileTimeUs += (taosGetTimestampUs() - start); - } else { + pFields = pQuery->pFields[pQuery->slot]; + } else { // in case of cache data block, no need to load operation assert(vnodeIsDatablockLoaded(pRuntimeEnv, pRuntimeEnv->pMeterObj, -1, true) == DISK_BLOCK_NO_NEED_TO_LOAD); + pFields = NULL; + } + + int64_t start = taosGetTimestampUs(); - SCacheBlock *pBlock = getCacheDataBlock(pRuntimeEnv->pMeterObj, pRuntimeEnv, pQuery->slot); - *pblockInfo = getBlockBasicInfo(pRuntimeEnv, pBlock, BLK_CACHE_BLOCK); + *forwardStep = + tableApplyFunctionsOnBlock(pRuntimeEnv, pBlockInfo, pFields, searchFn, &numOfRes, &pRuntimeEnv->windowResInfo); - *forwardStep = applyFunctionsOnBlock(pRuntimeEnv, pblockInfo, primaryKeys, NULL, searchFn, numOfRes); + int64_t elapsedTime = taosGetTimestampUs() - start; - pSummary->cacheTimeUs += (taosGetTimestampUs() - start); + if (IS_DISK_DATA_BLOCK(pQuery)) { + pSummary->fileTimeUs += elapsedTime; + } else { + pSummary->cacheTimeUs += elapsedTime; } -} -static void getNextLogicalQueryRange(SQueryRuntimeEnv *pRuntimeEnv, STimeWindow* pTimeWindow) { - SQuery *pQuery = pRuntimeEnv->pQuery; + return numOfRes; +} +// previous time window may not be of the same size of pQuery->intervalTime +static void getNextTimeWindow(SQuery *pQuery, STimeWindow *pTimeWindow) { int32_t factor = GET_FORWARD_DIRECTION_FACTOR(pQuery->order.order); - + pTimeWindow->skey += (pQuery->slidingTime * factor); - pTimeWindow->ekey += (pQuery->slidingTime * factor); + pTimeWindow->ekey = pTimeWindow->skey + (pQuery->intervalTime - 1); } static int64_t doScanAllDataBlocks(SQueryRuntimeEnv *pRuntimeEnv) { - SQuery *pQuery = pRuntimeEnv->pQuery; - bool LOAD_DATA = true; + SQuery * pQuery = pRuntimeEnv->pQuery; + SMeterObj *pMeterObj = pRuntimeEnv->pMeterObj; - int32_t forwardStep = 0; + bool LOAD_DATA = true; int64_t cnt = 0; - SMeterObj *pMeterObj = pRuntimeEnv->pMeterObj; - __block_search_fn_t searchFn = vnodeSearchKeyFunc[pMeterObj->searchAlgorithm]; int32_t blockLoadStatus = DISK_DATA_LOADED; - SQueryCostSummary * pSummary = &pRuntimeEnv->summary; int32_t step = GET_FORWARD_DIRECTION_FACTOR(pQuery->order.order); @@ -5001,9 +5317,9 @@ static int64_t doScanAllDataBlocks(SQueryRuntimeEnv *pRuntimeEnv) { return cnt; } - int32_t numOfRes = 0; - SBlockInfo blockInfo = {0}; - doHandleDataBlockImpl(pRuntimeEnv, &blockInfo, searchFn, &numOfRes, blockLoadStatus, &forwardStep); + int32_t forwardStep = 0; + SBlockInfo blockInfo = getBlockInfo(pRuntimeEnv); + /*int32_t numOfRes = */ doHandleDataBlockImpl(pRuntimeEnv, &blockInfo, searchFn, blockLoadStatus, &forwardStep); dTrace("QInfo:%p check data block, brange:%" PRId64 "-%" PRId64 ", fileId:%d, slot:%d, pos:%d, bstatus:%d, rows:%d, checked:%d", @@ -5016,90 +5332,66 @@ static int64_t doScanAllDataBlocks(SQueryRuntimeEnv *pRuntimeEnv) { cnt += forwardStep; - if (queryCompleteInBlock(pQuery, &blockInfo, forwardStep)) { + if (queryPausedInCurrentBlock(pQuery, &blockInfo, forwardStep)) { int32_t nextPos = accessPos + step; /* - * set the next access position, nextPos only required by - * 1. interval query. - * 2. multi-output query that may cause buffer overflow. + * set the next access position, nextPos only required when the interval query and projection query + * that cause output buffer overflow. When the query is completed, no need to load the next block any more. */ - if (pQuery->nAggTimeInterval > 0 || - (Q_STATUS_EQUAL(pQuery->over, QUERY_RESBUF_FULL) && pQuery->checkBufferInLoop == 1)) { + if (!Q_STATUS_EQUAL(pQuery->over, QUERY_COMPLETED) && Q_STATUS_EQUAL(pQuery->over, QUERY_RESBUF_FULL)) { if (nextPos >= blockInfo.size || nextPos < 0) { moveToNextBlock(pRuntimeEnv, step, searchFn, !LOAD_DATA); // slot/pos/fileId is updated in moveToNextBlock function savePointPosition(&pRuntimeEnv->nextPos, pQuery->fileId, pQuery->slot, pQuery->pos); } else { - savePointPosition(&pRuntimeEnv->nextPos, pQuery->fileId, pQuery->slot, accessPos + step); + savePointPosition(&pRuntimeEnv->nextPos, pQuery->fileId, pQuery->slot, nextPos); } } + break; } else { // query not completed, move to next block - int64_t start = taosGetTimestampUs(); - blockLoadStatus = moveToNextBlock(pRuntimeEnv, step, searchFn, LOAD_DATA); if (Q_STATUS_EQUAL(pQuery->over, QUERY_NO_DATA_TO_CHECK | QUERY_COMPLETED)) { - savePointPosition(&pRuntimeEnv->nextPos, pQuery->fileId, pQuery->slot, pQuery->pos); setQueryStatus(pQuery, QUERY_COMPLETED); break; } - - int64_t delta = (taosGetTimestampUs() - start); - if (IS_DISK_DATA_BLOCK(pQuery)) { - pSummary->fileTimeUs += delta; - } else { - pSummary->cacheTimeUs += delta; - } } // check next block - void *pNextBlock = getGenericDataBlock(pMeterObj, pRuntimeEnv, pQuery->slot); + blockInfo = getBlockInfo(pRuntimeEnv); - int32_t blockType = (IS_DISK_DATA_BLOCK(pQuery)) ? BLK_FILE_BLOCK : BLK_CACHE_BLOCK; - blockInfo = getBlockBasicInfo(pRuntimeEnv, pNextBlock, blockType); - if (!checkQueryRangeAgainstNextBlock(&blockInfo, pRuntimeEnv)) { + if ((QUERY_IS_ASC_QUERY(pQuery) && blockInfo.keyFirst > pQuery->ekey) || + (!QUERY_IS_ASC_QUERY(pQuery) && blockInfo.keyLast < pQuery->ekey)) { + setQueryStatus(pQuery, QUERY_COMPLETED); break; } - } // while(1) - - return cnt; -} - -static void updatelastkey(SQuery *pQuery, SMeterQueryInfo *pMeterQInfo) { pMeterQInfo->lastKey = pQuery->lastKey; } -void queryOnBlock(SMeterQuerySupportObj *pSupporter, int64_t *primaryKeys, int32_t blockStatus, - SBlockInfo *pBlockBasicInfo, SMeterDataInfo *pMeterDataInfo, SField *pFields, - __block_search_fn_t searchFn) { - /* cache blocks may be assign to other meter, abort */ - if (pBlockBasicInfo->size <= 0) { - return; - } - - SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; - SQuery * pQuery = pRuntimeEnv->pQuery; + if (Q_STATUS_EQUAL(pQuery->over, QUERY_RESBUF_FULL)) { + break; + } - if (pQuery->nAggTimeInterval == 0) { // not interval query - int32_t numOfRes = 0; - applyFunctionsOnBlock(pRuntimeEnv, pBlockBasicInfo, primaryKeys, pFields, searchFn, &numOfRes); + } // while(1) - // note: only fixed number of output for each group by operation - if (numOfRes > 0) { - pSupporter->pResult[pMeterDataInfo->groupIdx].numOfRows = numOfRes; - } + if (isIntervalQuery(pQuery) && IS_MASTER_SCAN(pRuntimeEnv)) { + if (Q_STATUS_EQUAL(pQuery->over, QUERY_COMPLETED | QUERY_NO_DATA_TO_CHECK)) { + closeAllTimeWindow(&pRuntimeEnv->windowResInfo); + pRuntimeEnv->windowResInfo.curIndex = pRuntimeEnv->windowResInfo.size - 1; + } else if (Q_STATUS_EQUAL(pQuery->over, QUERY_RESBUF_FULL)) { // check if window needs to be closed + SBlockInfo blockInfo = getBlockInfo(pRuntimeEnv); - // used to decide the correct start position in cache after check all data in files - updatelastkey(pQuery, pMeterDataInfo->pMeterQInfo); - if (pRuntimeEnv->pTSBuf != NULL) { - pMeterDataInfo->pMeterQInfo->cur = tsBufGetCursor(pRuntimeEnv->pTSBuf); + // check if need to close window result or not + TSKEY t = (QUERY_IS_ASC_QUERY(pQuery)) ? blockInfo.keyFirst : blockInfo.keyLast; + doCheckQueryCompleted(pRuntimeEnv, t, &pRuntimeEnv->windowResInfo); } - - } else { - applyIntervalQueryOnBlock(pSupporter, pMeterDataInfo, pBlockBasicInfo, blockStatus, pFields, searchFn); } + + return cnt; } +static void updatelastkey(SQuery *pQuery, SMeterQueryInfo *pMeterQInfo) { pMeterQInfo->lastKey = pQuery->lastKey; } + /* * set tag value in SQLFunctionCtx * e.g.,tag information into input buffer @@ -5109,7 +5401,7 @@ static void doSetTagValueInParam(SColumnModel *pTagSchema, int32_t tagColIdx, SM assert(tagColIdx >= 0); int16_t offset = getColumnModelOffset(pTagSchema, tagColIdx); - + void * pStr = (char *)pMeterSidInfo->tags + offset; SSchema *pCol = getColumnModelSchema(pTagSchema, tagColIdx); @@ -5123,7 +5415,7 @@ static void doSetTagValueInParam(SColumnModel *pTagSchema, int32_t tagColIdx, SM } void vnodeSetTagValueInParam(tSidSet *pSidSet, SQueryRuntimeEnv *pRuntimeEnv, SMeterSidExtInfo *pMeterSidInfo) { - SQuery * pQuery = pRuntimeEnv->pQuery; + SQuery * pQuery = pRuntimeEnv->pQuery; SColumnModel *pTagSchema = pSidSet->pColumnModel; SSqlFuncExprMsg *pFuncMsg = &pQuery->pSelectExpr[0].pBase; @@ -5153,8 +5445,7 @@ void vnodeSetTagValueInParam(tSidSet *pSidSet, SQueryRuntimeEnv *pRuntimeEnv, SM } } -static void doMerge(SQueryRuntimeEnv *pRuntimeEnv, int64_t timestamp, tFilePage *inputSrc, int32_t inputIdx, - bool mergeFlag) { +static void doMerge(SQueryRuntimeEnv *pRuntimeEnv, int64_t timestamp, SWindowResult *pWindowRes, bool mergeFlag) { SQuery * pQuery = pRuntimeEnv->pQuery; SQLFunctionCtx *pCtx = pRuntimeEnv->pCtx; @@ -5170,9 +5461,10 @@ static void doMerge(SQueryRuntimeEnv *pRuntimeEnv, int64_t timestamp, tFilePage pCtx[i].hasNull = true; pCtx[i].nStartQueryTimestamp = timestamp; - pCtx[i].aInputElemBuf = ((char *)inputSrc->data) + - ((int32_t)pRuntimeEnv->offset[i] * pRuntimeEnv->numOfRowsPerPage) + - pCtx[i].outputBytes * inputIdx; + pCtx[i].aInputElemBuf = getPosInResultPage(pRuntimeEnv, i, pWindowRes); + // pCtx[i].aInputElemBuf = ((char *)inputSrc->data) + + // ((int32_t)pRuntimeEnv->offset[i] * pRuntimeEnv->numOfRowsPerPage) + + // pCtx[i].outputBytes * inputIdx; // in case of tag column, the tag information should be extracted from input buffer if (functionId == TSDB_FUNC_TAG_DUMMY || functionId == TSDB_FUNC_TAG) { @@ -5262,7 +5554,7 @@ static void printBinaryData(int32_t functionId, char *data, int32_t srcDataType) void UNUSED_FUNC displayInterResult(SData **pdata, SQuery *pQuery, int32_t numOfRows) { int32_t numOfCols = pQuery->numOfOutputCols; - printf("metric query intern-result, total:%d\n", numOfRows); + printf("super table query intermediate result, total:%d\n", numOfRows); SQInfo * pQInfo = (SQInfo *)(GET_QINFO_ADDR(pQuery)); SMeterObj *pMeterObj = pQInfo->pObj; @@ -5302,55 +5594,54 @@ void UNUSED_FUNC displayInterResult(SData **pdata, SQuery *pQuery, int32_t numOf } } -static tFilePage *getMeterDataPage(SQueryResultBuf* pResultBuf, SMeterQueryInfo *pMeterQueryInfo, int32_t index) { - SIDList pList = getDataBufPagesIdList(pResultBuf, pMeterQueryInfo->sid); - return getResultBufferPageById(pResultBuf, pList.pData[index]); -} +// static tFilePage *getMeterDataPage(SQueryDiskbasedResultBuf *pResultBuf, SMeterQueryInfo *pMeterQueryInfo, +// int32_t index) { +// SIDList pList = getDataBufPagesIdList(pResultBuf, pMeterQueryInfo->sid); +// return getResultBufferPageById(pResultBuf, pList.pData[index]); +//} -typedef struct Position { - int32_t pageIdx; - int32_t rowIdx; -} Position; +// typedef struct Position { +// int32_t pageIdx; +// int32_t rowIdx; +//} Position; typedef struct SCompSupporter { SMeterDataInfo ** pMeterDataInfo; - Position * pPosition; - SMeterQuerySupportObj *pSupporter; + int32_t * position; + STableQuerySupportObj *pSupporter; } SCompSupporter; -int64_t getCurrentTimestamp(SCompSupporter *pSupportor, int32_t meterIdx) { - Position * pPos = &pSupportor->pPosition[meterIdx]; - tFilePage *pPage = getMeterDataPage(pSupportor->pSupporter->runtimeEnv.pResultBuf, - pSupportor->pMeterDataInfo[meterIdx]->pMeterQInfo, pPos->pageIdx); - - return *(int64_t *)(pPage->data + TSDB_KEYSIZE * pPos->rowIdx); -} - -int32_t meterResultComparator(const void *pLeft, const void *pRight, void *param) { +int32_t tableResultComparFn(const void *pLeft, const void *pRight, void *param) { int32_t left = *(int32_t *)pLeft; int32_t right = *(int32_t *)pRight; - SCompSupporter *supporter = (SCompSupporter *)param; - SQueryResultBuf* pResultBuf = supporter->pSupporter->runtimeEnv.pResultBuf; - - Position leftPos = supporter->pPosition[left]; - Position rightPos = supporter->pPosition[right]; + SCompSupporter * supporter = (SCompSupporter *)param; + SQueryRuntimeEnv *pRuntimeEnv = &supporter->pSupporter->runtimeEnv; + + int32_t leftPos = supporter->position[left]; + int32_t rightPos = supporter->position[right]; /* left source is exhausted */ - if (leftPos.pageIdx == -1 && leftPos.rowIdx == -1) { + if (leftPos == -1) { return 1; } /* right source is exhausted*/ - if (rightPos.pageIdx == -1 && rightPos.rowIdx == -1) { + if (rightPos == -1) { return -1; } - tFilePage *pPageLeft = getMeterDataPage(pResultBuf, supporter->pMeterDataInfo[left]->pMeterQInfo, leftPos.pageIdx); - int64_t leftTimestamp = *(int64_t *)(pPageLeft->data + TSDB_KEYSIZE * leftPos.rowIdx); + SWindowResInfo *pWindowResInfo1 = &supporter->pMeterDataInfo[left]->pMeterQInfo->windowResInfo; + SWindowResult * pWindowRes1 = getWindowResult(pWindowResInfo1, leftPos); + + char *b1 = getPosInResultPage(pRuntimeEnv, PRIMARYKEY_TIMESTAMP_COL_INDEX, pWindowRes1); + TSKEY leftTimestamp = GET_INT64_VAL(b1); - tFilePage *pPageRight = getMeterDataPage(pResultBuf, supporter->pMeterDataInfo[right]->pMeterQInfo, rightPos.pageIdx); - int64_t rightTimestamp = *(int64_t *)(pPageRight->data + TSDB_KEYSIZE * rightPos.rowIdx); + SWindowResInfo *pWindowResInfo2 = &supporter->pMeterDataInfo[right]->pMeterQInfo->windowResInfo; + SWindowResult * pWindowRes2 = getWindowResult(pWindowResInfo2, rightPos); + + char *b2 = getPosInResultPage(pRuntimeEnv, PRIMARYKEY_TIMESTAMP_COL_INDEX, pWindowRes2); + TSKEY rightTimestamp = GET_INT64_VAL(b2); if (leftTimestamp == rightTimestamp) { return 0; @@ -5359,7 +5650,7 @@ int32_t meterResultComparator(const void *pLeft, const void *pRight, void *param return leftTimestamp > rightTimestamp ? 1 : -1; } -int32_t mergeMetersResultToOneGroups(SMeterQuerySupportObj *pSupporter) { +int32_t mergeMetersResultToOneGroups(STableQuerySupportObj *pSupporter) { SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; SQuery * pQuery = pRuntimeEnv->pQuery; @@ -5392,7 +5683,7 @@ int32_t mergeMetersResultToOneGroups(SMeterQuerySupportObj *pSupporter) { return TSDB_CODE_SUCCESS; } -void copyResToQueryResultBuf(SMeterQuerySupportObj *pSupporter, SQuery *pQuery) { +void copyResToQueryResultBuf(STableQuerySupportObj *pSupporter, SQuery *pQuery) { if (pSupporter->offset == pSupporter->numOfGroupResultPages) { pSupporter->numOfGroupResultPages = 0; @@ -5408,142 +5699,153 @@ void copyResToQueryResultBuf(SMeterQuerySupportObj *pSupporter, SQuery *pQuery) } } - SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; - SQueryResultBuf* pResultBuf = pRuntimeEnv->pResultBuf; - - SIDList list = getDataBufPagesIdList(pResultBuf, 200000 + pSupporter->offset + (pSupporter->subgroupIdx - 1)* 10000); - + SQueryRuntimeEnv * pRuntimeEnv = &pSupporter->runtimeEnv; + SQueryDiskbasedResultBuf *pResultBuf = pRuntimeEnv->pResultBuf; + + int32_t id = getGroupResultId(pSupporter->subgroupIdx - 1); + SIDList list = getDataBufPagesIdList(pResultBuf, pSupporter->offset + id); + int32_t total = 0; - for(int32_t i = 0; i < list.size; ++i) { - tFilePage* pData = getResultBufferPageById(pResultBuf, list.pData[i]); + for (int32_t i = 0; i < list.size; ++i) { + tFilePage *pData = getResultBufferPageById(pResultBuf, list.pData[i]); total += pData->numOfElems; } - + pQuery->sdata[0]->len = total; - + int32_t offset = 0; - for(int32_t num = 0; num < list.size; ++num) { - tFilePage* pData = getResultBufferPageById(pResultBuf, list.pData[num]); - + for (int32_t num = 0; num < list.size; ++num) { + tFilePage *pData = getResultBufferPageById(pResultBuf, list.pData[num]); + for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { int32_t bytes = pRuntimeEnv->pCtx[i].outputBytes; - char* pDest = pQuery->sdata[i]->data; - - memcpy(pDest + offset*bytes, pData->data + pRuntimeEnv->offset[i] * pData->numOfElems, bytes * pData->numOfElems); + char * pDest = pQuery->sdata[i]->data; + + memcpy(pDest + offset * bytes, pData->data + pRuntimeEnv->offset[i] * pData->numOfElems, + bytes * pData->numOfElems); } - + offset += pData->numOfElems; } assert(pQuery->pointsRead == 0); - + pQuery->pointsRead += pQuery->sdata[0]->len; pSupporter->offset += 1; } -int32_t doMergeMetersResultsToGroupRes(SMeterQuerySupportObj *pSupporter, SQuery *pQuery, SQueryRuntimeEnv *pRuntimeEnv, - SMeterDataInfo *pMeterDataInfo, int32_t start, int32_t end) { - // calculate the maximum required space - if (pSupporter->groupResultSize == 0) { - for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { - pSupporter->groupResultSize += sizeof(tFilePage) + pQuery->pointsToRead * pRuntimeEnv->pCtx[i].outputBytes; +int64_t getNumOfResultWindowRes(SQueryRuntimeEnv *pRuntimeEnv, SWindowResult *pWindowRes) { + SQuery *pQuery = pRuntimeEnv->pQuery; + + int64_t maxOutput = 0; + for (int32_t j = 0; j < pQuery->numOfOutputCols; ++j) { + int32_t functionId = pQuery->pSelectExpr[j].pBase.functionId; + + /* + * ts, tag, tagprj function can not decide the output number of current query + * the number of output result is decided by main output + */ + if (functionId == TSDB_FUNC_TS || functionId == TSDB_FUNC_TAG || functionId == TSDB_FUNC_TAGPRJ) { + continue; + } + + SResultInfo *pResultInfo = &pWindowRes->resultInfo[j]; + if (pResultInfo != NULL && maxOutput < pResultInfo->numOfRes) { + maxOutput = pResultInfo->numOfRes; } } + return maxOutput; +} + +int32_t doMergeMetersResultsToGroupRes(STableQuerySupportObj *pSupporter, SQuery *pQuery, SQueryRuntimeEnv *pRuntimeEnv, + SMeterDataInfo *pMeterDataInfo, int32_t start, int32_t end) { tFilePage ** buffer = (tFilePage **)pQuery->sdata; - Position * posArray = calloc(1, sizeof(Position) * (end - start)); - SMeterDataInfo **pValidMeter = malloc(POINTER_BYTES * (end - start)); + int32_t * posList = calloc((end - start), sizeof(int32_t)); + SMeterDataInfo **pTableList = malloc(POINTER_BYTES * (end - start)); + // todo opt for the case of one table per group int32_t numOfMeters = 0; for (int32_t i = start; i < end; ++i) { int32_t sid = pMeterDataInfo[i].pMeterQInfo->sid; + SIDList list = getDataBufPagesIdList(pRuntimeEnv->pResultBuf, sid); - - if (list.size > 0 && pMeterDataInfo[i].pMeterQInfo->numOfRes > 0) { - pValidMeter[numOfMeters] = &pMeterDataInfo[i]; - // set the merge start position: page:0, index:0 - posArray[numOfMeters].pageIdx = 0; - posArray[numOfMeters++].rowIdx = 0; + if (list.size > 0 && pMeterDataInfo[i].pMeterQInfo->windowResInfo.size > 0) { + pTableList[numOfMeters] = &pMeterDataInfo[i]; + numOfMeters += 1; } } if (numOfMeters == 0) { - tfree(posArray); - tfree(pValidMeter); + tfree(posList); + tfree(pTableList); + assert(pSupporter->numOfGroupResultPages == 0); return 0; } - SCompSupporter cs = {pValidMeter, posArray, pSupporter}; - SLoserTreeInfo *pTree = NULL; + SCompSupporter cs = {pTableList, posList, pSupporter}; - tLoserTreeCreate(&pTree, numOfMeters, &cs, meterResultComparator); + SLoserTreeInfo *pTree = NULL; + tLoserTreeCreate(&pTree, numOfMeters, &cs, tableResultComparFn); - SQLFunctionCtx *pCtx = pRuntimeEnv->pCtx; - resetMergeResultBuf(pQuery, pCtx); + SResultInfo *pResultInfo = calloc(pQuery->numOfOutputCols, sizeof(SResultInfo)); + setWindowResultInfo(pResultInfo, pQuery, pRuntimeEnv->stableQuery); + resetMergeResultBuf(pQuery, pRuntimeEnv->pCtx, pResultInfo); int64_t lastTimestamp = -1; int64_t startt = taosGetTimestampMs(); while (1) { - int32_t pos = pTree->pNode[0].index; - Position * position = &cs.pPosition[pos]; - SQueryResultBuf* pResultBuf = cs.pSupporter->runtimeEnv.pResultBuf; - tFilePage *pPage = getMeterDataPage(pResultBuf, pValidMeter[pos]->pMeterQInfo, position->pageIdx); - - int64_t ts = getCurrentTimestamp(&cs, pos); - if (ts == lastTimestamp) {// merge with the last one - doMerge(pRuntimeEnv, ts, pPage, position->rowIdx, true); - } else { - // copy data to disk buffer - if (buffer[0]->numOfElems == pQuery->pointsToRead) { - if (flushFromResultBuf(pSupporter, pQuery, pRuntimeEnv) != TSDB_CODE_SUCCESS) { - return -1; - } + int32_t pos = pTree->pNode[0].index; - resetMergeResultBuf(pQuery, pCtx); - } + SWindowResInfo *pWindowResInfo = &pTableList[pos]->pMeterQInfo->windowResInfo; + SWindowResult * pWindowRes = getWindowResult(pWindowResInfo, cs.position[pos]); - pPage = getMeterDataPage(pResultBuf, pValidMeter[pos]->pMeterQInfo, position->pageIdx); - if (pPage->numOfElems <= 0) { // current source data page is empty - // do nothing - } else { - doMerge(pRuntimeEnv, ts, pPage, position->rowIdx, false); - buffer[0]->numOfElems += 1; - } - } + char *b = getPosInResultPage(pRuntimeEnv, PRIMARYKEY_TIMESTAMP_COL_INDEX, pWindowRes); + TSKEY ts = GET_INT64_VAL(b); - lastTimestamp = ts; + assert(ts == pWindowRes->window.skey); + int64_t num = getNumOfResultWindowRes(pRuntimeEnv, pWindowRes); + if (num <= 0) { + cs.position[pos] += 1; - if (cs.pPosition[pos].rowIdx >= pPage->numOfElems - 1) { - cs.pPosition[pos].rowIdx = 0; - cs.pPosition[pos].pageIdx += 1; // try next page + if (cs.position[pos] >= pWindowResInfo->size) { + cs.position[pos] = -1; - // check if current page is empty or not. if it is empty, ignore it and try next - SIDList list = getDataBufPagesIdList(pRuntimeEnv->pResultBuf, cs.pMeterDataInfo[pos]->pMeterQInfo->sid); - if (cs.pPosition[pos].pageIdx <= list.size - 1) { - tFilePage *newPage = getMeterDataPage(pResultBuf, pValidMeter[pos]->pMeterQInfo, position->pageIdx); - - // if current source data page is null, it must be the last page of source output page - if (newPage->numOfElems <= 0) { - cs.pPosition[pos].pageIdx += 1; - assert(cs.pPosition[pos].pageIdx >= list.size - 1); + // all input sources are exhausted + if (--numOfMeters == 0) { + break; + } + } + } else { + if (ts == lastTimestamp) { // merge with the last one + doMerge(pRuntimeEnv, ts, pWindowRes, true); + } else { // copy data to disk buffer + if (buffer[0]->numOfElems == pQuery->pointsToRead) { + if (flushFromResultBuf(pSupporter, pQuery, pRuntimeEnv) != TSDB_CODE_SUCCESS) { + return -1; + } + + resetMergeResultBuf(pQuery, pRuntimeEnv->pCtx, pResultInfo); } + + doMerge(pRuntimeEnv, ts, pWindowRes, false); + buffer[0]->numOfElems += 1; } - // the following code must be executed if current source pages are exhausted - if (cs.pPosition[pos].pageIdx >= list.size) { - cs.pPosition[pos].pageIdx = -1; - cs.pPosition[pos].rowIdx = -1; + lastTimestamp = ts; + + cs.position[pos] += 1; + if (cs.position[pos] >= pWindowResInfo->size) { + cs.position[pos] = -1; // all input sources are exhausted if (--numOfMeters == 0) { break; } } - } else { - cs.pPosition[pos].rowIdx += 1; } tLoserTreeAdjust(pTree, pos + pTree->numOfEntries); @@ -5551,11 +5853,12 @@ int32_t doMergeMetersResultsToGroupRes(SMeterQuerySupportObj *pSupporter, SQuery if (buffer[0]->numOfElems != 0) { // there are data in buffer if (flushFromResultBuf(pSupporter, pQuery, pRuntimeEnv) != TSDB_CODE_SUCCESS) { -// dError("QInfo:%p failed to flush data into temp file, abort query", GET_QINFO_ADDR(pQuery), -// pSupporter->extBufFile); + // dError("QInfo:%p failed to flush data into temp file, abort query", GET_QINFO_ADDR(pQuery), + // pSupporter->extBufFile); tfree(pTree); - tfree(pValidMeter); - tfree(posArray); + tfree(pTableList); + tfree(posList); + tfree(pResultInfo); return -1; } @@ -5569,56 +5872,59 @@ int32_t doMergeMetersResultsToGroupRes(SMeterQuerySupportObj *pSupporter, SQuery dTrace("QInfo:%p result merge completed, elapsed time:%" PRId64 " ms", GET_QINFO_ADDR(pQuery), endt - startt); tfree(pTree); - tfree(pValidMeter); - tfree(posArray); + tfree(pTableList); + tfree(posList); + tfree(pResultInfo); pSupporter->offset = 0; return pSupporter->numOfGroupResultPages; } -int32_t flushFromResultBuf(SMeterQuerySupportObj *pSupporter, const SQuery *pQuery, +int32_t flushFromResultBuf(STableQuerySupportObj *pSupporter, const SQuery *pQuery, const SQueryRuntimeEnv *pRuntimeEnv) { - SQueryResultBuf* pResultBuf = pRuntimeEnv->pResultBuf; - int32_t capacity = (DEFAULT_INTERN_BUF_SIZE - sizeof(tFilePage))/ pQuery->rowSize; - + SQueryDiskbasedResultBuf *pResultBuf = pRuntimeEnv->pResultBuf; + int32_t capacity = (DEFAULT_INTERN_BUF_SIZE - sizeof(tFilePage)) / pQuery->rowSize; + // the base value for group result, since the maximum number of table for each vnode will not exceed 100,000. - int32_t base = 200000; int32_t pageId = -1; - + int32_t remain = pQuery->sdata[0]->len; int32_t offset = 0; - - while(remain > 0) { + + while (remain > 0) { int32_t r = remain; if (r > capacity) { r = capacity; } - - tFilePage* buf = getNewDataBuf(pResultBuf, base + pSupporter->subgroupIdx*10000 + pSupporter->numOfGroupResultPages, &pageId); - - //pagewise copy to dest buffer + + int32_t id = getGroupResultId(pSupporter->subgroupIdx) + pSupporter->numOfGroupResultPages; + tFilePage *buf = getNewDataBuf(pResultBuf, id, &pageId); + + // pagewise copy to dest buffer for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { int32_t bytes = pRuntimeEnv->pCtx[i].outputBytes; buf->numOfElems = r; - - memcpy(buf->data + pRuntimeEnv->offset[i] * buf->numOfElems, ((char*)pQuery->sdata[i]->data) + offset * bytes, - buf->numOfElems * bytes); + + memcpy(buf->data + pRuntimeEnv->offset[i] * buf->numOfElems, ((char *)pQuery->sdata[i]->data) + offset * bytes, + buf->numOfElems * bytes); } - + offset += r; remain -= r; } - + pSupporter->numOfGroupResultPages += 1; return TSDB_CODE_SUCCESS; } -void resetMergeResultBuf(SQuery *pQuery, SQLFunctionCtx *pCtx) { +void resetMergeResultBuf(SQuery *pQuery, SQLFunctionCtx *pCtx, SResultInfo *pResultInfo) { for (int32_t k = 0; k < pQuery->numOfOutputCols; ++k) { pCtx[k].aOutputBuf = pQuery->sdata[k]->data - pCtx[k].outputBytes; pCtx[k].size = 1; pCtx[k].startOffset = 0; + pCtx[k].resultInfo = &pResultInfo[k]; + pQuery->sdata[k]->len = 0; } } @@ -5629,167 +5935,165 @@ void setMeterDataInfo(SMeterDataInfo *pMeterDataInfo, SMeterObj *pMeterObj, int3 pMeterDataInfo->meterOrderIdx = meterIdx; } -int32_t doCloseAllOpenedResults(SMeterQuerySupportObj *pSupporter) { - SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; - SQuery * pQuery = pRuntimeEnv->pQuery; - - /* for interval query, close all unclosed results */ - if (pQuery->nAggTimeInterval > 0) { - SMeterDataInfo *pMeterInfo = pSupporter->pMeterDataInfo; - for (int32_t i = 0; i < pSupporter->numOfMeters; ++i) { - if (pMeterInfo[i].pMeterQInfo != NULL && pMeterInfo[i].pMeterQInfo->lastResRows > 0) { - int32_t index = pMeterInfo[i].meterOrderIdx; +static void doDisableFunctsForSupplementaryScan(SQuery *pQuery, SWindowResInfo *pWindowResInfo, int32_t order) { + for (int32_t i = 0; i < pWindowResInfo->size; ++i) { + SWindowStatus *pStatus = getTimeWindowResStatus(pWindowResInfo, i); + if (!pStatus->closed) { + continue; + } - pRuntimeEnv->pMeterObj = getMeterObj(pSupporter->pMetersHashTable, pSupporter->pSidSet->pSids[index]->sid); - assert(pRuntimeEnv->pMeterObj == pMeterInfo[i].pMeterObj); + SWindowResult *buf = getWindowResult(pWindowResInfo, i); - int32_t ret = setIntervalQueryExecutionContext(pSupporter, i, pMeterInfo[i].pMeterQInfo); - if (ret != TSDB_CODE_SUCCESS) { - return ret; - } + // open/close the specified query for each group result + for (int32_t j = 0; j < pQuery->numOfOutputCols; ++j) { + int32_t functId = pQuery->pSelectExpr[j].pBase.functionId; - ret = saveResult(pSupporter, pMeterInfo[i].pMeterQInfo, pMeterInfo[i].pMeterQInfo->lastResRows); - if (ret != TSDB_CODE_SUCCESS) { - return ret; - } + if (((functId == TSDB_FUNC_FIRST || functId == TSDB_FUNC_FIRST_DST) && order == TSQL_SO_DESC) || + ((functId == TSDB_FUNC_LAST || functId == TSDB_FUNC_LAST_DST) && order == TSQL_SO_ASC)) { + buf->resultInfo[j].complete = false; + } else if (functId != TSDB_FUNC_TS && functId != TSDB_FUNC_TAG) { + buf->resultInfo[j].complete = true; } } } - - return TSDB_CODE_SUCCESS; } -void disableFunctForSuppleScan(SQueryRuntimeEnv *pRuntimeEnv, int32_t order) { +void disableFunctForTableSuppleScan(SQueryRuntimeEnv *pRuntimeEnv, int32_t order) { SQuery *pQuery = pRuntimeEnv->pQuery; - if (isGroupbyNormalCol(pQuery->pGroupbyExpr) || (pQuery->slidingTime > 0 && pQuery->nAggTimeInterval > 0)) { - for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { - pRuntimeEnv->pCtx[i].order = (pRuntimeEnv->pCtx[i].order) ^ 1; - } - - SSlidingWindowInfo *pSlidingWindowInfo = &pRuntimeEnv->swindowResInfo; - - for (int32_t i = 0; i < pSlidingWindowInfo->size; ++i) { - SWindowStatus *pStatus = &pSlidingWindowInfo->pStatus[i]; - if (!pStatus->closed) { - continue; - } - - SOutputRes *buf = &pSlidingWindowInfo->pResult[i]; - - // open/close the specified query for each group result - for (int32_t j = 0; j < pQuery->numOfOutputCols; ++j) { - int32_t functId = pQuery->pSelectExpr[j].pBase.functionId; + // group by normal columns and interval query on normal table + for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { + pRuntimeEnv->pCtx[i].order = (pRuntimeEnv->pCtx[i].order) ^ 1u; + } - if (((functId == TSDB_FUNC_FIRST || functId == TSDB_FUNC_FIRST_DST) && order == TSQL_SO_DESC) || - ((functId == TSDB_FUNC_LAST || functId == TSDB_FUNC_LAST_DST) && order == TSQL_SO_ASC)) { - buf->resultInfo[j].complete = false; - } else if (functId != TSDB_FUNC_TS && functId != TSDB_FUNC_TAG) { - buf->resultInfo[j].complete = true; - } + SWindowResInfo *pWindowResInfo = &pRuntimeEnv->windowResInfo; + if (isGroupbyNormalCol(pQuery->pGroupbyExpr) || isIntervalQuery(pQuery)) { + doDisableFunctsForSupplementaryScan(pQuery, pWindowResInfo, order); + } else { // for simple result of table query, + for (int32_t j = 0; j < pQuery->numOfOutputCols; ++j) { + int32_t functId = pQuery->pSelectExpr[j].pBase.functionId; + SQLFunctionCtx* pCtx = &pRuntimeEnv->pCtx[j]; + + if (((functId == TSDB_FUNC_FIRST || functId == TSDB_FUNC_FIRST_DST) && order == TSQL_SO_DESC) || + ((functId == TSDB_FUNC_LAST || functId == TSDB_FUNC_LAST_DST) && order == TSQL_SO_ASC)) { + pCtx->resultInfo->complete = false; + } else if (functId != TSDB_FUNC_TS && functId != TSDB_FUNC_TAG) { + pCtx->resultInfo->complete = true; } } - } else { // TODO ERROR!! - // need to handle for each query result, not just the single runtime ctx. - for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { - pRuntimeEnv->pCtx[i].order = (pRuntimeEnv->pCtx[i].order) ^ 1; - int32_t functId = pQuery->pSelectExpr[i].pBase.functionId; + } - SResultInfo *pResInfo = GET_RES_INFO(&pRuntimeEnv->pCtx[i]); - if (((functId == TSDB_FUNC_FIRST || functId == TSDB_FUNC_FIRST_DST) && order == TSQL_SO_DESC) || - ((functId == TSDB_FUNC_LAST || functId == TSDB_FUNC_LAST_DST) && order == TSQL_SO_ASC)) { - pResInfo->complete = false; + pQuery->order.order = pQuery->order.order ^ 1u; +} + +void disableFunctForSuppleScan(STableQuerySupportObj *pSupporter, int32_t order) { + SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; + SQuery * pQuery = pRuntimeEnv->pQuery; + + for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { + pRuntimeEnv->pCtx[i].order = (pRuntimeEnv->pCtx[i].order) ^ 1u; + } + + if (isIntervalQuery(pQuery)) { + for (int32_t i = 0; i < pSupporter->numOfMeters; ++i) { + SMeterQueryInfo *pMeterQueryInfo = pSupporter->pMeterDataInfo[i].pMeterQInfo; + SWindowResInfo * pWindowResInfo = &pMeterQueryInfo->windowResInfo; - } else if (functId != TSDB_FUNC_TS && functId != TSDB_FUNC_TAG) { - pResInfo->complete = true; - } + doDisableFunctsForSupplementaryScan(pQuery, pWindowResInfo, order); } + } else { + SWindowResInfo *pWindowResInfo = &pRuntimeEnv->windowResInfo; + doDisableFunctsForSupplementaryScan(pQuery, pWindowResInfo, order); } - pQuery->order.order = pQuery->order.order ^ 1; + pQuery->order.order = (pQuery->order.order) ^ 1u; } void enableFunctForMasterScan(SQueryRuntimeEnv *pRuntimeEnv, int32_t order) { SQuery *pQuery = pRuntimeEnv->pQuery; for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { - pRuntimeEnv->pCtx[i].order = (pRuntimeEnv->pCtx[i].order) ^ 1; + pRuntimeEnv->pCtx[i].order = (pRuntimeEnv->pCtx[i].order) ^ 1u; } - pQuery->order.order = (pQuery->order.order ^ 1); + pQuery->order.order = (pQuery->order.order) ^ 1u; } -void createQueryResultBuf(SQueryRuntimeEnv *pRuntimeEnv, SOutputRes *pResultRow, bool isSTableQuery, SPosInfo *posInfo) { - SQuery* pQuery = pRuntimeEnv->pQuery; - +void createQueryResultInfo(SQuery *pQuery, SWindowResult *pResultRow, bool isSTableQuery, SPosInfo *posInfo) { int32_t numOfCols = pQuery->numOfOutputCols; pResultRow->resultInfo = calloc((size_t)numOfCols, sizeof(SResultInfo)); - pResultRow->pos = *posInfo;//page->data + (pRuntimeEnv->offset[i] * pRuntimeEnv->numOfRowsPerPage) + page->numOfElems*s1; - - for (int32_t i = 0; i < numOfCols; ++i) { - SResultInfo *pResultInfo = &pResultRow->resultInfo[i]; - size_t size = pQuery->pSelectExpr[i].interResBytes; - setResultInfoBuf(pResultInfo, (int32_t)size, isSTableQuery); - } + pResultRow->pos = *posInfo; + + // set the intermediate result output buffer + setWindowResultInfo(pResultRow->resultInfo, pQuery, isSTableQuery); } -void clearGroupResultBuf(SQueryRuntimeEnv *pRuntimeEnv, SOutputRes *pOneOutputRes) { - if (pOneOutputRes == NULL) { +void clearTimeWindowResBuf(SQueryRuntimeEnv *pRuntimeEnv, SWindowResult *pWindowRes) { + if (pWindowRes == NULL) { return; } for (int32_t i = 0; i < pRuntimeEnv->pQuery->numOfOutputCols; ++i) { - SResultInfo *pResultInfo = &pOneOutputRes->resultInfo[i]; -// int32_t size = sizeof(tFilePage) + pResultInfo->bufLen * pOneOutputRes->nAlloc; + SResultInfo *pResultInfo = &pWindowRes->resultInfo[i]; -// memset(pOneOutputRes->pos[i], 0, (size_t)size); - char* s = getPosInResultPage(pRuntimeEnv, i, pOneOutputRes); + char * s = getPosInResultPage(pRuntimeEnv, i, pWindowRes); size_t size = pRuntimeEnv->pQuery->pSelectExpr[i].resBytes; memset(s, 0, size); - + resetResultInfo(pResultInfo); } + + pWindowRes->numOfRows = 0; + // pWindowRes->nAlloc = 0; + pWindowRes->pos = (SPosInfo){-1, -1}; + pWindowRes->status.closed = false; + pWindowRes->window = (STimeWindow){0, 0}; } -void copyGroupResultBuf(SQueryRuntimeEnv *pRuntimeEnv, SOutputRes* dst, const SOutputRes* src) { +/** + * The source window result pos attribution of the source window result does not assign to the destination, + * since the attribute of "Pos" is bound to each window result when the window result is created in the + * disk-based result buffer. + */ +void copyTimeWindowResBuf(SQueryRuntimeEnv *pRuntimeEnv, SWindowResult *dst, const SWindowResult *src) { dst->numOfRows = src->numOfRows; - dst->nAlloc = src->nAlloc; - + // dst->nAlloc = src->nAlloc; + dst->window = src->window; + dst->status = src->status; + int32_t nOutputCols = pRuntimeEnv->pQuery->numOfOutputCols; - - for(int32_t i = 0; i < nOutputCols; ++i) { + + for (int32_t i = 0; i < nOutputCols; ++i) { SResultInfo *pDst = &dst->resultInfo[i]; SResultInfo *pSrc = &src->resultInfo[i]; - - char* buf = pDst->interResultBuf; + + char *buf = pDst->interResultBuf; memcpy(pDst, pSrc, sizeof(SResultInfo)); pDst->interResultBuf = buf; // restore the allocated buffer - + // copy the result info struct memcpy(pDst->interResultBuf, pSrc->interResultBuf, pDst->bufLen); // copy the output buffer data from src to dst, the position info keep unchanged - char* dstBuf = getPosInResultPage(pRuntimeEnv, i, dst); - char* srcBuf = getPosInResultPage(pRuntimeEnv, i, src); + char * dstBuf = getPosInResultPage(pRuntimeEnv, i, dst); + char * srcBuf = getPosInResultPage(pRuntimeEnv, i, (SWindowResult *)src); size_t s = pRuntimeEnv->pQuery->pSelectExpr[i].resBytes; - + memcpy(dstBuf, srcBuf, s); } } -void destroyGroupResultBuf(SOutputRes *pOneOutputRes, int32_t nOutputCols) { - if (pOneOutputRes == NULL) { +void destroyTimeWindowRes(SWindowResult *pWindowRes, int32_t nOutputCols) { + if (pWindowRes == NULL) { return; } for (int32_t i = 0; i < nOutputCols; ++i) { -// free(pOneOutputRes->pos[i]); - free(pOneOutputRes->resultInfo[i].interResultBuf); + free(pWindowRes->resultInfo[i].interResultBuf); } - free(pOneOutputRes->resultInfo); -// free(pOneOutputRes->result); + free(pWindowRes->resultInfo); } void resetCtxOutputBuf(SQueryRuntimeEnv *pRuntimeEnv) { @@ -5829,7 +6133,7 @@ void forwardCtxOutputBuf(SQueryRuntimeEnv *pRuntimeEnv, int64_t output) { // set next output position if (IS_OUTER_FORWARD(aAggs[functionId].nStatus)) { - pRuntimeEnv->pCtx[j].aOutputBuf += pRuntimeEnv->pCtx[j].outputBytes * output /** factor*/; + pRuntimeEnv->pCtx[j].aOutputBuf += pRuntimeEnv->pCtx[j].outputBytes * output; } if (functionId == TSDB_FUNC_TOP || functionId == TSDB_FUNC_BOTTOM) { @@ -5840,7 +6144,7 @@ void forwardCtxOutputBuf(SQueryRuntimeEnv *pRuntimeEnv, int64_t output) { * * diff function is handled in multi-output function */ - pRuntimeEnv->pCtx[j].ptsOutputBuf += TSDB_KEYSIZE * output/* * factor*/; + pRuntimeEnv->pCtx[j].ptsOutputBuf += TSDB_KEYSIZE * output; } resetResultInfo(pRuntimeEnv->pCtx[j].resultInfo); @@ -5853,7 +6157,7 @@ void initCtxOutputBuf(SQueryRuntimeEnv *pRuntimeEnv) { for (int32_t j = 0; j < pQuery->numOfOutputCols; ++j) { int32_t functionId = pQuery->pSelectExpr[j].pBase.functionId; pRuntimeEnv->pCtx[j].currentStage = 0; - + aAggs[functionId].init(&pRuntimeEnv->pCtx[j]); } } @@ -5898,24 +6202,17 @@ typedef struct SQueryStatus { SPositionInfo start; SPositionInfo next; SPositionInfo end; - - TSKEY skey; - TSKEY ekey; - int8_t overStatus; - TSKEY lastKey; - - STSCursor cur; + int8_t overStatus; + TSKEY lastKey; + STSCursor cur; } SQueryStatus; - +// todo refactor static void queryStatusSave(SQueryRuntimeEnv *pRuntimeEnv, SQueryStatus *pStatus) { SQuery *pQuery = pRuntimeEnv->pQuery; pStatus->overStatus = pQuery->over; pStatus->lastKey = pQuery->lastKey; - pStatus->skey = pQuery->skey; - pStatus->ekey = pQuery->ekey; - pStatus->start = pRuntimeEnv->startPos; pStatus->next = pRuntimeEnv->nextPos; pStatus->end = pRuntimeEnv->endPos; @@ -5923,7 +6220,7 @@ static void queryStatusSave(SQueryRuntimeEnv *pRuntimeEnv, SQueryStatus *pStatus pStatus->cur = tsBufGetCursor(pRuntimeEnv->pTSBuf); // save the cursor if (pRuntimeEnv->pTSBuf) { - pRuntimeEnv->pTSBuf->cur.order ^= 1; + pRuntimeEnv->pTSBuf->cur.order ^= 1u; tsBufNextPos(pRuntimeEnv->pTSBuf); } @@ -5932,19 +6229,13 @@ static void queryStatusSave(SQueryRuntimeEnv *pRuntimeEnv, SQueryStatus *pStatus SWAP(pQuery->skey, pQuery->ekey, TSKEY); pQuery->lastKey = pQuery->skey; pRuntimeEnv->startPos = pRuntimeEnv->endPos; - - SWAP(pRuntimeEnv->intervalWindow.skey, pRuntimeEnv->intervalWindow.ekey, TSKEY); } static void queryStatusRestore(SQueryRuntimeEnv *pRuntimeEnv, SQueryStatus *pStatus) { SQuery *pQuery = pRuntimeEnv->pQuery; SWAP(pQuery->skey, pQuery->ekey, TSKEY); - SWAP(pRuntimeEnv->intervalWindow.skey, pRuntimeEnv->intervalWindow.ekey, TSKEY); - - pQuery->lastKey = pStatus->lastKey; - pQuery->skey = pStatus->skey; - pQuery->ekey = pStatus->ekey; + pQuery->lastKey = pStatus->lastKey; pQuery->over = pStatus->overStatus; pRuntimeEnv->startPos = pStatus->start; @@ -5963,7 +6254,7 @@ static void doSingleMeterSupplementScan(SQueryRuntimeEnv *pRuntimeEnv) { } dTrace("QInfo:%p start to supp scan", GET_QINFO_ADDR(pQuery)); - + SET_SUPPLEMENT_SCAN_FLAG(pRuntimeEnv); // usually this load operation will incur load disk block operation @@ -5973,7 +6264,7 @@ static void doSingleMeterSupplementScan(SQueryRuntimeEnv *pRuntimeEnv) { (!QUERY_IS_ASC_QUERY(pQuery) && endKey >= pQuery->ekey)); // close necessary function execution during supplementary scan - disableFunctForSuppleScan(pRuntimeEnv, pQuery->order.order); + disableFunctForTableSuppleScan(pRuntimeEnv, pQuery->order.order); queryStatusSave(pRuntimeEnv, &qStatus); doScanAllDataBlocks(pRuntimeEnv); @@ -5998,60 +6289,90 @@ void setQueryStatus(SQuery *pQuery, int8_t status) { } } -void vnodeScanAllData(SQueryRuntimeEnv *pRuntimeEnv) { +bool needScanDataBlocksAgain(SQueryRuntimeEnv *pRuntimeEnv) { SQuery *pQuery = pRuntimeEnv->pQuery; - setQueryStatus(pQuery, QUERY_NOT_COMPLETED); - - /* store the start query position */ - savePointPosition(&pRuntimeEnv->startPos, pQuery->fileId, pQuery->slot, pQuery->pos); - int64_t skey = pQuery->lastKey; - - while (1) { - doScanAllDataBlocks(pRuntimeEnv); + bool toContinue = false; - bool toContinue = true; + if (isGroupbyNormalCol(pQuery->pGroupbyExpr) || isIntervalQuery(pQuery)) { + // for each group result, call the finalize function for each column + SWindowResInfo *pWindowResInfo = &pRuntimeEnv->windowResInfo; - if (isGroupbyNormalCol(pQuery->pGroupbyExpr) || (pQuery->nAggTimeInterval > 0 && pQuery->slidingTime > 0)) { - // for each group result, call the finalize function for each column - SSlidingWindowInfo *pSlidingWindowInfo = &pRuntimeEnv->swindowResInfo; + for (int32_t i = 0; i < pWindowResInfo->size; ++i) { + SWindowResult *pResult = getWindowResult(pWindowResInfo, i); + if (!pResult->status.closed) { + continue; + } - for (int32_t i = 0; i < pSlidingWindowInfo->size; ++i) { - SOutputRes *buf = &pSlidingWindowInfo->pResult[i]; + setWindowResOutputBuf(pRuntimeEnv, pResult); - SWindowStatus *pStatus = &pSlidingWindowInfo->pStatus[i]; - if (!pStatus->closed) { + for (int32_t j = 0; j < pQuery->numOfOutputCols; ++j) { + int16_t functId = pQuery->pSelectExpr[j].pBase.functionId; + if (functId == TSDB_FUNC_TS) { continue; } + + aAggs[functId].xNextStep(&pRuntimeEnv->pCtx[j]); + SResultInfo *pResInfo = GET_RES_INFO(&pRuntimeEnv->pCtx[j]); + + toContinue |= (!pResInfo->complete); + } + } + } else { + for (int32_t j = 0; j < pQuery->numOfOutputCols; ++j) { + int16_t functId = pQuery->pSelectExpr[j].pBase.functionId; + if (functId == TSDB_FUNC_TS) { + continue; + } + + aAggs[functId].xNextStep(&pRuntimeEnv->pCtx[j]); + SResultInfo *pResInfo = GET_RES_INFO(&pRuntimeEnv->pCtx[j]); - setGroupOutputBuffer(pRuntimeEnv, buf); + toContinue |= (!pResInfo->complete); + } + } - for (int32_t j = 0; j < pQuery->numOfOutputCols; ++j) { - aAggs[pQuery->pSelectExpr[j].pBase.functionId].xNextStep(&pRuntimeEnv->pCtx[j]); - SResultInfo *pResInfo = GET_RES_INFO(&pRuntimeEnv->pCtx[j]); + return toContinue; +} - toContinue &= (pResInfo->complete); - } - } - } else { - for (int32_t j = 0; j < pQuery->numOfOutputCols; ++j) { - aAggs[pQuery->pSelectExpr[j].pBase.functionId].xNextStep(&pRuntimeEnv->pCtx[j]); - SResultInfo *pResInfo = GET_RES_INFO(&pRuntimeEnv->pCtx[j]); +void vnodeScanAllData(SQueryRuntimeEnv *pRuntimeEnv) { + SQuery *pQuery = pRuntimeEnv->pQuery; + setQueryStatus(pQuery, QUERY_NOT_COMPLETED); - toContinue &= (pResInfo->complete); - } - } + /* store the start query position */ + savePointPosition(&pRuntimeEnv->startPos, pQuery->fileId, pQuery->slot, pQuery->pos); + int64_t oldSkey = pQuery->skey; + int64_t oldEkey = pQuery->ekey; + + int64_t skey = pQuery->lastKey; + int32_t status = pQuery->over; + + SET_MASTER_SCAN_FLAG(pRuntimeEnv); + int32_t step = GET_FORWARD_DIRECTION_FACTOR(pQuery->order.order); + + while (1) { + doScanAllDataBlocks(pRuntimeEnv); - if (toContinue) { + if (!needScanDataBlocksAgain(pRuntimeEnv)) { + // restore the status + if (pRuntimeEnv->scanFlag == REPEAT_SCAN) { + pQuery->over = status; + } break; } - // set the correct start position, and load the corresponding block in buffer if required. - TSKEY actKey = loadRequiredBlockIntoMem(pRuntimeEnv, &pRuntimeEnv->startPos); - assert((QUERY_IS_ASC_QUERY(pQuery) && actKey >= pQuery->skey) || - (!QUERY_IS_ASC_QUERY(pQuery) && actKey <= pQuery->skey)); + /* + * set the correct start position, and load the corresponding block in buffer for next + * round scan all data blocks. + */ + TSKEY key = loadRequiredBlockIntoMem(pRuntimeEnv, &pRuntimeEnv->startPos); + assert((QUERY_IS_ASC_QUERY(pQuery) && key >= pQuery->skey) || (!QUERY_IS_ASC_QUERY(pQuery) && key <= pQuery->skey)); - setQueryStatus(pQuery, QUERY_NOT_COMPLETED); + status = pQuery->over; + pQuery->ekey = pQuery->lastKey - step; pQuery->lastKey = pQuery->skey; + + setQueryStatus(pQuery, QUERY_NOT_COMPLETED); + pRuntimeEnv->scanFlag = REPEAT_SCAN; /* check if query is killed or not */ if (isQueryKilled(pQuery)) { @@ -6060,33 +6381,36 @@ void vnodeScanAllData(SQueryRuntimeEnv *pRuntimeEnv) { } } - int64_t newSkey = pQuery->skey; + // no need to set the end key + int64_t curLastKey = pQuery->lastKey; pQuery->skey = skey; + pQuery->ekey = pQuery->lastKey - step; doSingleMeterSupplementScan(pRuntimeEnv); - - // update the pQuery->skey/pQuery->ekey to limit the scan scope of sliding query during - // supplementary scan - pQuery->skey = newSkey; + + // update the pQuery->skey/pQuery->ekey to limit the scan scope of sliding query during supplementary scan + pQuery->skey = oldSkey; + pQuery->ekey = oldEkey; + pQuery->lastKey = curLastKey; } void doFinalizeResult(SQueryRuntimeEnv *pRuntimeEnv) { SQuery *pQuery = pRuntimeEnv->pQuery; - if (isGroupbyNormalCol(pQuery->pGroupbyExpr) || (pQuery->nAggTimeInterval > 0 && pQuery->slidingTime > 0)) { + if (isGroupbyNormalCol(pQuery->pGroupbyExpr) || isIntervalQuery(pQuery)) { // for each group result, call the finalize function for each column - SSlidingWindowInfo *pSlidingWindowInfo = &pRuntimeEnv->swindowResInfo; + SWindowResInfo *pWindowResInfo = &pRuntimeEnv->windowResInfo; if (isGroupbyNormalCol(pQuery->pGroupbyExpr)) { - closeAllSlidingWindow(pSlidingWindowInfo); + closeAllTimeWindow(pWindowResInfo); } - - for (int32_t i = 0; i < pSlidingWindowInfo->size; ++i) { - SOutputRes *buf = &pSlidingWindowInfo->pResult[i]; - if (!slidingWindowClosed(pSlidingWindowInfo, i)) { + + for (int32_t i = 0; i < pWindowResInfo->size; ++i) { + SWindowResult *buf = &pWindowResInfo->pResult[i]; + if (!isWindowResClosed(pWindowResInfo, i)) { continue; } - - setGroupOutputBuffer(pRuntimeEnv, buf); + + setWindowResOutputBuf(pRuntimeEnv, buf); for (int32_t j = 0; j < pQuery->numOfOutputCols; ++j) { aAggs[pQuery->pSelectExpr[j].pBase.functionId].xFinalize(&pRuntimeEnv->pCtx[j]); @@ -6144,89 +6468,6 @@ int64_t getNumOfResult(SQueryRuntimeEnv *pRuntimeEnv) { return maxOutput; } -static int32_t getNextIntervalQueryRange(SMeterQuerySupportObj *pSupporter, SQueryRuntimeEnv *pRuntimeEnv, - int64_t *skey, int64_t *ekey) { - SQuery *pQuery = pRuntimeEnv->pQuery; - - int32_t factor = GET_FORWARD_DIRECTION_FACTOR(pQuery->order.order); - - *skey = pRuntimeEnv->intervalWindow.skey + (pQuery->slidingTime * factor); - *ekey = pRuntimeEnv->intervalWindow.ekey + (pQuery->slidingTime * factor); - - if (pQuery->slidingTime > 0) { - if (QUERY_IS_ASC_QUERY(pQuery)) { - // the next sliding window is not contained in the query time range - if (*skey < pSupporter->rawSKey) { - *skey = pSupporter->rawSKey; - } - - if (*skey > pSupporter->rawEKey) { - return QUERY_COMPLETED; - } - - if (*ekey > pSupporter->rawEKey) { - *ekey = pSupporter->rawEKey; - } - } else { - if (*skey > pSupporter->rawSKey) { - *skey = pSupporter->rawSKey; - } - - if (*skey < pSupporter->rawEKey) { - return QUERY_COMPLETED; - } - - if (*ekey < pSupporter->rawEKey) { - *ekey = pSupporter->rawEKey; - } - } - } - - return QUERY_NOT_COMPLETED; -} - -/* - * forward the query range for next interval query - */ -void forwardIntervalQueryRange(SMeterQuerySupportObj *pSupporter, SQueryRuntimeEnv *pRuntimeEnv) { - SQuery *pQuery = pRuntimeEnv->pQuery; - if (pQuery->slidingTime > 0 && pQuery->nAggTimeInterval > 0) { - if ((QUERY_IS_ASC_QUERY(pQuery) && pQuery->lastKey >= pQuery->ekey) || - (!QUERY_IS_ASC_QUERY(pQuery) && pQuery->lastKey <= pQuery->ekey)) { - setQueryStatus(pQuery, QUERY_COMPLETED); - } else { - /*TSKEY nextTimestamp =*/ loadRequiredBlockIntoMem(pRuntimeEnv, &pRuntimeEnv->nextPos); - } - - return; - } - - int32_t r = getNextIntervalQueryRange(pSupporter, pRuntimeEnv, &pQuery->skey, &pQuery->ekey); - if (r == QUERY_COMPLETED) { - setQueryStatus(pQuery, QUERY_COMPLETED); - return; - } - - getNextLogicalQueryRange(pRuntimeEnv, &pRuntimeEnv->intervalWindow); - - /* ensure the search in cache will return right position */ - pQuery->lastKey = pQuery->skey; - - TSKEY nextTimestamp = loadRequiredBlockIntoMem(pRuntimeEnv, &pRuntimeEnv->nextPos); - if ((nextTimestamp > pSupporter->rawEKey && QUERY_IS_ASC_QUERY(pQuery)) || - (nextTimestamp < pSupporter->rawEKey && !QUERY_IS_ASC_QUERY(pQuery)) || - Q_STATUS_EQUAL(pQuery->over, QUERY_NO_DATA_TO_CHECK)) { - setQueryStatus(pQuery, QUERY_COMPLETED); - return; - } - - // bridge the gap in group by time function - if ((nextTimestamp > pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) || - (nextTimestamp < pQuery->ekey && !QUERY_IS_ASC_QUERY(pQuery))) { - getAlignedIntervalQueryRange(pRuntimeEnv, nextTimestamp, pSupporter->rawSKey, pSupporter->rawEKey); - } -} - static int32_t offsetComparator(const void *pLeft, const void *pRight) { SMeterDataInfo **pLeft1 = (SMeterDataInfo **)pLeft; SMeterDataInfo **pRight1 = (SMeterDataInfo **)pRight; @@ -6252,7 +6493,7 @@ int32_t vnodeFilterQualifiedMeters(SQInfo *pQInfo, int32_t vid, tSidSet *pSidSet int32_t *numOfMeters, SMeterDataInfo ***pReqMeterDataInfo) { SQuery *pQuery = &pQInfo->query; - SMeterQuerySupportObj *pSupporter = pQInfo->pMeterQuerySupporter; + STableQuerySupportObj *pSupporter = pQInfo->pTableQuerySupporter; SMeterSidExtInfo ** pMeterSidExtInfo = pSupporter->pMeterSidExtInfo; SQueryRuntimeEnv * pRuntimeEnv = &pSupporter->runtimeEnv; @@ -6348,7 +6589,8 @@ int32_t vnodeFilterQualifiedMeters(SQInfo *pQInfo, int32_t vid, tSidSet *pSidSet pOneMeterDataInfo->offsetInHeaderFile = (uint64_t)compHeader->compInfoOffset; if (pOneMeterDataInfo->pMeterQInfo == NULL) { - pOneMeterDataInfo->pMeterQInfo = createMeterQueryInfo(pQuery, pMeterObj->sid, pSupporter->rawSKey, pSupporter->rawEKey); + pOneMeterDataInfo->pMeterQInfo = + createMeterQueryInfo(pSupporter, pMeterObj->sid, pSupporter->rawSKey, pSupporter->rawEKey); } (*pReqMeterDataInfo)[*numOfMeters] = pOneMeterDataInfo; @@ -6367,26 +6609,19 @@ int32_t vnodeFilterQualifiedMeters(SQInfo *pQInfo, int32_t vid, tSidSet *pSidSet return TSDB_CODE_SUCCESS; } -SMeterQueryInfo *createMeterQueryInfo(SQuery *pQuery, int32_t sid, TSKEY skey, TSKEY ekey) { +SMeterQueryInfo *createMeterQueryInfo(STableQuerySupportObj *pSupporter, int32_t sid, TSKEY skey, TSKEY ekey) { + SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; + SMeterQueryInfo *pMeterQueryInfo = calloc(1, sizeof(SMeterQueryInfo)); pMeterQueryInfo->skey = skey; pMeterQueryInfo->ekey = ekey; pMeterQueryInfo->lastKey = skey; -// pMeterQueryInfo->numOfPages = 0; -// pMeterQueryInfo->numOfAlloc = INIT_ALLOCATE_DISK_PAGES; -// pMeterQueryInfo->pageList = calloc(pMeterQueryInfo->numOfAlloc, sizeof(uint32_t)); - pMeterQueryInfo->lastResRows = 0; pMeterQueryInfo->sid = sid; pMeterQueryInfo->cur.vnodeIndex = -1; - pMeterQueryInfo->resultInfo = calloc((size_t)pQuery->numOfOutputCols, sizeof(SResultInfo)); - for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { - SResultInfo *pResInfo = &pMeterQueryInfo->resultInfo[i]; - setResultInfoBuf(pResInfo, pQuery->pSelectExpr[i].interResBytes, true); - } - + initWindowResInfo(&pMeterQueryInfo->windowResInfo, pRuntimeEnv, 100, 100, TSDB_DATA_TYPE_INT); return pMeterQueryInfo; } @@ -6395,53 +6630,35 @@ void destroyMeterQueryInfo(SMeterQueryInfo *pMeterQueryInfo, int32_t numOfCols) return; } -// free(pMeterQueryInfo->pageList); - for (int32_t i = 0; i < numOfCols; ++i) { - tfree(pMeterQueryInfo->resultInfo[i].interResultBuf); - } + // free(pMeterQueryInfo->pageList); + // for (int32_t i = 0; i < numOfCols; ++i) { + // tfree(pMeterQueryInfo->[i].interResultBuf); + // } - free(pMeterQueryInfo->resultInfo); + // free(pMeterQueryInfo->resultInfo); free(pMeterQueryInfo); } -void changeMeterQueryInfoForSuppleQuery(SQueryResultBuf* pResultBuf, SMeterQueryInfo *pMeterQueryInfo, TSKEY skey, - TSKEY ekey) { +void changeMeterQueryInfoForSuppleQuery(SQuery *pQuery, SMeterQueryInfo *pMeterQueryInfo, TSKEY skey, TSKEY ekey) { if (pMeterQueryInfo == NULL) { return; } - pMeterQueryInfo->skey = skey; - pMeterQueryInfo->ekey = ekey; - pMeterQueryInfo->lastKey = pMeterQueryInfo->skey; - - pMeterQueryInfo->queryRangeSet = 0; - pMeterQueryInfo->cur.order = pMeterQueryInfo->cur.order ^ 1; - pMeterQueryInfo->cur.vnodeIndex = -1; - - // previous does not generate any results - SIDList list = getDataBufPagesIdList(pResultBuf, pMeterQueryInfo->sid); - - if (list.size == 0) { - pMeterQueryInfo->reverseFillRes = 0; + // order has change already! + int32_t step = GET_FORWARD_DIRECTION_FACTOR(pQuery->order.order); + if (!QUERY_IS_ASC_QUERY(pQuery)) { + assert(pMeterQueryInfo->ekey >= pMeterQueryInfo->lastKey + step); } else { - pMeterQueryInfo->reverseIndex = pMeterQueryInfo->numOfRes; - pMeterQueryInfo->reverseFillRes = 1; + assert(pMeterQueryInfo->ekey <= pMeterQueryInfo->lastKey + step); } -} -void saveIntervalQueryRange(SQueryRuntimeEnv *pRuntimeEnv, SMeterQueryInfo *pMeterQueryInfo) { - SQuery *pQuery = pRuntimeEnv->pQuery; - - pMeterQueryInfo->skey = pQuery->skey; - pMeterQueryInfo->ekey = pQuery->ekey; - pMeterQueryInfo->lastKey = pQuery->lastKey; + pMeterQueryInfo->ekey = pMeterQueryInfo->lastKey + step; - assert(((pQuery->lastKey >= pQuery->skey) && QUERY_IS_ASC_QUERY(pQuery)) || - ((pQuery->lastKey <= pQuery->skey) && !QUERY_IS_ASC_QUERY(pQuery))); + SWAP(pMeterQueryInfo->skey, pMeterQueryInfo->ekey, TSKEY); + pMeterQueryInfo->lastKey = pMeterQueryInfo->skey; - if (pRuntimeEnv->pTSBuf != NULL) { - pMeterQueryInfo->cur = tsBufGetCursor(pRuntimeEnv->pTSBuf); - } + pMeterQueryInfo->cur.order = pMeterQueryInfo->cur.order ^ 1u; + pMeterQueryInfo->cur.vnodeIndex = -1; } void restoreIntervalQueryRange(SQueryRuntimeEnv *pRuntimeEnv, SMeterQueryInfo *pMeterQueryInfo) { @@ -6555,7 +6772,7 @@ static bool setCurrentQueryRange(SMeterDataInfo *pMeterDataInfo, SQuery *pQuery, * @param pMeterDataInfo * @return */ -int32_t getDataBlocksForMeters(SMeterQuerySupportObj *pSupporter, SQuery *pQuery, int32_t numOfMeters, +int32_t getDataBlocksForMeters(STableQuerySupportObj *pSupporter, SQuery *pQuery, int32_t numOfMeters, const char *filePath, SMeterDataInfo **pMeterDataInfo, uint32_t *numOfBlocks) { SQInfo * pQInfo = (SQInfo *)GET_QINFO_ADDR(pQuery); SQueryCostSummary *pSummary = &pSupporter->runtimeEnv.summary; @@ -6590,13 +6807,13 @@ int32_t getDataBlocksForMeters(SMeterQuerySupportObj *pSupporter, SQuery *pQuery size_t bufferSize = size + sizeof(TSCKSUM); pMeterDataInfo[j]->numOfBlocks = compInfo.numOfBlocks; - char* p = realloc(pMeterDataInfo[j]->pBlock, bufferSize); + char *p = realloc(pMeterDataInfo[j]->pBlock, bufferSize); if (p == NULL) { clearAllMeterDataBlockInfo(pMeterDataInfo, 0, numOfMeters); return TSDB_CODE_SERV_OUT_OF_MEMORY; } else { memset(p, 0, bufferSize); - pMeterDataInfo[j]->pBlock = (SCompBlock*) p; + pMeterDataInfo[j]->pBlock = (SCompBlock *)p; } read(pVnodeFileInfo->headerFd, pMeterDataInfo[j]->pBlock, bufferSize); @@ -6633,7 +6850,7 @@ int32_t getDataBlocksForMeters(SMeterQuerySupportObj *pSupporter, SQuery *pQuery if (!setValidDataBlocks(pMeterDataInfo[j], end)) { clearAllMeterDataBlockInfo(pMeterDataInfo, 0, numOfMeters); - + pQInfo->killed = 1; // set query kill, abort current query since no memory available return TSDB_CODE_SERV_OUT_OF_MEMORY; } @@ -6756,10 +6973,10 @@ int32_t createDataBlocksInfoEx(SMeterDataInfo **pMeterDataInfo, int32_t numOfMet for (int32_t k = 0; k < pMeterDataInfo[j]->numOfBlocks; ++k) { SMeterDataBlockInfoEx *pBlockInfoEx = &supporter.pDataBlockInfoEx[numOfQualMeters][k]; - + pBlockInfoEx->pBlock.compBlock = &pBlock[k]; pBlockInfoEx->pBlock.fields = NULL; - + pBlockInfoEx->pMeterDataInfo = pMeterDataInfo[j]; pBlockInfoEx->groupIdx = pMeterDataInfo[j]->groupIdx; // set the group index pBlockInfoEx->blockIndex = pMeterDataInfo[j]->start + k; // set the block index in original meter @@ -6803,516 +7020,97 @@ int32_t createDataBlocksInfoEx(SMeterDataInfo **pMeterDataInfo, int32_t numOfMet * for(int32_t i = 0; i < cnt - 1; ++i) { * assert((*pDataBlockInfoEx)[i].pBlock.compBlock->offset < (*pDataBlockInfoEx)[i+1].pBlock.compBlock->offset); * } - */ - - dTrace("QInfo %p %d data blocks sort completed", addr, cnt); - cleanBlockOrderSupporter(&supporter, numOfMeters); - free(pTree); - - return TSDB_CODE_SUCCESS; -} - -/** - * set output buffer for different group - * @param pRuntimeEnv - * @param pDataBlockInfoEx - */ -void setExecutionContext(SMeterQuerySupportObj *pSupporter, SOutputRes *outputRes, int32_t meterIdx, int32_t groupIdx, - SMeterQueryInfo *pMeterQueryInfo) { - SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; - - setGroupOutputBuffer(pRuntimeEnv, &outputRes[groupIdx]); - initCtxOutputBuf(pRuntimeEnv); - - vnodeSetTagValueInParam(pSupporter->pSidSet, pRuntimeEnv, pSupporter->pMeterSidExtInfo[meterIdx]); - - // set the right cursor position for ts buffer - if (pSupporter->runtimeEnv.pTSBuf != NULL) { - if (pMeterQueryInfo->cur.vnodeIndex == -1) { - pMeterQueryInfo->tag = pRuntimeEnv->pCtx[0].tag.i64Key; - - tsBufGetElemStartPos(pSupporter->runtimeEnv.pTSBuf, 0, pMeterQueryInfo->tag); - } else { - tsBufSetCursor(pSupporter->runtimeEnv.pTSBuf, &pMeterQueryInfo->cur); - } - } -} - -static void setGroupOutputBuffer(SQueryRuntimeEnv *pRuntimeEnv, SOutputRes *pResult) { - SQuery *pQuery = pRuntimeEnv->pQuery; - - // Note: pResult->pos[i]->numOfElems == 0, there is only fixed number of results for each group - for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { - SQLFunctionCtx *pCtx = &pRuntimeEnv->pCtx[i]; - pCtx->aOutputBuf = getPosInResultPage(pRuntimeEnv, i, pResult); - - int32_t functionId = pQuery->pSelectExpr[i].pBase.functionId; - if (functionId == TSDB_FUNC_TOP || functionId == TSDB_FUNC_BOTTOM || functionId == TSDB_FUNC_DIFF) { - pCtx->ptsOutputBuf = pRuntimeEnv->pCtx[0].aOutputBuf; - } - - /* - * set the output buffer information and intermediate buffer - * not all queries require the interResultBuf, such as COUNT - */ - pCtx->resultInfo = &pResult->resultInfo[i]; - - // set super table query flag - SResultInfo *pResInfo = GET_RES_INFO(pCtx); - if (!isGroupbyNormalCol(pQuery->pGroupbyExpr)) { - pResInfo->superTableQ = true; - } - } -} - -static char *getOutputResPos(SQueryRuntimeEnv *pRuntimeEnv, tFilePage *pData, int32_t row, int32_t col) { - // the output for each record should be less than the DEFAULT_INTERN_BUF_SIZE - assert(pRuntimeEnv->pCtx[col].outputBytes <= DEFAULT_INTERN_BUF_SIZE); - - return (char *)pData->data + pRuntimeEnv->offset[col] * pRuntimeEnv->numOfRowsPerPage + - pRuntimeEnv->pCtx[col].outputBytes * row; -} - -void setCtxOutputPointerForSupplementScan(SMeterQuerySupportObj *pSupporter, SMeterQueryInfo *pMeterQueryInfo) { - SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; - SQuery * pQuery = pRuntimeEnv->pQuery; - - int32_t index = pMeterQueryInfo->reverseIndex; - tFilePage *pData = NULL; - int32_t i = 0; - - SQueryResultBuf* pResultBuf = pRuntimeEnv->pResultBuf; - - // find the position for this output result - SIDList list = getDataBufPagesIdList(pResultBuf, pMeterQueryInfo->sid); - for (; i < list.size; ++i) { - pData = getResultBufferPageById(pResultBuf, list.pData[i]); - if (index <= pData->numOfElems) { - break; - } - - index -= pData->numOfElems; - } - - assert(index >= 0); - - /* - * if it is the first records in master scan, no next results exist, so no need to init the result buffer - * all data are processed and save to buffer during supplementary scan. - */ - if (index == 0) { - return; - } - - for (int32_t k = 0; k < pQuery->numOfOutputCols; ++k) { - SQLFunctionCtx *pCtx = &pRuntimeEnv->pCtx[k]; - - pCtx->aOutputBuf = getOutputResPos(pRuntimeEnv, pData, index - 1, k); - SResultInfo *pResInfo = GET_RES_INFO(pCtx); - if (pResInfo->complete) { - continue; - } - - int32_t functId = pQuery->pSelectExpr[k].pBase.functionId; - - // setup runtime environment - if ((QUERY_IS_ASC_QUERY(pQuery) && functId == TSDB_FUNC_FIRST_DST) || - (!QUERY_IS_ASC_QUERY(pQuery) && functId == TSDB_FUNC_LAST_DST)) { - if (pMeterQueryInfo->lastResRows == 0) { - pCtx->currentStage = 0; - - resetResultInfo(pResInfo); - aAggs[functId].init(pCtx); - } - } - } - - // the first column is always the timestamp for interval query - TSKEY ts = *(TSKEY *)pRuntimeEnv->pCtx[0].aOutputBuf; - SMeterObj *pMeterObj = pRuntimeEnv->pMeterObj; - qTrace("QInfo:%p vid:%d sid:%d id:%s, set output result pointer, ts:%" PRId64 ", index:%d", GET_QINFO_ADDR(pQuery), - pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, ts, pMeterQueryInfo->reverseIndex); -} + */ -void validateTimestampForSupplementResult(SQueryRuntimeEnv *pRuntimeEnv, int64_t numOfIncrementRes) { - SQuery * pQuery = pRuntimeEnv->pQuery; - SQLFunctionCtx *pCtx = pRuntimeEnv->pCtx; + dTrace("QInfo %p %d data blocks sort completed", addr, cnt); + cleanBlockOrderSupporter(&supporter, numOfMeters); + free(pTree); - if (pRuntimeEnv->scanFlag == SUPPLEMENTARY_SCAN && numOfIncrementRes > 0) { - for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { - int32_t functionId = pQuery->pSelectExpr[i].pBase.functionId; - if (functionId == TSDB_FUNC_TS) { - assert(*(TSKEY *)pCtx[i].aOutputBuf == pCtx[i].nStartQueryTimestamp); - } - } - } + return TSDB_CODE_SUCCESS; } -int32_t setOutputBufferForIntervalQuery(SMeterQuerySupportObj *pSupporter, SMeterQueryInfo *pMeterQueryInfo) { +/** + * set output buffer for different group + * @param pRuntimeEnv + * @param pDataBlockInfoEx + */ +void setExecutionContext(STableQuerySupportObj *pSupporter, SMeterQueryInfo *pMeterQueryInfo, int32_t meterIdx, + int32_t groupIdx, TSKEY nextKey) { SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; - tFilePage * pData = NULL; - - SQueryResultBuf* pResultBuf = pRuntimeEnv->pResultBuf; - - // in the first scan, new space needed for results - SIDList list = getDataBufPagesIdList(pResultBuf, pMeterQueryInfo->sid); - int32_t pageId = -1; - if (list.size == 0) { - pData = getNewDataBuf(pResultBuf, pMeterQueryInfo->sid, &pageId); - } else { - pData = getResultBufferPageById(pResultBuf, getLastPageId(&list)); + SWindowResInfo * pWindowResInfo = &pRuntimeEnv->windowResInfo; + int32_t GROUPRESULTID = 1; - if (pData->numOfElems >= pRuntimeEnv->numOfRowsPerPage) { - pData = getNewDataBuf(pResultBuf, pMeterQueryInfo->sid, &pageId); - if (pData != NULL) { - assert(pData->numOfElems == 0); // number of elements must be 0 for new allocated buffer - } - } + SWindowResult *pWindowRes = doSetTimeWindowFromKey(pRuntimeEnv, pWindowResInfo, (char *)&groupIdx, sizeof(groupIdx)); + if (pWindowRes == NULL) { + return; } - if (pData == NULL) { - return -1; + /* + * not assign result buffer yet, add new result buffer + * all group belong to one result set, and each group result has different group id so set the id to be one + */ + if (pWindowRes->pos.pageId == -1) { + if (addNewWindowResultBuf(pWindowRes, pRuntimeEnv->pResultBuf, GROUPRESULTID, pRuntimeEnv->numOfRowsPerPage) != + TSDB_CODE_SUCCESS) { + return; + } } - for (int32_t i = 0; i < pRuntimeEnv->pQuery->numOfOutputCols; ++i) { - pRuntimeEnv->pCtx[i].aOutputBuf = getOutputResPos(pRuntimeEnv, pData, pData->numOfElems, i); - pRuntimeEnv->pCtx[i].resultInfo = &pMeterQueryInfo->resultInfo[i]; - } + setWindowResOutputBuf(pRuntimeEnv, pWindowRes); + initCtxOutputBuf(pRuntimeEnv); - return TSDB_CODE_SUCCESS; + pMeterQueryInfo->lastKey = nextKey; + setAdditionalInfo(pSupporter, meterIdx, pMeterQueryInfo); } -int32_t setIntervalQueryExecutionContext(SMeterQuerySupportObj *pSupporter, int32_t meterIdx, - SMeterQueryInfo *pMeterQueryInfo) { - SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; +static void setWindowResOutputBuf(SQueryRuntimeEnv *pRuntimeEnv, SWindowResult *pResult) { + SQuery *pQuery = pRuntimeEnv->pQuery; - if (IS_MASTER_SCAN(pRuntimeEnv)) { - if (setOutputBufferForIntervalQuery(pSupporter, pMeterQueryInfo) != TSDB_CODE_SUCCESS) { - // not enough disk space or memory buffer for intermediate results - return -1; - } + // Note: pResult->pos[i]->numOfElems == 0, there is only fixed number of results for each group + for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { + SQLFunctionCtx *pCtx = &pRuntimeEnv->pCtx[i]; + pCtx->aOutputBuf = getPosInResultPage(pRuntimeEnv, i, pResult); - if (pMeterQueryInfo->lastResRows == 0) { - initCtxOutputBuf(pRuntimeEnv); + int32_t functionId = pQuery->pSelectExpr[i].pBase.functionId; + if (functionId == TSDB_FUNC_TOP || functionId == TSDB_FUNC_BOTTOM || functionId == TSDB_FUNC_DIFF) { + pCtx->ptsOutputBuf = pRuntimeEnv->pCtx[0].aOutputBuf; } - } else { - if (pMeterQueryInfo->reverseFillRes) { - setCtxOutputPointerForSupplementScan(pSupporter, pMeterQueryInfo); - } else { - /* - * set output buffer for reverse scan data blocks - * find the correct output position of existed results during - * - * If the master scan does not produce any results, new spaces needed to be allocated during supplement scan - */ - if (setOutputBufferForIntervalQuery(pSupporter, pMeterQueryInfo) != TSDB_CODE_SUCCESS) { - return -1; - } - } + /* + * set the output buffer information and intermediate buffer + * not all queries require the interResultBuf, such as COUNT + */ + pCtx->resultInfo = &pResult->resultInfo[i]; + + // set super table query flag + SResultInfo *pResInfo = GET_RES_INFO(pCtx); + pResInfo->superTableQ = pRuntimeEnv->stableQuery; } +} + +int32_t setAdditionalInfo(STableQuerySupportObj *pSupporter, int32_t meterIdx, SMeterQueryInfo *pMeterQueryInfo) { + SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; + assert(pMeterQueryInfo->lastKey > 0); vnodeSetTagValueInParam(pSupporter->pSidSet, pRuntimeEnv, pSupporter->pMeterSidExtInfo[meterIdx]); // both the master and supplement scan needs to set the correct ts comp start position - if (pSupporter->runtimeEnv.pTSBuf != NULL) { + if (pRuntimeEnv->pTSBuf != NULL) { if (pMeterQueryInfo->cur.vnodeIndex == -1) { pMeterQueryInfo->tag = pRuntimeEnv->pCtx[0].tag.i64Key; - tsBufGetElemStartPos(pSupporter->runtimeEnv.pTSBuf, 0, pMeterQueryInfo->tag); + tsBufGetElemStartPos(pRuntimeEnv->pTSBuf, 0, pMeterQueryInfo->tag); // keep the cursor info of current meter - pMeterQueryInfo->cur = pSupporter->runtimeEnv.pTSBuf->cur; + pMeterQueryInfo->cur = pRuntimeEnv->pTSBuf->cur; } else { - tsBufSetCursor(pSupporter->runtimeEnv.pTSBuf, &pMeterQueryInfo->cur); + tsBufSetCursor(pRuntimeEnv->pTSBuf, &pMeterQueryInfo->cur); } } return 0; } -//static void doApplyIntervalQueryOnBlock(SMeterQuerySupportObj *pSupporter, SMeterQueryInfo *pMeterQueryInfo, -// SBlockInfo *pBlockInfo, int64_t *pPrimaryCol, SField *pFields, -// __block_search_fn_t searchFn) { -// SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; -// SQuery * pQuery = pRuntimeEnv->pQuery; -// int32_t factor = GET_FORWARD_DIRECTION_FACTOR(pQuery->order.order); -// -// int64_t nextKey = -1; -// bool queryCompleted = false; -// -// while (1) { -// int32_t numOfRes = 0; -// int32_t steps = applyFunctionsOnBlock(pRuntimeEnv, pBlockInfo, pPrimaryCol, pFields, searchFn, &numOfRes); -// assert(steps > 0); -// -// // NOTE: in case of stable query, only ONE(or ZERO) row of pos generated for each query range -// if (pMeterQueryInfo->lastResRows == 0) { -// pMeterQueryInfo->lastResRows = numOfRes; -// } else { -// assert(pMeterQueryInfo->lastResRows == 1); -// } -// -// int32_t pos = pQuery->pos + steps * factor; -// -// // query does not reach the end of current block -// if ((pos < pBlockInfo->size && QUERY_IS_ASC_QUERY(pQuery)) || (pos >= 0 && !QUERY_IS_ASC_QUERY(pQuery))) { -// nextKey = pPrimaryCol[pos]; -// } else { -// assert((pQuery->lastKey > pBlockInfo->keyLast && QUERY_IS_ASC_QUERY(pQuery)) || -// (pQuery->lastKey < pBlockInfo->keyFirst && !QUERY_IS_ASC_QUERY(pQuery))); -// } -// -// // all data satisfy current query are checked, query completed -// if (QUERY_IS_ASC_QUERY(pQuery)) { -// queryCompleted = (nextKey > pQuery->ekey || pQuery->ekey <= pBlockInfo->keyLast); -// } else { -// queryCompleted = (nextKey < pQuery->ekey || pQuery->ekey >= pBlockInfo->keyFirst); -// } -// -// /* -// * 1. there may be more date that satisfy current query interval, other than -// * current block, we need to try next data blocks -// * 2. query completed, since reaches the upper bound of the main query range -// */ -// if (QUERY_IS_ASC_QUERY(pQuery)) { -// if (pQuery->lastKey > pBlockInfo->keyLast || pQuery->lastKey > pSupporter->rawEKey || -// nextKey > pSupporter->rawEKey) { -// /* -// * current interval query is completed, set query pos flag closed and -// * try next data block if pQuery->ekey == pSupporter->rawEKey, whole query is completed -// */ -// if (pQuery->lastKey > pBlockInfo->keyLast) { -// assert(pQuery->ekey >= pBlockInfo->keyLast); -// } -// -// if (pQuery->lastKey > pSupporter->rawEKey || nextKey > pSupporter->rawEKey) { -// /* whole query completed, save pos and abort */ -// assert(queryCompleted); -// saveResult(pSupporter, pMeterQueryInfo, pMeterQueryInfo->lastResRows); -// -// // save the pQuery->lastKey for retrieve data in cache, actually, there will be no qualified data in cache. -// saveIntervalQueryRange(pRuntimeEnv, pMeterQueryInfo); -// } else if (pQuery->ekey == pBlockInfo->keyLast) { -// /* current interval query is completed, set the next query range on other data blocks if exist */ -// int64_t prevEKey = pQuery->ekey; -// -// getAlignedIntervalQueryRange(pRuntimeEnv, pQuery->lastKey, pSupporter->rawSKey, pSupporter->rawEKey); -// saveIntervalQueryRange(pRuntimeEnv, pMeterQueryInfo); -// -// assert(queryCompleted && prevEKey < pQuery->skey); -// if (pMeterQueryInfo->lastResRows > 0) { -// saveResult(pSupporter, pMeterQueryInfo, pMeterQueryInfo->lastResRows); -// } -// } else { -// /* -// * Data that satisfy current query range may locate in current block and blocks that are directly right -// * next to current block. Therefore, we need to keep the query range(interval) unchanged until reaching -// * the direct next data block, while only forwards the pQuery->lastKey. -// * -// * With the information of the directly next data block, whether locates in cache or disk, -// * current interval query being completed or not can be decided. -// */ -// saveIntervalQueryRange(pRuntimeEnv, pMeterQueryInfo); -// assert(pQuery->lastKey > pBlockInfo->keyLast && pQuery->lastKey <= pQuery->ekey); -// -// /* -// * if current block is the last block of current file, we still close the pos flag, and -// * merge with other meters in the same group -// */ -// if (queryCompleted) { -// saveResult(pSupporter, pMeterQueryInfo, pMeterQueryInfo->lastResRows); -// } -// } -// -// break; -// } -// } else { -// if (pQuery->lastKey < pBlockInfo->keyFirst || pQuery->lastKey < pSupporter->rawEKey || -// nextKey < pSupporter->rawEKey) { -// if (pQuery->lastKey < pBlockInfo->keyFirst) { -// assert(pQuery->ekey <= pBlockInfo->keyFirst); -// } -// -// if (pQuery->lastKey < pSupporter->rawEKey || (nextKey < pSupporter->rawEKey && nextKey != -1)) { -// /* whole query completed, save pos and abort */ -// assert(queryCompleted); -// saveResult(pSupporter, pMeterQueryInfo, pMeterQueryInfo->lastResRows); -// -// /* -// * save the pQuery->lastKey for retrieve data in cache, actually, -// * there will be no qualified data in cache. -// */ -// saveIntervalQueryRange(pRuntimeEnv, pMeterQueryInfo); -// } else if (pQuery->ekey == pBlockInfo->keyFirst) { -// // current interval query is completed, set the next query range on other data blocks if exist -// int64_t prevEKey = pQuery->ekey; -// -// getAlignedIntervalQueryRange(pRuntimeEnv, pQuery->lastKey, pSupporter->rawSKey, pSupporter->rawEKey); -// saveIntervalQueryRange(pRuntimeEnv, pMeterQueryInfo); -// -// assert(queryCompleted && prevEKey > pQuery->skey); -// if (pMeterQueryInfo->lastResRows > 0) { -// saveResult(pSupporter, pMeterQueryInfo, pMeterQueryInfo->lastResRows); -// } -// } else { -// /* -// * Data that satisfy current query range may locate in current block and blocks that are -// * directly right next to current block. Therefore, we need to keep the query range(interval) -// * unchanged until reaching the direct next data block, while only forwards the pQuery->lastKey. -// * -// * With the information of the directly next data block, whether locates in cache or disk, -// * current interval query being completed or not can be decided. -// */ -// saveIntervalQueryRange(pRuntimeEnv, pMeterQueryInfo); -// assert(pQuery->lastKey < pBlockInfo->keyFirst && pQuery->lastKey >= pQuery->ekey); -// -// /* -// * if current block is the last block of current file, we still close the pos -// * flag, and merge with other meters in the same group -// */ -// if (queryCompleted) { -// saveResult(pSupporter, pMeterQueryInfo, pMeterQueryInfo->lastResRows); -// } -// } -// -// break; -// } -// } -// -// assert(queryCompleted); -// saveResult(pSupporter, pMeterQueryInfo, pMeterQueryInfo->lastResRows); -// -// assert((nextKey >= pQuery->lastKey && QUERY_IS_ASC_QUERY(pQuery)) || -// (nextKey <= pQuery->lastKey && !QUERY_IS_ASC_QUERY(pQuery))); -// -// /* still in the same block to query */ -// getAlignedIntervalQueryRange(pRuntimeEnv, nextKey, pSupporter->rawSKey, pSupporter->rawEKey); -// saveIntervalQueryRange(pRuntimeEnv, pMeterQueryInfo); -// -// int32_t newPos = searchFn((char *)pPrimaryCol, pBlockInfo->size, pQuery->skey, pQuery->order.order); -// assert(newPos == pQuery->pos + steps * factor); -// -// pQuery->pos = newPos; -// } -//} - -static void doApplyIntervalQueryOnBlock_rv(SMeterQuerySupportObj *pSupporter, SMeterQueryInfo *pMeterQueryInfo, - SBlockInfo *pBlockInfo, int64_t *pPrimaryCol, SField *pFields, - __block_search_fn_t searchFn) { - SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; - SQuery * pQuery = pRuntimeEnv->pQuery; - int32_t factor = GET_FORWARD_DIRECTION_FACTOR(pQuery->order.order); - - while (1) { - int64_t nextKey = -1; - int32_t numOfRes = 0; - - int32_t steps = applyFunctionsOnBlock(pRuntimeEnv, pBlockInfo, pPrimaryCol, pFields, searchFn, &numOfRes); - assert(steps > 0); - - // NOTE: in case of stable query, only ONE(or ZERO) row of result generated for each query range - if (pMeterQueryInfo->lastResRows == 0) { - pMeterQueryInfo->lastResRows = numOfRes; - } else { - assert(pMeterQueryInfo->lastResRows == 1); - } - - int32_t pos = pQuery->pos + steps * factor; - - // query does not reach the end of current block - if ((pos < pBlockInfo->size && QUERY_IS_ASC_QUERY(pQuery)) || (pos >= 0 && !QUERY_IS_ASC_QUERY(pQuery))) { - nextKey = pPrimaryCol[pos]; - } else { - assert((pQuery->lastKey > pBlockInfo->keyLast && QUERY_IS_ASC_QUERY(pQuery)) || - (pQuery->lastKey < pBlockInfo->keyFirst && !QUERY_IS_ASC_QUERY(pQuery))); - } - - // all data satisfy current query are checked, query completed - bool completed = false; - if (QUERY_IS_ASC_QUERY(pQuery)) { - completed = (pQuery->lastKey > pQuery->ekey); - } else { - completed = (pQuery->lastKey < pQuery->ekey); - } - - /* - * 1. there may be more date that satisfy current query interval, other than - * current block, we need to try next data blocks - * 2. query completed, since reaches the upper bound of the main query range - */ - if (!completed) { - /* - * Data that satisfy current query range may locate in current block and blocks that are directly right - * next to current block. Therefore, we need to keep the query range(interval) unchanged until reaching - * the direct next data block, while only forwards the pQuery->lastKey. - * - * With the information of the directly next data block, whether locates in cache or disk, - * current interval query being completed or not can be decided. - */ - saveIntervalQueryRange(pRuntimeEnv, pMeterQueryInfo); - - if (QUERY_IS_ASC_QUERY(pQuery)) { - assert(pQuery->lastKey > pBlockInfo->keyLast && pQuery->lastKey <= pQuery->ekey); - } else { - assert(pQuery->lastKey < pBlockInfo->keyFirst && pQuery->lastKey >= pQuery->ekey); - } - - break; - } - - assert(completed); - - // while the interval time window is less than the time range gap between two points, nextKey may be greater than - // pSupporter->rawEKey - if (pQuery->ekey == pSupporter->rawEKey || (nextKey > pSupporter->rawEKey && QUERY_IS_ASC_QUERY(pQuery)) || - (nextKey < pSupporter->rawEKey && !QUERY_IS_ASC_QUERY(pQuery))) { - /* whole query completed, save result and abort */ - saveResult(pSupporter, pMeterQueryInfo, pMeterQueryInfo->lastResRows); - - // save the pQuery->lastKey for retrieve data in cache, actually, there will be no qualified data in cache. - saveIntervalQueryRange(pRuntimeEnv, pMeterQueryInfo); - - return; - } else if ((QUERY_IS_ASC_QUERY(pQuery) && pQuery->ekey == pBlockInfo->keyLast) || - (!QUERY_IS_ASC_QUERY(pQuery) && pQuery->ekey == pBlockInfo->keyFirst)) { - /* current interval query is completed, set the next query range on other data blocks if exist */ - saveIntervalQueryRange(pRuntimeEnv, pMeterQueryInfo); - return; - } - - saveResult(pSupporter, pMeterQueryInfo, pMeterQueryInfo->lastResRows); - - assert(pos >= 0 && pos < pBlockInfo->size); - assert((nextKey >= pQuery->lastKey && QUERY_IS_ASC_QUERY(pQuery)) || - (nextKey <= pQuery->lastKey && !QUERY_IS_ASC_QUERY(pQuery))); - - /* still in the same block to query */ - getAlignedIntervalQueryRange(pRuntimeEnv, nextKey, pSupporter->rawSKey, pSupporter->rawEKey); - saveIntervalQueryRange(pRuntimeEnv, pMeterQueryInfo); - - int32_t newPos = searchFn((char *)pPrimaryCol, pBlockInfo->size, pQuery->skey, pQuery->order.order); - assert(newPos == pQuery->pos + steps * factor); - - pQuery->pos = newPos; - } - -} -int64_t getNextAccessedKeyInData(SQuery *pQuery, int64_t *pPrimaryCol, SBlockInfo *pBlockInfo, int32_t blockStatus) { - assert(pQuery->pos >= 0 && pQuery->pos <= pBlockInfo->size - 1); - - TSKEY key = -1; - if (IS_DATA_BLOCK_LOADED(blockStatus)) { - key = pPrimaryCol[pQuery->pos]; - } else { - assert(pQuery->pos == pBlockInfo->size - 1 || pQuery->pos == 0); - key = QUERY_IS_ASC_QUERY(pQuery) ? pBlockInfo->keyFirst : pBlockInfo->keyLast; - } - - assert((key >= pQuery->skey && QUERY_IS_ASC_QUERY(pQuery)) || (key <= pQuery->skey && !QUERY_IS_ASC_QUERY(pQuery))); - return key; -} - /* * There are two cases to handle: * @@ -7322,42 +7120,61 @@ int64_t getNextAccessedKeyInData(SQuery *pQuery, int64_t *pPrimaryCol, SBlockInf * merged during merge stage. In this case, we need the pMeterQueryInfo->lastResRows to decide if there * is a previous result generated or not. */ -void setIntervalQueryRange(SMeterQueryInfo *pMeterQueryInfo, SMeterQuerySupportObj *pSupporter, TSKEY key) { +void setIntervalQueryRange(SMeterQueryInfo *pMeterQueryInfo, STableQuerySupportObj *pSupporter, TSKEY key) { SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; SQuery * pQuery = pRuntimeEnv->pQuery; if (pMeterQueryInfo->queryRangeSet) { - assert((QUERY_IS_ASC_QUERY(pQuery) && pQuery->lastKey >= pQuery->skey) || - (!QUERY_IS_ASC_QUERY(pQuery) && pQuery->lastKey <= pQuery->skey)); - - if ((pQuery->ekey < key && QUERY_IS_ASC_QUERY(pQuery)) || (pQuery->ekey > key && !QUERY_IS_ASC_QUERY(pQuery))) { - /* - * last query on this block of the meter is done, start next interval on this block - * otherwise, keep the previous query range and proceed - */ - getAlignedIntervalQueryRange(pRuntimeEnv, key, pSupporter->rawSKey, pSupporter->rawEKey); - saveIntervalQueryRange(pRuntimeEnv, pMeterQueryInfo); - - // previous query does not be closed, save the results and close it - if (pMeterQueryInfo->lastResRows > 0) { - saveResult(pSupporter, pMeterQueryInfo, pMeterQueryInfo->lastResRows); - } - } else { - /* current query not completed, continue. do nothing with respect to query range, */ - } + pQuery->lastKey = key; + pMeterQueryInfo->lastKey = key; } else { pQuery->skey = key; - assert(pMeterQueryInfo->lastResRows == 0); + STimeWindow win = {.skey = key, pSupporter->rawEKey}; + // for too small query range, no data in this interval. if ((QUERY_IS_ASC_QUERY(pQuery) && (pQuery->ekey < pQuery->skey)) || (!QUERY_IS_ASC_QUERY(pQuery) && (pQuery->skey < pQuery->ekey))) { - // for too small query range, no data in this interval. return; } - getAlignedIntervalQueryRange(pRuntimeEnv, pQuery->skey, pSupporter->rawSKey, pSupporter->rawEKey); - saveIntervalQueryRange(pRuntimeEnv, pMeterQueryInfo); + /** + * In handling the both ascending and descending order super table query, we need to find the first qualified + * timestamp of this table, and then set the first qualified start timestamp. + * In ascending query, key is the first qualified timestamp. However, in the descending order query, additional + * operations involve. + */ + if (!QUERY_IS_ASC_QUERY(pQuery)) { + TSKEY k = getGreaterEqualTimestamp(pRuntimeEnv); + win.skey = k; + win.ekey = key; // current key is the last timestamp value that are contained in query time window + + SPositionInfo p = {.fileId = pQuery->fileId, .slot = pQuery->slot, .pos = pQuery->pos}; + loadRequiredBlockIntoMem(pRuntimeEnv, &p); + } + + TSKEY skey1, ekey1; + TSKEY windowSKey = 0, windowEKey = 0; + + SWindowResInfo *pWindowResInfo = &pMeterQueryInfo->windowResInfo; + + doGetAlignedIntervalQueryRangeImpl(pQuery, win.skey, win.skey, win.ekey, &skey1, &ekey1, &windowSKey, &windowEKey); + pWindowResInfo->startTime = windowSKey; // windowSKey may be 0 in case of 1970 timestamp + // assert(pWindowResInfo->startTime > 0); + + if (pWindowResInfo->prevSKey == 0) { + if (QUERY_IS_ASC_QUERY(pQuery)) { + pWindowResInfo->prevSKey = windowSKey; + } else { + assert(win.ekey == pQuery->skey); + pWindowResInfo->prevSKey = windowSKey + ((win.ekey - windowSKey) / pQuery->slidingTime) * pQuery->slidingTime; + } + } + pMeterQueryInfo->queryRangeSet = 1; + pMeterQueryInfo->lastKey = pQuery->skey; + pMeterQueryInfo->skey = pQuery->skey; + + pQuery->lastKey = pQuery->skey; } } @@ -7415,7 +7232,7 @@ int32_t LoadDatablockOnDemand(SCompBlock *pBlock, SField **pFields, uint8_t *blk if (((pQuery->lastKey <= pBlock->keyFirst && pQuery->ekey >= pBlock->keyLast && QUERY_IS_ASC_QUERY(pQuery)) || (pQuery->ekey <= pBlock->keyFirst && pQuery->lastKey >= pBlock->keyLast && !QUERY_IS_ASC_QUERY(pQuery))) && onDemand) { - int32_t req = 0; + uint32_t req = 0; if (pQuery->numOfFilterCols > 0) { req = BLK_DATA_ALL_NEEDED; } else { @@ -7425,7 +7242,7 @@ int32_t LoadDatablockOnDemand(SCompBlock *pBlock, SField **pFields, uint8_t *blk pQuery->pSelectExpr[i].pBase.colInfo.colId, *blkStatus); } - if (pRuntimeEnv->pTSBuf > 0 || (pQuery->nAggTimeInterval > 0 && pQuery->slidingTime > 0)) { + if (pRuntimeEnv->pTSBuf > 0 || isIntervalQuery(pQuery)) { req |= BLK_DATA_ALL_NEEDED; } } @@ -7487,9 +7304,8 @@ int32_t LoadDatablockOnDemand(SCompBlock *pBlock, SField **pFields, uint8_t *blk /* find first qualified record position in this block */ if (loadTS) { - /* find first qualified record position in this block */ - pQuery->pos = - searchFn(pRuntimeEnv->primaryColBuffer->data, pBlock->numOfPoints, pQuery->lastKey, pQuery->order.order); + pQuery->pos = searchFn((char *)primaryKeys, pBlock->numOfPoints, pQuery->lastKey, pQuery->order.order); + /* boundary timestamp check */ assert(pBlock->keyFirst == primaryKeys[0] && pBlock->keyLast == primaryKeys[pBlock->numOfPoints - 1]); } @@ -7509,121 +7325,15 @@ int32_t LoadDatablockOnDemand(SCompBlock *pBlock, SField **pFields, uint8_t *blk } bool onDemandLoadDatablock(SQuery *pQuery, int16_t queryRangeSet) { - return (pQuery->nAggTimeInterval == 0) || ((queryRangeSet == 1) && (pQuery->nAggTimeInterval > 0)); -} - -static void validateResultBuf(SMeterQuerySupportObj *pSupporter, SMeterQueryInfo *pMeterQueryInfo) { - SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; - SQuery * pQuery = pSupporter->runtimeEnv.pQuery; - SQueryResultBuf* pResultBuf = pRuntimeEnv->pResultBuf; - - SIDList list = getDataBufPagesIdList(pResultBuf, pMeterQueryInfo->sid); - int32_t id = getLastPageId(&list); - - tFilePage* newOutput = getResultBufferPageById(pResultBuf, id); - for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { - assert(pRuntimeEnv->pCtx[i].aOutputBuf - newOutput->data < DEFAULT_INTERN_BUF_SIZE); - } -} - -int32_t saveResult(SMeterQuerySupportObj *pSupporter, SMeterQueryInfo *pMeterQueryInfo, int32_t numOfResult) { - SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; - SQuery * pQuery = pRuntimeEnv->pQuery; - - // no results generated, do nothing for master scan - if (numOfResult <= 0) { - if (IS_MASTER_SCAN(pRuntimeEnv)) { - return TSDB_CODE_SUCCESS; - } else { - /* - * There is a case that no result generated during the the supplement scan, and during the main - * scan also no result generated. The index can be backwards moved. - * - * However, if during the main scan, there is a result generated, such as applies count to timestamp, which - * always generates a result, but applies last query to a NULL column may fail to generate results during the - * supplement scan. - * - * NOTE: - * nStartQueryTimestamp is the actually timestamp of current interval, if the actually interval timestamp - * equals to the recorded timestamp that is acquired during the master scan, backwards one step even - * there is no results during the supplementary scan. - */ - TSKEY ts = *(TSKEY *)pRuntimeEnv->pCtx[0].aOutputBuf; - if (ts == pRuntimeEnv->pCtx[0].nStartQueryTimestamp && pMeterQueryInfo->reverseIndex > 0) { - assert(pMeterQueryInfo->numOfRes >= 0 && pMeterQueryInfo->reverseIndex > 0 && - pMeterQueryInfo->reverseIndex <= pMeterQueryInfo->numOfRes); - - // backward one step from the previous position, the start position is (pMeterQueryInfo->numOfRows-1); - pMeterQueryInfo->reverseIndex -= 1; - setCtxOutputPointerForSupplementScan(pSupporter, pMeterQueryInfo); - } - - return TSDB_CODE_SUCCESS; - } - } - - assert(pMeterQueryInfo->lastResRows == 1); - numOfResult = 1; - pMeterQueryInfo->lastResRows = 0; - - if (IS_SUPPLEMENT_SCAN(pRuntimeEnv) && pMeterQueryInfo->reverseFillRes == 1) { - assert(pMeterQueryInfo->numOfRes > 0 && pMeterQueryInfo->reverseIndex > 0 && - pMeterQueryInfo->reverseIndex <= pMeterQueryInfo->numOfRes); - // backward one step from the previous position, the start position is (pMeterQueryInfo->numOfRows-1); - pMeterQueryInfo->reverseIndex -= 1; - setCtxOutputPointerForSupplementScan(pSupporter, pMeterQueryInfo); - } else { - SIDList list = getDataBufPagesIdList(pRuntimeEnv->pResultBuf, pMeterQueryInfo->sid); - - int32_t pageId = getLastPageId(&list); - tFilePage* pData = getResultBufferPageById(pRuntimeEnv->pResultBuf, pageId); - - // in handling records occuring around '1970-01-01', the aligned start timestamp may be 0. - TSKEY ts = *(TSKEY *)getOutputResPos(pRuntimeEnv, pData, pData->numOfElems, 0); - - SMeterObj *pMeterObj = pRuntimeEnv->pMeterObj; - qTrace("QInfo:%p vid:%d sid:%d id:%s, save results, ts:%" PRId64 ", total:%d", GET_QINFO_ADDR(pQuery), - pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, ts, pMeterQueryInfo->numOfRes + 1); - - pData->numOfElems += numOfResult; - pMeterQueryInfo->numOfRes += numOfResult; - assert(pData->numOfElems <= pRuntimeEnv->numOfRowsPerPage); - - if (setOutputBufferForIntervalQuery(pSupporter, pMeterQueryInfo) != TSDB_CODE_SUCCESS) { - return -1; - } - - for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { - resetResultInfo(&pMeterQueryInfo->resultInfo[i]); - } - - validateResultBuf(pSupporter, pMeterQueryInfo); - initCtxOutputBuf(pRuntimeEnv); -#if 0 - SSchema sc[TSDB_MAX_COLUMNS] = {0}; - sc[0].type = TSDB_DATA_TYPE_BIGINT; - sc[0].bytes = 8; - - sc[1].type = TSDB_DATA_TYPE_BIGINT; - sc[1].bytes = 8; - - UNUSED(sc); - SColumnModel *cm = createColumnModel(sc, pQuery->numOfOutputCols, pRuntimeEnv->numOfRowsPerPage); - -// if (outputPage->numOfElems + numOfResult >= pRuntimeEnv->numOfRowsPerPage) - tColModelDisplay(cm, outputPage->data, outputPage->numOfElems, pRuntimeEnv->numOfRowsPerPage); -#endif - } - - return TSDB_CODE_SUCCESS; + return (pQuery->intervalTime == 0) || ((queryRangeSet == 1) && (isIntervalQuery(pQuery))); } -static int32_t getNumOfSubset(SMeterQuerySupportObj *pSupporter) { +static int32_t getNumOfSubset(STableQuerySupportObj *pSupporter) { SQuery *pQuery = pSupporter->runtimeEnv.pQuery; int32_t totalSubset = 0; - if (isGroupbyNormalCol(pQuery->pGroupbyExpr) || (pQuery->nAggTimeInterval > 0 && pQuery->slidingTime > 0)) { - totalSubset = numOfClosedSlidingWindow(&pSupporter->runtimeEnv.swindowResInfo); + if (isGroupbyNormalCol(pQuery->pGroupbyExpr) || (isIntervalQuery(pQuery))) { + totalSubset = numOfClosedTimeWindow(&pSupporter->runtimeEnv.windowResInfo); } else { totalSubset = pSupporter->pSidSet->numOfSubSet; } @@ -7631,26 +7341,26 @@ static int32_t getNumOfSubset(SMeterQuerySupportObj *pSupporter) { return totalSubset; } -static int32_t doCopyFromGroupBuf(SMeterQuerySupportObj *pSupporter, SOutputRes *result, int32_t orderType) { +static int32_t doCopyToSData(STableQuerySupportObj *pSupporter, SWindowResult *result, int32_t orderType) { SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; SQuery * pQuery = pRuntimeEnv->pQuery; int32_t numOfResult = 0; int32_t startIdx = 0; - int32_t forward = 1; - - dTrace("QInfo:%p start to copy data to dest buf", GET_QINFO_ADDR(pSupporter->runtimeEnv.pQuery)); + int32_t step = -1; + dTrace("QInfo:%p start to copy data from windowResInfo to pQuery buf", GET_QINFO_ADDR(pQuery)); int32_t totalSubset = getNumOfSubset(pSupporter); if (orderType == TSQL_SO_ASC) { startIdx = pSupporter->subgroupIdx; - } else { // desc + step = 1; + } else { // desc order copy all data startIdx = totalSubset - pSupporter->subgroupIdx - 1; - forward = -1; + step = -1; } - for (int32_t i = startIdx; (i < totalSubset) && (i >= 0); i += forward) { + for (int32_t i = startIdx; (i < totalSubset) && (i >= 0); i += step) { if (result[i].numOfRows == 0) { pSupporter->offset = 0; pSupporter->subgroupIdx += 1; @@ -7662,8 +7372,11 @@ static int32_t doCopyFromGroupBuf(SMeterQuerySupportObj *pSupporter, SOutputRes int32_t numOfRowsToCopy = result[i].numOfRows - pSupporter->offset; int32_t oldOffset = pSupporter->offset; + /* + * current output space is not enough to keep all the result data of this group, only copy partial results + * to SQuery object's result buffer + */ if (numOfRowsToCopy > pQuery->pointsToRead - numOfResult) { - // current output space is not enough for the keep the data of this group numOfRowsToCopy = pQuery->pointsToRead - numOfResult; pSupporter->offset += numOfRowsToCopy; } else { @@ -7672,10 +7385,11 @@ static int32_t doCopyFromGroupBuf(SMeterQuerySupportObj *pSupporter, SOutputRes } for (int32_t j = 0; j < pQuery->numOfOutputCols; ++j) { - int32_t elemSize = pRuntimeEnv->pCtx[j].outputBytes; - char * outputBuf = pQuery->sdata[j]->data + numOfResult * elemSize; - char* p = getPosInResultPage(pRuntimeEnv, j, &result[i]); - memcpy(outputBuf, p + oldOffset * elemSize, elemSize * numOfRowsToCopy); + int32_t size = pRuntimeEnv->pCtx[j].outputBytes; + + char *out = pQuery->sdata[j]->data + numOfResult * size; + char *in = getPosInResultPage(pRuntimeEnv, j, &result[i]); + memcpy(out, in + oldOffset * size, size * numOfRowsToCopy); } numOfResult += numOfRowsToCopy; @@ -7684,7 +7398,7 @@ static int32_t doCopyFromGroupBuf(SMeterQuerySupportObj *pSupporter, SOutputRes } } - dTrace("QInfo:%p done copy data to dst buf", GET_QINFO_ADDR(pSupporter->runtimeEnv.pQuery)); + dTrace("QInfo:%p copy data to SQuery buf completed", GET_QINFO_ADDR(pQuery)); #ifdef _DEBUG_VIEW displayInterResult(pQuery->sdata, pQuery, numOfResult); @@ -7693,58 +7407,63 @@ static int32_t doCopyFromGroupBuf(SMeterQuerySupportObj *pSupporter, SOutputRes } /** - * copyFromGroupBuf support copy data in ascending/descending order + * copyFromWindowResToSData support copy data in ascending/descending order + * For interval query of both super table and table, copy the data in ascending order, since the output results are + * ordered in SWindowResutl already. While handling the group by query for both table and super table, + * all group result are completed already. + * * @param pQInfo * @param result */ -void copyFromGroupBuf(SQInfo *pQInfo, SOutputRes *result) { +void copyFromWindowResToSData(SQInfo *pQInfo, SWindowResult *result) { SQuery * pQuery = &pQInfo->query; - SMeterQuerySupportObj *pSupporter = pQInfo->pMeterQuerySupporter; + STableQuerySupportObj *pSupporter = pQInfo->pTableQuerySupporter; int32_t orderType = (pQuery->pGroupbyExpr != NULL) ? pQuery->pGroupbyExpr->orderType : TSQL_SO_ASC; - int32_t numOfResult = doCopyFromGroupBuf(pSupporter, result, orderType); + int32_t numOfResult = doCopyToSData(pSupporter, result, orderType); pQuery->pointsRead += numOfResult; assert(pQuery->pointsRead <= pQuery->pointsToRead); } -static void applyIntervalQueryOnBlock(SMeterQuerySupportObj *pSupporter, SMeterDataInfo *pMeterDataInfo, - SBlockInfo *pBlockInfo, int32_t blockStatus, SField *pFields, - __block_search_fn_t searchFn) { - SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; - SQuery * pQuery = pRuntimeEnv->pQuery; - SMeterQueryInfo * pMeterQueryInfo = pMeterDataInfo->pMeterQInfo; +static void updateWindowResNumOfRes(SQueryRuntimeEnv *pRuntimeEnv, SMeterDataInfo *pMeterDataInfo) { + SQuery *pQuery = pRuntimeEnv->pQuery; - int64_t* pPrimaryKey = (int64_t*) pRuntimeEnv->primaryColBuffer->data; - /* - * for each block, we need to handle the previous query, since the determination of previous query being completed - * or not is based on the start key of current block. - */ - TSKEY key = getNextAccessedKeyInData(pQuery, pPrimaryKey, pBlockInfo, blockStatus); - setIntervalQueryRange(pMeterDataInfo->pMeterQInfo, pSupporter, key); + // update the number of result for each, only update the number of rows for the corresponding window result. + if (pQuery->intervalTime == 0) { + int32_t g = pMeterDataInfo->groupIdx; + assert(pRuntimeEnv->windowResInfo.size > 0); - if (((pQuery->skey > pQuery->ekey) && QUERY_IS_ASC_QUERY(pQuery)) || - ((pQuery->skey < pQuery->ekey) && !QUERY_IS_ASC_QUERY(pQuery))) { - return; + SWindowResult *pWindowRes = doSetTimeWindowFromKey(pRuntimeEnv, &pRuntimeEnv->windowResInfo, (char *)&g, sizeof(g)); + if (pWindowRes->numOfRows == 0) { + pWindowRes->numOfRows = getNumOfResult(pRuntimeEnv); + } } +} + +void stableApplyFunctionsOnBlock(STableQuerySupportObj *pSupporter, SMeterDataInfo *pMeterDataInfo, + SBlockInfo *pBlockInfo, SField *pFields, __block_search_fn_t searchFn) { + SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; + SQuery * pQuery = pRuntimeEnv->pQuery; + SMeterQueryInfo * pMeterQueryInfo = pMeterDataInfo->pMeterQInfo; + SWindowResInfo * pWindowResInfo = &pMeterQueryInfo->windowResInfo; - if (((pBlockInfo->keyLast < pQuery->ekey) && QUERY_IS_ASC_QUERY(pQuery)) || - ((pBlockInfo->keyFirst > pQuery->ekey) && !QUERY_IS_ASC_QUERY(pQuery))) { - int32_t numOfRes = 0; - /* current block is included in this interval */ - int32_t steps = applyFunctionsOnBlock(pRuntimeEnv, pBlockInfo, pPrimaryKey, pFields, searchFn, &numOfRes); - assert(numOfRes <= 1 && numOfRes >= 0 && steps > 0); + int64_t *pPrimaryKey = (int64_t *)pRuntimeEnv->primaryColBuffer->data; - if (pMeterQueryInfo->lastResRows == 0) { - pMeterQueryInfo->lastResRows = numOfRes; - } else { - assert(pMeterQueryInfo->lastResRows == 1); - } + int32_t forwardStep = + getNumOfRowsInTimeWindow(pQuery, pBlockInfo, pPrimaryKey, pQuery->pos, pQuery->ekey, searchFn, true); - saveIntervalQueryRange(pRuntimeEnv, pMeterQueryInfo); + int32_t numOfRes = 0; + if (pQuery->numOfFilterCols > 0 || pRuntimeEnv->pTSBuf != NULL) { + numOfRes = rowwiseApplyAllFunctions(pRuntimeEnv, &forwardStep, pFields, pBlockInfo, pWindowResInfo); } else { - doApplyIntervalQueryOnBlock_rv(pSupporter, pMeterQueryInfo, pBlockInfo, pPrimaryKey, pFields, searchFn); + numOfRes = blockwiseApplyAllFunctions(pRuntimeEnv, forwardStep, pFields, pBlockInfo, pWindowResInfo, searchFn); } + + assert(numOfRes >= 0); + + updateWindowResNumOfRes(pRuntimeEnv, pMeterDataInfo); + updatelastkey(pQuery, pMeterQueryInfo); } // we need to split the refstatsult into different packages. @@ -7758,7 +7477,7 @@ int32_t vnodeGetResultSize(void *thandle, int32_t *numOfRows) { * * TODO handle the case that the file is too large to send back one time */ - if (pQInfo->pMeterQuerySupporter != NULL && isTSCompQuery(pQuery) && (*numOfRows) > 0) { + if (pQInfo->pTableQuerySupporter != NULL && isTSCompQuery(pQuery) && (*numOfRows) > 0) { struct stat fstat; if (stat(pQuery->sdata[0]->data, &fstat) == 0) { *numOfRows = fstat.st_size; @@ -7779,7 +7498,7 @@ int64_t vnodeGetOffsetVal(void *thandle) { bool vnodeHasRemainResults(void *handle) { SQInfo * pQInfo = (SQInfo *)handle; - SMeterQuerySupportObj *pSupporter = pQInfo->pMeterQuerySupporter; + STableQuerySupportObj *pSupporter = pQInfo->pTableQuerySupporter; if (pSupporter == NULL || pQInfo->query.interpoType == TSDB_INTERPO_NONE) { return false; @@ -7803,10 +7522,10 @@ bool vnodeHasRemainResults(void *handle) { // query has completed if (Q_STATUS_EQUAL(pQuery->over, QUERY_COMPLETED | QUERY_NO_DATA_TO_CHECK)) { - TSKEY ekey = taosGetRevisedEndKey(pSupporter->rawEKey, pQuery->order.order, pQuery->nAggTimeInterval, + TSKEY ekey = taosGetRevisedEndKey(pSupporter->rawEKey, pQuery->order.order, pQuery->intervalTime, pQuery->intervalTimeUnit, pQuery->precision); int32_t numOfTotal = taosGetNumOfResultWithInterpo(pInterpoInfo, (TSKEY *)pRuntimeEnv->pInterpoBuf[0]->data, - remain, pQuery->nAggTimeInterval, ekey, pQuery->pointsToRead); + remain, pQuery->intervalTime, ekey, pQuery->pointsToRead); return numOfTotal > 0; } @@ -7817,7 +7536,7 @@ bool vnodeHasRemainResults(void *handle) { static int32_t resultInterpolate(SQInfo *pQInfo, tFilePage **data, tFilePage **pDataSrc, int32_t numOfRows, int32_t outputRows) { SQuery * pQuery = &pQInfo->query; - SQueryRuntimeEnv *pRuntimeEnv = &pQInfo->pMeterQuerySupporter->runtimeEnv; + SQueryRuntimeEnv *pRuntimeEnv = &pQInfo->pTableQuerySupporter->runtimeEnv; assert(pRuntimeEnv->pCtx[0].outputBytes == TSDB_KEYSIZE); @@ -7839,7 +7558,7 @@ static int32_t resultInterpolate(SQInfo *pQInfo, tFilePage **data, tFilePage **p } int32_t numOfRes = taosDoInterpoResult(&pRuntimeEnv->interpoInfo, pQuery->interpoType, data, numOfRows, outputRows, - pQuery->nAggTimeInterval, (int64_t *)pDataSrc[0]->data, pModel, srcData, + pQuery->intervalTime, (int64_t *)pDataSrc[0]->data, pModel, srcData, pQuery->defaultVal, functions, pRuntimeEnv->pMeterObj->pointsPerFileBlock); destroyColumnModel(pModel); @@ -7907,18 +7626,17 @@ int32_t vnodeCopyQueryResultToMsg(void *handle, char *data, int32_t numOfRows) { int32_t vnodeQueryResultInterpolate(SQInfo *pQInfo, tFilePage **pDst, tFilePage **pDataSrc, int32_t numOfRows, int32_t *numOfInterpo) { - SMeterQuerySupportObj *pSupporter = pQInfo->pMeterQuerySupporter; + STableQuerySupportObj *pSupporter = pQInfo->pTableQuerySupporter; SQueryRuntimeEnv * pRuntimeEnv = &pSupporter->runtimeEnv; SQuery * pQuery = pRuntimeEnv->pQuery; while (1) { numOfRows = taosNumOfRemainPoints(&pRuntimeEnv->interpoInfo); - TSKEY ekey = taosGetRevisedEndKey(pSupporter->rawEKey, pQuery->order.order, pQuery->nAggTimeInterval, + TSKEY ekey = taosGetRevisedEndKey(pSupporter->rawEKey, pQuery->order.order, pQuery->intervalTime, pQuery->intervalTimeUnit, pQuery->precision); - int32_t numOfFinalRows = - taosGetNumOfResultWithInterpo(&pRuntimeEnv->interpoInfo, (TSKEY *)pDataSrc[0]->data, numOfRows, - pQuery->nAggTimeInterval, ekey, pQuery->pointsToRead); + int32_t numOfFinalRows = taosGetNumOfResultWithInterpo(&pRuntimeEnv->interpoInfo, (TSKEY *)pDataSrc[0]->data, + numOfRows, pQuery->intervalTime, ekey, pQuery->pointsToRead); int32_t ret = resultInterpolate(pQInfo, pDst, pDataSrc, numOfRows, numOfFinalRows); assert(ret == numOfFinalRows); @@ -7949,7 +7667,7 @@ int32_t vnodeQueryResultInterpolate(SQInfo *pQInfo, tFilePage **pDst, tFilePage } } -void vnodePrintQueryStatistics(SMeterQuerySupportObj *pSupporter) { +void vnodePrintQueryStatistics(STableQuerySupportObj *pSupporter) { SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; SQuery *pQuery = pRuntimeEnv->pQuery; diff --git a/src/vnode/detail/src/vnodeQueryProcess.c b/src/vnode/detail/src/vnodeQueryProcess.c index c243a78e837cbc0f1ad60d83a7786da3aae54d3a..ae51365918b142e392dcffa27a6b071543f3d02e 100644 --- a/src/vnode/detail/src/vnodeQueryProcess.c +++ b/src/vnode/detail/src/vnodeQueryProcess.c @@ -26,8 +26,9 @@ #include "vnodeQueryImpl.h" -#define ALL_CACHE_BLOCKS_CHECKED(q) \ - (((q)->slot == (q)->currentSlot && QUERY_IS_ASC_QUERY(q)) || ((q)->slot == (q)->firstSlot && (!QUERY_IS_ASC_QUERY(q)))) +#define ALL_CACHE_BLOCKS_CHECKED(q) \ + (((q)->slot == (q)->currentSlot && QUERY_IS_ASC_QUERY(q)) || \ + ((q)->slot == (q)->firstSlot && (!QUERY_IS_ASC_QUERY(q)))) #define FORWARD_CACHE_BLOCK_CHECK_SLOT(slot, step, maxblocks) (slot) = ((slot) + (step) + (maxblocks)) % (maxblocks); @@ -47,23 +48,10 @@ static bool isGroupbyEachTable(SSqlGroupbyExpr *pGroupbyExpr, tSidSet *pSidset) return false; } -static bool doCheckWithPrevQueryRange(SQInfo *pQInfo, TSKEY nextKey, SMeterDataInfo *pMeterInfo) { - SMeterQuerySupportObj *pSupporter = pQInfo->pMeterQuerySupporter; - SQuery * pQuery = &pQInfo->query; - SMeterObj * pMeterObj = pMeterInfo->pMeterObj; - - /* no data for current query */ +static bool doCheckWithPrevQueryRange(SQuery *pQuery, TSKEY nextKey) { if ((nextKey > pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) || (nextKey < pQuery->ekey && !QUERY_IS_ASC_QUERY(pQuery))) { - if (((nextKey > pSupporter->rawEKey) && QUERY_IS_ASC_QUERY(pQuery)) || - ((nextKey < pSupporter->rawEKey) && (!QUERY_IS_ASC_QUERY(pQuery)))) { - dTrace("QInfo:%p vid:%d sid:%d id:%s, no data qualified in block, ignore", pQInfo, pMeterObj->vnode, - pMeterObj->sid, pMeterObj->meterId); - - return false; - } else { // in case of interval query, forward the query range - setIntervalQueryRange(pMeterInfo->pMeterQInfo, pSupporter, nextKey); - } + return false; } return true; @@ -86,8 +74,8 @@ static void setStartPositionForCacheBlock(SQuery *pQuery, SCacheBlock *pBlock, b } static void enableExecutionForNextTable(SQueryRuntimeEnv *pRuntimeEnv) { - SQuery* pQuery = pRuntimeEnv->pQuery; - + SQuery *pQuery = pRuntimeEnv->pQuery; + for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { SResultInfo *pResInfo = GET_RES_INFO(&pRuntimeEnv->pCtx[i]); if (pResInfo != NULL) { @@ -96,10 +84,10 @@ static void enableExecutionForNextTable(SQueryRuntimeEnv *pRuntimeEnv) { } } -static void queryOnMultiDataCache(SQInfo *pQInfo, SMeterDataInfo *pMeterInfo) { +static void queryOnMultiDataCache(SQInfo *pQInfo, SMeterDataInfo *pMeterDataInfo) { SQuery * pQuery = &pQInfo->query; - SMeterQuerySupportObj *pSupporter = pQInfo->pMeterQuerySupporter; - SQueryRuntimeEnv * pRuntimeEnv = &pQInfo->pMeterQuerySupporter->runtimeEnv; + STableQuerySupportObj *pSupporter = pQInfo->pTableQuerySupporter; + SQueryRuntimeEnv * pRuntimeEnv = &pQInfo->pTableQuerySupporter->runtimeEnv; SMeterSidExtInfo **pMeterSidExtInfo = pSupporter->pMeterSidExtInfo; @@ -131,17 +119,18 @@ static void queryOnMultiDataCache(SQInfo *pQInfo, SMeterDataInfo *pMeterInfo) { pQInfo->pObj = pMeterObj; pRuntimeEnv->pMeterObj = pMeterObj; - if (pMeterInfo[k].pMeterQInfo == NULL) { - pMeterInfo[k].pMeterQInfo = createMeterQueryInfo(pQuery, pMeterObj->sid, pSupporter->rawSKey, pSupporter->rawEKey); + if (pMeterDataInfo[k].pMeterQInfo == NULL) { + pMeterDataInfo[k].pMeterQInfo = + createMeterQueryInfo(pSupporter, pMeterObj->sid, pSupporter->rawSKey, pSupporter->rawEKey); } - if (pMeterInfo[k].pMeterObj == NULL) { // no data in disk for this meter, set its pointer - setMeterDataInfo(&pMeterInfo[k], pMeterObj, k, groupIdx); + if (pMeterDataInfo[k].pMeterObj == NULL) { // no data in disk for this meter, set its pointer + setMeterDataInfo(&pMeterDataInfo[k], pMeterObj, k, groupIdx); } - assert(pMeterInfo[k].meterOrderIdx == k && pMeterObj == pMeterInfo[k].pMeterObj); + assert(pMeterDataInfo[k].meterOrderIdx == k && pMeterObj == pMeterDataInfo[k].pMeterObj); - SMeterQueryInfo *pMeterQueryInfo = pMeterInfo[k].pMeterQInfo; + SMeterQueryInfo *pMeterQueryInfo = pMeterDataInfo[k].pMeterQInfo; restoreIntervalQueryRange(pRuntimeEnv, pMeterQueryInfo); /* @@ -154,29 +143,18 @@ static void queryOnMultiDataCache(SQInfo *pQInfo, SMeterDataInfo *pMeterInfo) { vnodeUpdateQueryColumnIndex(pQuery, pMeterObj); vnodeUpdateFilterColumnIndex(pQuery); - if (pQuery->nAggTimeInterval == 0) { - if ((pQuery->lastKey > pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) || - (pQuery->lastKey < pQuery->ekey && !QUERY_IS_ASC_QUERY(pQuery))) { - dTrace( - "QInfo:%p vid:%d sid:%d id:%s, query completed, ignore data in cache. qrange:%" PRId64 "-%" PRId64 ", " - "lastKey:%" PRId64, - pQInfo, pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, pQuery->skey, pQuery->ekey, - pQuery->lastKey); - - continue; - } + if ((pQuery->lastKey > pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) || + (pQuery->lastKey < pQuery->ekey && !QUERY_IS_ASC_QUERY(pQuery))) { + dTrace("QInfo:%p vid:%d sid:%d id:%s, query completed, ignore data in cache. qrange:%" PRId64 "-%" PRId64 + ", lastKey:%" PRId64, + pQInfo, pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, pQuery->skey, pQuery->ekey, + pQuery->lastKey); - setExecutionContext(pSupporter, pSupporter->pResult, k, pMeterInfo[k].groupIdx, pMeterQueryInfo); - } else { - int32_t ret = setIntervalQueryExecutionContext(pSupporter, k, pMeterQueryInfo); - if (ret != TSDB_CODE_SUCCESS) { - pQInfo->killed = 1; - return; - } + continue; } - qTrace("QInfo:%p vid:%d sid:%d id:%s, query in cache, qrange:%" PRId64 "-%" PRId64 ", lastKey:%" PRId64, pQInfo, pMeterObj->vnode, - pMeterObj->sid, pMeterObj->meterId, pQuery->skey, pQuery->ekey, pQuery->lastKey); + qTrace("QInfo:%p vid:%d sid:%d id:%s, query in cache, qrange:%" PRId64 "-%" PRId64 ", lastKey:%" PRId64, pQInfo, + pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, pQuery->skey, pQuery->ekey, pQuery->lastKey); /* * find the appropriated start position in cache @@ -186,7 +164,7 @@ static void queryOnMultiDataCache(SQInfo *pQInfo, SMeterDataInfo *pMeterInfo) { * should be ignored (the fourth parameter). */ TSKEY nextKey = getQueryStartPositionInCache(pRuntimeEnv, &pQuery->slot, &pQuery->pos, true); - if (nextKey < 0) { + if (nextKey < 0 || !doCheckWithPrevQueryRange(pQuery, nextKey)) { qTrace("QInfo:%p vid:%d sid:%d id:%s, no data qualified in cache, cache blocks:%d, lastKey:%" PRId64, pQInfo, pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, pQuery->numOfBlocks, pQuery->lastKey); continue; @@ -199,10 +177,6 @@ static void queryOnMultiDataCache(SQInfo *pQInfo, SMeterDataInfo *pMeterInfo) { continue; } - if (!doCheckWithPrevQueryRange(pQInfo, nextKey, &pMeterInfo[k])) { - continue; - } - bool firstCheckSlot = true; SCacheInfo *pCacheInfo = (SCacheInfo *)pMeterObj->pCache; @@ -224,24 +198,39 @@ static void queryOnMultiDataCache(SQInfo *pQInfo, SMeterDataInfo *pMeterInfo) { setStartPositionForCacheBlock(pQuery, pBlock, &firstCheckSlot); - TSKEY* primaryKeys = (TSKEY*) pRuntimeEnv->primaryColBuffer->data; - + TSKEY *primaryKeys = (TSKEY *)pRuntimeEnv->primaryColBuffer->data; + TSKEY key = primaryKeys[pQuery->pos]; + // in handling file data block, the timestamp range validation is done during fetching candidate file blocks - if ((primaryKeys[pQuery->pos] > pSupporter->rawEKey && QUERY_IS_ASC_QUERY(pQuery)) || - (primaryKeys[pQuery->pos] < pSupporter->rawEKey && !QUERY_IS_ASC_QUERY(pQuery))) { + if ((key > pSupporter->rawEKey && QUERY_IS_ASC_QUERY(pQuery)) || + (key < pSupporter->rawEKey && !QUERY_IS_ASC_QUERY(pQuery))) { break; } + if (pQuery->intervalTime == 0) { + setExecutionContext(pSupporter, pMeterQueryInfo, k, pMeterDataInfo[k].groupIdx, key); + } else { + setIntervalQueryRange(pMeterQueryInfo, pSupporter, key); + int32_t ret = setAdditionalInfo(pSupporter, k, pMeterQueryInfo); + if (ret != TSDB_CODE_SUCCESS) { + pQInfo->killed = 1; + return; + } + } + + qTrace("QInfo:%p vid:%d sid:%d id:%s, query in cache, qrange:%" PRId64 "-%" PRId64 ", lastKey:%" PRId64, pQInfo, + pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, pQuery->skey, pQuery->ekey, pQuery->lastKey); + // only record the key on last block SET_CACHE_BLOCK_FLAG(pRuntimeEnv->blockStatus); - SBlockInfo binfo = getBlockBasicInfo(pRuntimeEnv, pBlock, BLK_CACHE_BLOCK); + SBlockInfo binfo = getBlockInfo(pRuntimeEnv); dTrace("QInfo:%p check data block, brange:%" PRId64 "-%" PRId64 ", fileId:%d, slot:%d, pos:%d, bstatus:%d", GET_QINFO_ADDR(pQuery), binfo.keyFirst, binfo.keyLast, pQuery->fileId, pQuery->slot, pQuery->pos, pRuntimeEnv->blockStatus); totalBlocks++; - queryOnBlock(pSupporter, primaryKeys, pRuntimeEnv->blockStatus, &binfo, &pMeterInfo[k], NULL, searchFn); + stableApplyFunctionsOnBlock(pSupporter, &pMeterDataInfo[k], &binfo, NULL, searchFn); if (ALL_CACHE_BLOCKS_CHECKED(pQuery)) { break; @@ -266,7 +255,7 @@ static void queryOnMultiDataCache(SQInfo *pQInfo, SMeterDataInfo *pMeterInfo) { static void queryOnMultiDataFiles(SQInfo *pQInfo, SMeterDataInfo *pMeterDataInfo) { SQuery * pQuery = &pQInfo->query; - SMeterQuerySupportObj *pSupporter = pQInfo->pMeterQuerySupporter; + STableQuerySupportObj *pSupporter = pQInfo->pTableQuerySupporter; SQueryRuntimeEnv * pRuntimeEnv = &pSupporter->runtimeEnv; SMeterDataBlockInfoEx *pDataBlockInfoEx = NULL; int32_t nAllocBlocksInfoSize = 0; @@ -274,9 +263,9 @@ static void queryOnMultiDataFiles(SQInfo *pQInfo, SMeterDataInfo *pMeterDataInfo SMeterObj * pTempMeter = getMeterObj(pSupporter->pMetersHashTable, pSupporter->pMeterSidExtInfo[0]->sid); __block_search_fn_t searchFn = vnodeSearchKeyFunc[pTempMeter->searchAlgorithm]; - int32_t vnodeId = pTempMeter->vnode; - SQueryFilesInfo* pVnodeFileInfo = &pRuntimeEnv->vnodeFileInfo; - + int32_t vnodeId = pTempMeter->vnode; + SQueryFilesInfo *pVnodeFileInfo = &pRuntimeEnv->vnodeFileInfo; + dTrace("QInfo:%p start to check data blocks in %d files", pQInfo, pVnodeFileInfo->numOfFiles); int32_t fid = QUERY_IS_ASC_QUERY(pQuery) ? -1 : INT32_MAX; @@ -291,7 +280,7 @@ static void queryOnMultiDataFiles(SQInfo *pQInfo, SMeterDataInfo *pMeterDataInfo break; } - int32_t fileIdx = vnodeGetVnodeHeaderFileIdx(&fid, pRuntimeEnv, pQuery->order.order); + int32_t fileIdx = vnodeGetVnodeHeaderFileIndex(&fid, pRuntimeEnv, pQuery->order.order); if (fileIdx < 0) { // no valid file, abort current search break; } @@ -304,25 +293,25 @@ static void queryOnMultiDataFiles(SQInfo *pQInfo, SMeterDataInfo *pMeterDataInfo fid += step; continue; } - + int32_t numOfQualifiedMeters = 0; assert(fileIdx == pRuntimeEnv->vnodeFileInfo.current); - + SMeterDataInfo **pReqMeterDataInfo = NULL; - int32_t ret = vnodeFilterQualifiedMeters(pQInfo, vnodeId, pSupporter->pSidSet, pMeterDataInfo, + int32_t ret = vnodeFilterQualifiedMeters(pQInfo, vnodeId, pSupporter->pSidSet, pMeterDataInfo, &numOfQualifiedMeters, &pReqMeterDataInfo); if (ret != TSDB_CODE_SUCCESS) { dError("QInfo:%p failed to create meterdata struct to perform query processing, abort", pQInfo); - + tfree(pReqMeterDataInfo); pQInfo->code = -ret; pQInfo->killed = 1; - + return; } dTrace("QInfo:%p file:%s, %d meters qualified", pQInfo, pVnodeFileInfo->dataFilePath, numOfQualifiedMeters); - + // none of meters in query set have pHeaderFileData in this file, try next file if (numOfQualifiedMeters == 0) { fid += step; @@ -335,17 +324,17 @@ static void queryOnMultiDataFiles(SQInfo *pQInfo, SMeterDataInfo *pMeterDataInfo pReqMeterDataInfo, &numOfBlocks); if (ret != TSDB_CODE_SUCCESS) { dError("QInfo:%p failed to get data block before scan data blocks, abort", pQInfo); - + tfree(pReqMeterDataInfo); pQInfo->code = -ret; pQInfo->killed = 1; - + return; } dTrace("QInfo:%p file:%s, %d meters contains %d blocks to be checked", pQInfo, pVnodeFileInfo->dataFilePath, numOfQualifiedMeters, numOfBlocks); - + if (numOfBlocks == 0) { fid += step; tfree(pReqMeterDataInfo); @@ -353,7 +342,7 @@ static void queryOnMultiDataFiles(SQInfo *pQInfo, SMeterDataInfo *pMeterDataInfo } ret = createDataBlocksInfoEx(pReqMeterDataInfo, numOfQualifiedMeters, &pDataBlockInfoEx, numOfBlocks, - &nAllocBlocksInfoSize, (int64_t)pQInfo); + &nAllocBlocksInfoSize, (int64_t)pQInfo); if (ret != TSDB_CODE_SUCCESS) { // failed to create data blocks dError("QInfo:%p build blockInfoEx failed, abort", pQInfo); tfree(pReqMeterDataInfo); @@ -383,8 +372,8 @@ static void queryOnMultiDataFiles(SQInfo *pQInfo, SMeterDataInfo *pMeterDataInfo stimeUnit = taosGetTimestampMs(); } else if ((j % TRACE_OUTPUT_BLOCK_CNT) == 0) { etimeUnit = taosGetTimestampMs(); - dTrace("QInfo:%p load and check %" PRId64 " blocks, and continue. elapsed:%" PRId64 " ms", pQInfo, TRACE_OUTPUT_BLOCK_CNT, - etimeUnit - stimeUnit); + dTrace("QInfo:%p load and check %" PRId64 " blocks, and continue. elapsed:%" PRId64 " ms", pQInfo, + TRACE_OUTPUT_BLOCK_CNT, etimeUnit - stimeUnit); stimeUnit = taosGetTimestampMs(); } @@ -398,56 +387,60 @@ static void queryOnMultiDataFiles(SQInfo *pQInfo, SMeterDataInfo *pMeterDataInfo restoreIntervalQueryRange(pRuntimeEnv, pMeterQueryInfo); - if (pQuery->nAggTimeInterval == 0 && !isSumAvgRateQuery(pQuery)) { // normal query - if ((pQuery->lastKey > pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) || - (pQuery->lastKey < pQuery->ekey && !QUERY_IS_ASC_QUERY(pQuery))) { - qTrace( - "QInfo:%p vid:%d sid:%d id:%s, query completed, no need to scan this data block. qrange:%" PRId64 "-%" PRId64 ", " - "lastKey:%" PRId64, - pQInfo, pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, pQuery->skey, pQuery->ekey, - pQuery->lastKey); + if ((pQuery->lastKey > pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) || + (pQuery->lastKey < pQuery->ekey && !QUERY_IS_ASC_QUERY(pQuery))) { + qTrace("QInfo:%p vid:%d sid:%d id:%s, query completed, no need to scan this data block. qrange:%" PRId64 + "-%" PRId64 ", lastKey:%" PRId64, + pQInfo, pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, pQuery->skey, pQuery->ekey, + pQuery->lastKey); - continue; - } - - setExecutionContext(pSupporter, pSupporter->pResult, pOneMeterDataInfo->meterOrderIdx, - pOneMeterDataInfo->groupIdx, pMeterQueryInfo); - } else { // interval query - ret = setIntervalQueryExecutionContext(pSupporter, pOneMeterDataInfo->meterOrderIdx, pMeterQueryInfo); - if (ret != TSDB_CODE_SUCCESS) { - tfree(pReqMeterDataInfo); // error code has been set - pQInfo->killed = 1; - return; - } + continue; } SCompBlock *pBlock = pInfoEx->pBlock.compBlock; bool ondemandLoad = onDemandLoadDatablock(pQuery, pMeterQueryInfo->queryRangeSet); - int32_t ret = LoadDatablockOnDemand(pBlock, &pInfoEx->pBlock.fields, &pRuntimeEnv->blockStatus, pRuntimeEnv, - fileIdx, pInfoEx->blockIndex, searchFn, ondemandLoad); + ret = LoadDatablockOnDemand(pBlock, &pInfoEx->pBlock.fields, &pRuntimeEnv->blockStatus, pRuntimeEnv, fileIdx, + pInfoEx->blockIndex, searchFn, ondemandLoad); if (ret != DISK_DATA_LOADED) { pSummary->skippedFileBlocks++; continue; } SBlockInfo binfo = getBlockBasicInfo(pRuntimeEnv, pBlock, BLK_FILE_BLOCK); + int64_t nextKey = -1; assert(pQuery->pos >= 0 && pQuery->pos < pBlock->numOfPoints); TSKEY *primaryKeys = (TSKEY *)pRuntimeEnv->primaryColBuffer->data; if (IS_DATA_BLOCK_LOADED(pRuntimeEnv->blockStatus) && needPrimaryTimestampCol(pQuery, &binfo)) { - TSKEY nextKey = primaryKeys[pQuery->pos]; - if (!doCheckWithPrevQueryRange(pQInfo, nextKey, pOneMeterDataInfo)) { + nextKey = primaryKeys[pQuery->pos]; + + if (!doCheckWithPrevQueryRange(pQuery, nextKey)) { + qTrace("QInfo:%p vid:%d sid:%d id:%s, no data qualified in data file, lastKey:%" PRId64, pQInfo, + pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, pQuery->numOfBlocks, pQuery->lastKey); continue; } } else { // if data block is not loaded, it must be the intermediate blocks assert((pBlock->keyFirst >= pQuery->lastKey && pBlock->keyLast <= pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) || (pBlock->keyFirst >= pQuery->ekey && pBlock->keyLast <= pQuery->lastKey && !QUERY_IS_ASC_QUERY(pQuery))); + nextKey = QUERY_IS_ASC_QUERY(pQuery) ? pBlock->keyFirst : pBlock->keyLast; } - queryOnBlock(pSupporter, primaryKeys, pRuntimeEnv->blockStatus, &binfo, pOneMeterDataInfo, pInfoEx->pBlock.fields, - searchFn); + if (pQuery->intervalTime == 0) { + setExecutionContext(pSupporter, pMeterQueryInfo, pOneMeterDataInfo->meterOrderIdx, pOneMeterDataInfo->groupIdx, + nextKey); + } else { // interval query + setIntervalQueryRange(pMeterQueryInfo, pSupporter, nextKey); + ret = setAdditionalInfo(pSupporter, pOneMeterDataInfo->meterOrderIdx, pMeterQueryInfo); + if (ret != TSDB_CODE_SUCCESS) { + tfree(pReqMeterDataInfo); // error code has been set + pQInfo->killed = 1; + return; + } + } + + stableApplyFunctionsOnBlock(pSupporter, pOneMeterDataInfo, &binfo, pInfoEx->pBlock.fields, searchFn); } tfree(pReqMeterDataInfo); @@ -470,7 +463,7 @@ static void queryOnMultiDataFiles(SQInfo *pQInfo, SMeterDataInfo *pMeterDataInfo static bool multimeterMultioutputHelper(SQInfo *pQInfo, bool *dataInDisk, bool *dataInCache, int32_t index, int32_t start) { - SMeterQuerySupportObj *pSupporter = pQInfo->pMeterQuerySupporter; + STableQuerySupportObj *pSupporter = pQInfo->pTableQuerySupporter; SMeterSidExtInfo **pMeterSidExtInfo = pSupporter->pMeterSidExtInfo; SQueryRuntimeEnv * pRuntimeEnv = &pSupporter->runtimeEnv; @@ -486,13 +479,13 @@ static bool multimeterMultioutputHelper(SQInfo *pQInfo, bool *dataInDisk, bool * vnodeSetTagValueInParam(pSupporter->pSidSet, pRuntimeEnv, pMeterSidExtInfo[index]); - dTrace("QInfo:%p query on (%d): vid:%d sid:%d meterId:%s, qrange:%" PRId64 "-%" PRId64, pQInfo, index - start, pMeterObj->vnode, - pMeterObj->sid, pMeterObj->meterId, pQuery->skey, pQuery->ekey); + dTrace("QInfo:%p query on (%d): vid:%d sid:%d meterId:%s, qrange:%" PRId64 "-%" PRId64, pQInfo, index - start, + pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, pQuery->skey, pQuery->ekey); pQInfo->pObj = pMeterObj; pQuery->lastKey = pQuery->skey; pRuntimeEnv->pMeterObj = pMeterObj; - + vnodeUpdateQueryColumnIndex(pQuery, pRuntimeEnv->pMeterObj); vnodeUpdateFilterColumnIndex(pQuery); @@ -500,8 +493,8 @@ static bool multimeterMultioutputHelper(SQInfo *pQInfo, bool *dataInDisk, bool * // data in file or cache is not qualified for the query. abort if (!(dataInCache || dataInDisk)) { - dTrace("QInfo:%p vid:%d sid:%d meterId:%s, qrange:%" PRId64 "-%" PRId64 ", nores, %p", pQInfo, pMeterObj->vnode, pMeterObj->sid, - pMeterObj->meterId, pQuery->skey, pQuery->ekey, pQuery); + dTrace("QInfo:%p vid:%d sid:%d meterId:%s, qrange:%" PRId64 "-%" PRId64 ", nores, %p", pQInfo, pMeterObj->vnode, + pMeterObj->sid, pMeterObj->meterId, pQuery->skey, pQuery->ekey, pQuery); return false; } @@ -525,7 +518,7 @@ static bool multimeterMultioutputHelper(SQInfo *pQInfo, bool *dataInDisk, bool * static int64_t doCheckMetersInGroup(SQInfo *pQInfo, int32_t index, int32_t start) { SQuery * pQuery = &pQInfo->query; - SMeterQuerySupportObj *pSupporter = pQInfo->pMeterQuerySupporter; + STableQuerySupportObj *pSupporter = pQInfo->pTableQuerySupporter; SQueryRuntimeEnv * pRuntimeEnv = &pSupporter->runtimeEnv; bool dataInDisk = true; @@ -556,7 +549,7 @@ static int64_t doCheckMetersInGroup(SQInfo *pQInfo, int32_t index, int32_t start pointInterpSupporterDestroy(&pointInterpSupporter); vnodeScanAllData(pRuntimeEnv); - + // first/last_row query, do not invoke the finalize for super table query doFinalizeResult(pRuntimeEnv); @@ -580,7 +573,7 @@ static int64_t doCheckMetersInGroup(SQInfo *pQInfo, int32_t index, int32_t start * @param pQInfo */ static void vnodeSTableSeqProcessor(SQInfo *pQInfo) { - SMeterQuerySupportObj *pSupporter = pQInfo->pMeterQuerySupporter; + STableQuerySupportObj *pSupporter = pQInfo->pTableQuerySupporter; SMeterSidExtInfo **pMeterSidExtInfo = pSupporter->pMeterSidExtInfo; SQueryRuntimeEnv * pRuntimeEnv = &pSupporter->runtimeEnv; @@ -589,10 +582,10 @@ static void vnodeSTableSeqProcessor(SQInfo *pQInfo) { tSidSet *pSids = pSupporter->pSidSet; int32_t vid = getMeterObj(pSupporter->pMetersHashTable, pMeterSidExtInfo[0]->sid)->vnode; - + if (isPointInterpoQuery(pQuery)) { resetCtxOutputBuf(pRuntimeEnv); - + assert(pQuery->limit.offset == 0 && pQuery->limit.limit != 0); while (pSupporter->subgroupIdx < pSids->numOfSubSet) { @@ -600,8 +593,8 @@ static void vnodeSTableSeqProcessor(SQInfo *pQInfo) { int32_t end = pSids->starterPos[pSupporter->subgroupIdx + 1] - 1; if (isFirstLastRowQuery(pQuery)) { - dTrace("QInfo:%p last_row query on vid:%d, numOfGroups:%d, current group:%d", pQInfo, vid, - pSids->numOfSubSet, pSupporter->subgroupIdx); + dTrace("QInfo:%p last_row query on vid:%d, numOfGroups:%d, current group:%d", pQInfo, vid, pSids->numOfSubSet, + pSupporter->subgroupIdx); TSKEY key = -1; int32_t index = -1; @@ -633,8 +626,8 @@ static void vnodeSTableSeqProcessor(SQInfo *pQInfo) { int64_t num = doCheckMetersInGroup(pQInfo, index, start); assert(num >= 0); } else { - dTrace("QInfo:%p interp query on vid:%d, numOfGroups:%d, current group:%d", pQInfo, vid, - pSids->numOfSubSet, pSupporter->subgroupIdx); + dTrace("QInfo:%p interp query on vid:%d, numOfGroups:%d, current group:%d", pQInfo, vid, pSids->numOfSubSet, + pSupporter->subgroupIdx); for (int32_t k = start; k <= end; ++k) { if (isQueryKilled(pQuery)) { @@ -670,7 +663,7 @@ static void vnodeSTableSeqProcessor(SQInfo *pQInfo) { * we need to return it to client in the first place. */ if (pSupporter->subgroupIdx > 0) { - copyFromGroupBuf(pQInfo, pSupporter->pResult); + copyFromWindowResToSData(pQInfo, pRuntimeEnv->windowResInfo.pResult); pQInfo->pointsRead += pQuery->pointsRead; if (pQuery->pointsRead > 0) { @@ -681,10 +674,10 @@ static void vnodeSTableSeqProcessor(SQInfo *pQInfo) { if (pSupporter->meterIdx >= pSids->numOfSids) { return; } - + resetCtxOutputBuf(pRuntimeEnv); - resetSlidingWindowInfo(pRuntimeEnv, &pRuntimeEnv->swindowResInfo); - + resetTimeWindowInfo(pRuntimeEnv, &pRuntimeEnv->windowResInfo); + while (pSupporter->meterIdx < pSupporter->numOfMeters) { int32_t k = pSupporter->meterIdx; @@ -692,9 +685,8 @@ static void vnodeSTableSeqProcessor(SQInfo *pQInfo) { setQueryStatus(pQuery, QUERY_NO_DATA_TO_CHECK); return; } - - TSKEY skey = pQInfo->pMeterQuerySupporter->pMeterSidExtInfo[k]->key; + TSKEY skey = pQInfo->pTableQuerySupporter->pMeterSidExtInfo[k]->key; if (skey > 0) { pQuery->skey = skey; } @@ -747,10 +739,10 @@ static void vnodeSTableSeqProcessor(SQInfo *pQInfo) { pSupporter->meterIdx = pSupporter->pSidSet->numOfSids; break; } - + // enable execution for next table, when handling the projection query enableExecutionForNextTable(pRuntimeEnv); - + if (Q_STATUS_EQUAL(pQuery->over, QUERY_NO_DATA_TO_CHECK | QUERY_COMPLETED)) { /* * query range is identical in terms of all meters involved in query, @@ -762,7 +754,7 @@ static void vnodeSTableSeqProcessor(SQInfo *pQInfo) { pQuery->ekey = pSupporter->rawEKey; pSupporter->meterIdx++; - pQInfo->pMeterQuerySupporter->pMeterSidExtInfo[k]->key = pQuery->lastKey; + pQInfo->pTableQuerySupporter->pMeterSidExtInfo[k]->key = pQuery->lastKey; // if the buffer is full or group by each table, we need to jump out of the loop if (Q_STATUS_EQUAL(pQuery->over, QUERY_RESBUF_FULL) || @@ -770,7 +762,7 @@ static void vnodeSTableSeqProcessor(SQInfo *pQInfo) { break; } - } else { // forward query range + } else { // forward query range pQuery->skey = pQuery->lastKey; // all data in the result buffer are skipped due to the offset, continue to retrieve data from current meter @@ -778,7 +770,7 @@ static void vnodeSTableSeqProcessor(SQInfo *pQInfo) { assert(!Q_STATUS_EQUAL(pQuery->over, QUERY_RESBUF_FULL)); continue; } else { - pQInfo->pMeterQuerySupporter->pMeterSidExtInfo[k]->key = pQuery->lastKey; + pQInfo->pTableQuerySupporter->pMeterSidExtInfo[k]->key = pQuery->lastKey; // buffer is full, wait for the next round to retrieve data from current meter assert(Q_STATUS_EQUAL(pQuery->over, QUERY_RESBUF_FULL)); break; @@ -808,20 +800,21 @@ static void vnodeSTableSeqProcessor(SQInfo *pQInfo) { // todo refactor if (isGroupbyNormalCol(pQuery->pGroupbyExpr)) { - SSlidingWindowInfo* pSlidingWindowInfo = &pRuntimeEnv->swindowResInfo; - - for (int32_t i = 0; i < pSlidingWindowInfo->size; ++i) { - SOutputRes *buf = &pSlidingWindowInfo->pResult[i]; - pSlidingWindowInfo->pStatus[i].closed = true; // enable return all results for group by normal columns - + SWindowResInfo *pWindowResInfo = &pRuntimeEnv->windowResInfo; + + for (int32_t i = 0; i < pWindowResInfo->size; ++i) { + SWindowStatus *pStatus = &pWindowResInfo->pResult[i].status; + pStatus->closed = true; // enable return all results for group by normal columns + + SWindowResult *pResult = &pWindowResInfo->pResult[i]; for (int32_t j = 0; j < pQuery->numOfOutputCols; ++j) { - buf->numOfRows = MAX(buf->numOfRows, buf->resultInfo[j].numOfRes); + pResult->numOfRows = MAX(pResult->numOfRows, pResult->resultInfo[j].numOfRes); } } - pQInfo->pMeterQuerySupporter->subgroupIdx = 0; + pQInfo->pTableQuerySupporter->subgroupIdx = 0; pQuery->pointsRead = 0; - copyFromGroupBuf(pQInfo, pSlidingWindowInfo->pResult); + copyFromWindowResToSData(pQInfo, pWindowResInfo->pResult); } pQInfo->pointsRead += pQuery->pointsRead; @@ -830,12 +823,12 @@ static void vnodeSTableSeqProcessor(SQInfo *pQInfo) { dTrace( "QInfo %p vid:%d, numOfMeters:%d, index:%d, numOfGroups:%d, %d points returned, totalRead:%d totalReturn:%d," "next skey:%" PRId64 ", offset:%" PRId64, - pQInfo, vid, pSids->numOfSids, pSupporter->meterIdx, pSids->numOfSubSet, pQuery->pointsRead, - pQInfo->pointsRead, pQInfo->pointsReturned, pQuery->skey, pQuery->limit.offset); + pQInfo, vid, pSids->numOfSids, pSupporter->meterIdx, pSids->numOfSubSet, pQuery->pointsRead, pQInfo->pointsRead, + pQInfo->pointsReturned, pQuery->skey, pQuery->limit.offset); } static void doOrderedScan(SQInfo *pQInfo) { - SMeterQuerySupportObj *pSupporter = pQInfo->pMeterQuerySupporter; + STableQuerySupportObj *pSupporter = pQInfo->pTableQuerySupporter; SQuery * pQuery = &pQInfo->query; if (QUERY_IS_ASC_QUERY(pQuery)) { @@ -855,17 +848,17 @@ static void doOrderedScan(SQInfo *pQInfo) { } } -static void setupMeterQueryInfoForSupplementQuery(SMeterQuerySupportObj *pSupporter) { +static void setupMeterQueryInfoForSupplementQuery(STableQuerySupportObj *pSupporter) { + SQuery *pQuery = pSupporter->runtimeEnv.pQuery; + for (int32_t i = 0; i < pSupporter->numOfMeters; ++i) { SMeterQueryInfo *pMeterQueryInfo = pSupporter->pMeterDataInfo[i].pMeterQInfo; - SQueryResultBuf* pResultBuf = pSupporter->runtimeEnv.pResultBuf; - - changeMeterQueryInfoForSuppleQuery(pResultBuf, pMeterQueryInfo, pSupporter->rawSKey, pSupporter->rawEKey); + changeMeterQueryInfoForSuppleQuery(pQuery, pMeterQueryInfo, pSupporter->rawSKey, pSupporter->rawEKey); } } static void doMultiMeterSupplementaryScan(SQInfo *pQInfo) { - SMeterQuerySupportObj *pSupporter = pQInfo->pMeterQuerySupporter; + STableQuerySupportObj *pSupporter = pQInfo->pTableQuerySupporter; SQueryRuntimeEnv *pRuntimeEnv = &pSupporter->runtimeEnv; SQuery * pQuery = &pQInfo->query; @@ -876,17 +869,19 @@ static void doMultiMeterSupplementaryScan(SQInfo *pQInfo) { } SET_SUPPLEMENT_SCAN_FLAG(pRuntimeEnv); - disableFunctForSuppleScan(pRuntimeEnv, pQuery->order.order); + disableFunctForSuppleScan(pSupporter, pQuery->order.order); if (pRuntimeEnv->pTSBuf != NULL) { - pRuntimeEnv->pTSBuf->cur.order = pRuntimeEnv->pTSBuf->cur.order ^ 1; + pRuntimeEnv->pTSBuf->cur.order = pRuntimeEnv->pTSBuf->cur.order ^ 1u; } SWAP(pSupporter->rawSKey, pSupporter->rawEKey, TSKEY); setupMeterQueryInfoForSupplementQuery(pSupporter); int64_t st = taosGetTimestampMs(); + doOrderedScan(pQInfo); + int64_t et = taosGetTimestampMs(); dTrace("QInfo:%p supplementary scan completed, elapsed time: %lldms", pQInfo, et - st); @@ -905,7 +900,8 @@ static void doMultiMeterSupplementaryScan(SQInfo *pQInfo) { } static void vnodeMultiMeterQueryProcessor(SQInfo *pQInfo) { - SMeterQuerySupportObj *pSupporter = pQInfo->pMeterQuerySupporter; + STableQuerySupportObj *pSupporter = pQInfo->pTableQuerySupporter; + SQueryRuntimeEnv * pRuntimeEnv = &pSupporter->runtimeEnv; SQuery * pQuery = &pQInfo->query; if (pSupporter->subgroupIdx > 0) { @@ -913,14 +909,14 @@ static void vnodeMultiMeterQueryProcessor(SQInfo *pQInfo) { * if the subgroupIdx > 0, the query process must be completed yet, we only need to * copy the data into output buffer */ - if (pQuery->nAggTimeInterval > 0) { + if (pQuery->intervalTime > 0) { copyResToQueryResultBuf(pSupporter, pQuery); #ifdef _DEBUG_VIEW displayInterResult(pQuery->sdata, pQuery, pQuery->sdata[0]->len); #endif } else { - copyFromGroupBuf(pQInfo, pSupporter->pResult); + copyFromWindowResToSData(pQInfo, pRuntimeEnv->windowResInfo.pResult); } pQInfo->pointsRead += pQuery->pointsRead; @@ -941,22 +937,25 @@ static void vnodeMultiMeterQueryProcessor(SQInfo *pQInfo) { return; } - dTrace("QInfo:%p query start, qrange:%" PRId64 "-%" PRId64 ", order:%d, group:%d", pQInfo, pSupporter->rawSKey, pSupporter->rawEKey, - pQuery->order.order, pSupporter->pSidSet->numOfSubSet); + dTrace("QInfo:%p query start, qrange:%" PRId64 "-%" PRId64 ", order:%d, group:%d", pQInfo, pSupporter->rawSKey, + pSupporter->rawEKey, pQuery->order.order, pSupporter->pSidSet->numOfSubSet); dTrace("QInfo:%p main query scan start", pQInfo); int64_t st = taosGetTimestampMs(); doOrderedScan(pQInfo); int64_t et = taosGetTimestampMs(); dTrace("QInfo:%p main scan completed, elapsed time: %lldms, supplementary scan start, order:%d", pQInfo, et - st, - pQuery->order.order ^ 1); + pQuery->order.order ^ 1u); - // failed to save all intermediate results into disk, abort further query processing - if (doCloseAllOpenedResults(pSupporter) != TSDB_CODE_SUCCESS) { - dError("QInfo:%p failed to save intermediate results, abort further query processing", pQInfo); - return; + if (pQuery->intervalTime > 0) { + for (int32_t i = 0; i < pSupporter->numOfMeters; ++i) { + SMeterQueryInfo *pMeterQueryInfo = pSupporter->pMeterDataInfo[i].pMeterQInfo; + closeAllTimeWindow(&pMeterQueryInfo->windowResInfo); + } + } else { // close results for group result + closeAllTimeWindow(&pRuntimeEnv->windowResInfo); } - + doMultiMeterSupplementaryScan(pQInfo); if (isQueryKilled(pQuery)) { @@ -964,18 +963,18 @@ static void vnodeMultiMeterQueryProcessor(SQInfo *pQInfo) { return; } - if (pQuery->nAggTimeInterval > 0 || isSumAvgRateQuery(pQuery)) { + if (pQuery->intervalTime > 0 || isSumAvgRateQuery(pQuery)) { assert(pSupporter->subgroupIdx == 0 && pSupporter->numOfGroupResultPages == 0); if (mergeMetersResultToOneGroups(pSupporter) == TSDB_CODE_SUCCESS) { copyResToQueryResultBuf(pSupporter, pQuery); - + #ifdef _DEBUG_VIEW displayInterResult(pQuery->sdata, pQuery, pQuery->sdata[0]->len); #endif } } else { // not a interval query - copyFromGroupBuf(pQInfo, pSupporter->pResult); + copyFromWindowResToSData(pQInfo, pRuntimeEnv->windowResInfo.pResult); } // handle the limitation of output buffer @@ -992,7 +991,7 @@ static void vnodeMultiMeterQueryProcessor(SQInfo *pQInfo) { */ static void vnodeSingleTableFixedOutputProcessor(SQInfo *pQInfo) { SQuery * pQuery = &pQInfo->query; - SQueryRuntimeEnv *pRuntimeEnv = &pQInfo->pMeterQuerySupporter->runtimeEnv; + SQueryRuntimeEnv *pRuntimeEnv = &pQInfo->pTableQuerySupporter->runtimeEnv; assert(pQuery->slot >= 0 && pQuery->pos >= 0); @@ -1023,7 +1022,7 @@ static void vnodeSingleTableMultiOutputProcessor(SQInfo *pQInfo) { SQuery * pQuery = &pQInfo->query; SMeterObj *pMeterObj = pQInfo->pObj; - SQueryRuntimeEnv *pRuntimeEnv = &pQInfo->pMeterQuerySupporter->runtimeEnv; + SQueryRuntimeEnv *pRuntimeEnv = &pQInfo->pTableQuerySupporter->runtimeEnv; // for ts_comp query, re-initialized is not allowed if (!isTSCompQuery(pQuery)) { @@ -1054,8 +1053,9 @@ static void vnodeSingleTableMultiOutputProcessor(SQInfo *pQInfo) { TSKEY nextTimestamp = loadRequiredBlockIntoMem(pRuntimeEnv, &pRuntimeEnv->nextPos); assert(nextTimestamp > 0 || ((nextTimestamp < 0) && Q_STATUS_EQUAL(pQuery->over, QUERY_NO_DATA_TO_CHECK))); - dTrace("QInfo:%p vid:%d sid:%d id:%s, skip current result, offset:%" PRId64 ", next qrange:%" PRId64 "-%" PRId64, pQInfo, - pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, pQuery->limit.offset, pQuery->lastKey, pQuery->ekey); + dTrace("QInfo:%p vid:%d sid:%d id:%s, skip current result, offset:%" PRId64 ", next qrange:%" PRId64 "-%" PRId64, + pQInfo, pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, pQuery->limit.offset, pQuery->lastKey, + pQuery->ekey); resetCtxOutputBuf(pRuntimeEnv); } @@ -1067,8 +1067,8 @@ static void vnodeSingleTableMultiOutputProcessor(SQInfo *pQInfo) { TSKEY nextTimestamp = loadRequiredBlockIntoMem(pRuntimeEnv, &pRuntimeEnv->nextPos); assert(nextTimestamp > 0 || ((nextTimestamp < 0) && Q_STATUS_EQUAL(pQuery->over, QUERY_NO_DATA_TO_CHECK))); - dTrace("QInfo:%p vid:%d sid:%d id:%s, query abort due to buffer limitation, next qrange:%" PRId64 "-%" PRId64, pQInfo, - pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, pQuery->lastKey, pQuery->ekey); + dTrace("QInfo:%p vid:%d sid:%d id:%s, query abort due to buffer limitation, next qrange:%" PRId64 "-%" PRId64, + pQInfo, pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, pQuery->lastKey, pQuery->ekey); } dTrace("QInfo:%p vid:%d sid:%d id:%s, %d points returned, totalRead:%d totalReturn:%d", pQInfo, pMeterObj->vnode, @@ -1080,58 +1080,39 @@ static void vnodeSingleTableMultiOutputProcessor(SQInfo *pQInfo) { } } -static void vnodeSingleMeterIntervalMainLooper(SMeterQuerySupportObj *pSupporter, SQueryRuntimeEnv *pRuntimeEnv) { +static void vnodeSingleMeterIntervalMainLooper(STableQuerySupportObj *pSupporter, SQueryRuntimeEnv *pRuntimeEnv) { SQuery *pQuery = pRuntimeEnv->pQuery; while (1) { - assert((pQuery->skey <= pQuery->ekey && QUERY_IS_ASC_QUERY(pQuery)) || - (pQuery->skey >= pQuery->ekey && !QUERY_IS_ASC_QUERY(pQuery))); - initCtxOutputBuf(pRuntimeEnv); - clearCompletedSlidingWindows(pRuntimeEnv); - vnodeScanAllData(pRuntimeEnv); + if (isQueryKilled(pQuery)) { return; } assert(!Q_STATUS_EQUAL(pQuery->over, QUERY_NOT_COMPLETED)); - - // clear tag, used to decide if the whole interval query is completed or not - pQuery->over &= (~QUERY_COMPLETED); doFinalizeResult(pRuntimeEnv); - int64_t maxOutput = getNumOfResult(pRuntimeEnv); - // here we can ignore the records in case of no interpolation + // todo handle offset, in case of top/bottom interval query if ((pQuery->numOfFilterCols > 0 || pRuntimeEnv->pTSBuf != NULL) && pQuery->limit.offset > 0 && - pQuery->interpoType == TSDB_INTERPO_NONE) { // maxOutput <= 0, means current query does not generate any results - // todo handle offset, in case of top/bottom interval query - if (maxOutput > 0) { - pQuery->limit.offset--; - } - } else { - pQuery->pointsRead += maxOutput; - forwardCtxOutputBuf(pRuntimeEnv, maxOutput); - } + pQuery->interpoType == TSDB_INTERPO_NONE) { + // maxOutput <= 0, means current query does not generate any results + int32_t numOfClosed = numOfClosedTimeWindow(&pRuntimeEnv->windowResInfo); - if (Q_STATUS_EQUAL(pQuery->over, QUERY_NO_DATA_TO_CHECK)) { - break; + int32_t c = MIN(numOfClosed, pQuery->limit.offset); + clearFirstNTimeWindow(pRuntimeEnv, c); + pQuery->limit.offset -= c; } - forwardIntervalQueryRange(pSupporter, pRuntimeEnv); - if (Q_STATUS_EQUAL(pQuery->over, QUERY_COMPLETED|QUERY_RESBUF_FULL)) { + if (Q_STATUS_EQUAL(pQuery->over, QUERY_NO_DATA_TO_CHECK | QUERY_COMPLETED)) { break; } - /* - * the scan limitation mechanism is upon here, - * 1. since there is only one(k) record is generated in one scan operation - * 2. remain space is not sufficient for next query output, abort - */ - if ((pQuery->pointsRead % pQuery->pointsToRead == 0 && pQuery->pointsRead != 0) || - ((pQuery->pointsRead + maxOutput) > pQuery->pointsToRead)) { - setQueryStatus(pQuery, QUERY_RESBUF_FULL); + // load the data block for the next retrieve + loadRequiredBlockIntoMem(pRuntimeEnv, &pRuntimeEnv->nextPos); + if (Q_STATUS_EQUAL(pQuery->over, QUERY_RESBUF_FULL)) { break; } } @@ -1142,7 +1123,7 @@ static void vnodeSingleTableIntervalProcessor(SQInfo *pQInfo) { SQuery * pQuery = &(pQInfo->query); SMeterObj *pMeterObj = pQInfo->pObj; - SMeterQuerySupportObj *pSupporter = pQInfo->pMeterQuerySupporter; + STableQuerySupportObj *pSupporter = pQInfo->pTableQuerySupporter; SQueryRuntimeEnv * pRuntimeEnv = &pSupporter->runtimeEnv; int32_t numOfInterpo = 0; @@ -1151,6 +1132,14 @@ static void vnodeSingleTableIntervalProcessor(SQInfo *pQInfo) { resetCtxOutputBuf(pRuntimeEnv); vnodeSingleMeterIntervalMainLooper(pSupporter, pRuntimeEnv); + if (pQuery->intervalTime > 0) { + pSupporter->subgroupIdx = 0; // always start from 0 + pQuery->pointsRead = 0; + copyFromWindowResToSData(pQInfo, pRuntimeEnv->windowResInfo.pResult); + + clearFirstNTimeWindow(pRuntimeEnv, pSupporter->subgroupIdx); + } + // the offset is handled at prepare stage if no interpolation involved if (pQuery->interpoType == TSDB_INTERPO_NONE) { doRevisedResultsByLimit(pQInfo); @@ -1177,11 +1166,13 @@ static void vnodeSingleTableIntervalProcessor(SQInfo *pQInfo) { pQuery->pointsRead = 0; } } - - if (isGroupbyNormalCol(pQuery->pGroupbyExpr) || (pQuery->slidingTime > 0 && pQuery->nAggTimeInterval > 0)) { - pQInfo->pMeterQuerySupporter->subgroupIdx = 0; + + // all data scanned, the group by normal column can return + if (isGroupbyNormalCol(pQuery->pGroupbyExpr)) {//todo refactor with merge interval time result + pSupporter->subgroupIdx = 0; pQuery->pointsRead = 0; - copyFromGroupBuf(pQInfo, pRuntimeEnv->swindowResInfo.pResult); + copyFromWindowResToSData(pQInfo, pRuntimeEnv->windowResInfo.pResult); + clearFirstNTimeWindow(pRuntimeEnv, pSupporter->subgroupIdx); } pQInfo->pointsRead += pQuery->pointsRead; @@ -1195,7 +1186,7 @@ static void vnodeSingleTableIntervalProcessor(SQInfo *pQInfo) { void vnodeSingleTableQuery(SSchedMsg *pMsg) { SQInfo *pQInfo = (SQInfo *)pMsg->ahandle; - if (pQInfo == NULL || pQInfo->pMeterQuerySupporter == NULL) { + if (pQInfo == NULL || pQInfo->pTableQuerySupporter == NULL) { dTrace("%p freed abort query", pQInfo); return; } @@ -1203,21 +1194,22 @@ void vnodeSingleTableQuery(SSchedMsg *pMsg) { if (pQInfo->killed) { dTrace("QInfo:%p it is already killed, abort", pQInfo); vnodeDecRefCount(pQInfo); - + return; } assert(pQInfo->refCount >= 1); - SQuery * pQuery = &pQInfo->query; - SMeterObj *pMeterObj = pQInfo->pObj; + SQuery * pQuery = &pQInfo->query; + SMeterObj * pMeterObj = pQInfo->pObj; + STableQuerySupportObj *pSupporter = pQInfo->pTableQuerySupporter; + SQueryRuntimeEnv * pRuntimeEnv = &pSupporter->runtimeEnv; + + assert(pRuntimeEnv->pMeterObj == pMeterObj); dTrace("vid:%d sid:%d id:%s, query thread is created, numOfQueries:%d, QInfo:%p", pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, pMeterObj->numOfQueries, pQInfo); - SQueryRuntimeEnv *pRuntimeEnv = &pQInfo->pMeterQuerySupporter->runtimeEnv; - assert(pRuntimeEnv->pMeterObj == pMeterObj); - if (vnodeHasRemainResults(pQInfo)) { /* * There are remain results that are not returned due to result interpolation @@ -1249,12 +1241,18 @@ void vnodeSingleTableQuery(SSchedMsg *pMsg) { // here we have scan all qualified data in both data file and cache if (Q_STATUS_EQUAL(pQuery->over, QUERY_NO_DATA_TO_CHECK | QUERY_COMPLETED)) { // continue to get push data from the group result - if (isGroupbyNormalCol(pQuery->pGroupbyExpr)) { + if (isGroupbyNormalCol(pQuery->pGroupbyExpr) || + (pQuery->intervalTime > 0 && pQInfo->pointsReturned < pQuery->limit.limit)) { + //todo limit the output for interval query? pQuery->pointsRead = 0; - if (pQInfo->pMeterQuerySupporter->subgroupIdx > 0) { - copyFromGroupBuf(pQInfo, pQInfo->pMeterQuerySupporter->pResult); + pSupporter->subgroupIdx = 0; // always start from 0 + + if (pRuntimeEnv->windowResInfo.size > 0) { + copyFromWindowResToSData(pQInfo, pRuntimeEnv->windowResInfo.pResult); pQInfo->pointsRead += pQuery->pointsRead; + clearFirstNTimeWindow(pRuntimeEnv, pSupporter->subgroupIdx); + if (pQuery->pointsRead > 0) { dTrace("QInfo:%p vid:%d sid:%d id:%s, %d points returned %d from group results, totalRead:%d totalReturn:%d", pQInfo, pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, pQuery->pointsRead, pQInfo->pointsRead, @@ -1262,19 +1260,19 @@ void vnodeSingleTableQuery(SSchedMsg *pMsg) { sem_post(&pQInfo->dataReady); vnodeDecRefCount(pQInfo); - + return; } } } pQInfo->over = 1; - dTrace("QInfo:%p vid:%d sid:%d id:%s, query over, %d points are returned", pQInfo, - pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, pQInfo->pointsRead); + dTrace("QInfo:%p vid:%d sid:%d id:%s, query over, %d points are returned", pQInfo, pMeterObj->vnode, pMeterObj->sid, + pMeterObj->meterId, pQInfo->pointsRead); - vnodePrintQueryStatistics(pQInfo->pMeterQuerySupporter); + vnodePrintQueryStatistics(pSupporter); sem_post(&pQInfo->dataReady); - + vnodeDecRefCount(pQInfo); return; } @@ -1286,7 +1284,7 @@ void vnodeSingleTableQuery(SSchedMsg *pMsg) { int64_t st = taosGetTimestampUs(); // group by normal column, sliding window query, interval query are handled by interval query processor - if (pQuery->nAggTimeInterval != 0 || isGroupbyNormalCol(pQuery->pGroupbyExpr)) { // interval (down sampling operation) + if (pQuery->intervalTime != 0 || isGroupbyNormalCol(pQuery->pGroupbyExpr)) { // interval (down sampling operation) assert(pQuery->checkBufferInLoop == 0 && pQuery->pointsOffset == pQuery->pointsToRead); vnodeSingleTableIntervalProcessor(pQInfo); } else { @@ -1307,8 +1305,8 @@ void vnodeSingleTableQuery(SSchedMsg *pMsg) { dTrace("QInfo:%p query is killed", pQInfo); pQInfo->over = 1; } else { - dTrace("QInfo:%p vid:%d sid:%d id:%s, meter query thread completed, %d points are returned", - pQInfo, pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, pQuery->pointsRead); + dTrace("QInfo:%p vid:%d sid:%d id:%s, meter query thread completed, %d points are returned", pQInfo, + pMeterObj->vnode, pMeterObj->sid, pMeterObj->meterId, pQuery->pointsRead); } sem_post(&pQInfo->dataReady); @@ -1318,7 +1316,7 @@ void vnodeSingleTableQuery(SSchedMsg *pMsg) { void vnodeMultiMeterQuery(SSchedMsg *pMsg) { SQInfo *pQInfo = (SQInfo *)pMsg->ahandle; - if (pQInfo == NULL || pQInfo->pMeterQuerySupporter == NULL) { + if (pQInfo == NULL || pQInfo->pTableQuerySupporter == NULL) { return; } @@ -1334,12 +1332,12 @@ void vnodeMultiMeterQuery(SSchedMsg *pMsg) { pQuery->pointsRead = 0; int64_t st = taosGetTimestampUs(); - if (pQuery->nAggTimeInterval > 0 || + if (pQuery->intervalTime > 0 || (isFixedOutputQuery(pQuery) && (!isPointInterpoQuery(pQuery)) && !isGroupbyNormalCol(pQuery->pGroupbyExpr))) { assert(pQuery->checkBufferInLoop == 0); vnodeMultiMeterQueryProcessor(pQInfo); } else { - assert((pQuery->checkBufferInLoop == 1 && pQuery->nAggTimeInterval == 0) || isPointInterpoQuery(pQuery) || + assert((pQuery->checkBufferInLoop == 1 && pQuery->intervalTime == 0) || isPointInterpoQuery(pQuery) || isGroupbyNormalCol(pQuery->pGroupbyExpr)); vnodeSTableSeqProcessor(pQInfo); @@ -1349,10 +1347,10 @@ void vnodeMultiMeterQuery(SSchedMsg *pMsg) { pQInfo->useconds += (taosGetTimestampUs() - st); pQInfo->over = isQueryKilled(pQuery) ? 1 : 0; - taosInterpoSetStartInfo(&pQInfo->pMeterQuerySupporter->runtimeEnv.interpoInfo, pQuery->pointsRead, + taosInterpoSetStartInfo(&pQInfo->pTableQuerySupporter->runtimeEnv.interpoInfo, pQuery->pointsRead, pQInfo->query.interpoType); - SMeterQuerySupportObj *pSupporter = pQInfo->pMeterQuerySupporter; + STableQuerySupportObj *pSupporter = pQInfo->pTableQuerySupporter; if (pQuery->pointsRead == 0) { pQInfo->over = 1; diff --git a/src/vnode/detail/src/vnodeRead.c b/src/vnode/detail/src/vnodeRead.c index e4a8b898ec3266c0a89b24357a4eec08632644a1..fb7c85e61c61272159202a2bda4ef7f30fdd93d0 100644 --- a/src/vnode/detail/src/vnodeRead.c +++ b/src/vnode/detail/src/vnodeRead.c @@ -266,7 +266,7 @@ static SQInfo *vnodeAllocateQInfoEx(SQueryMeterMsg *pQueryMsg, SSqlGroupbyExpr * } pQuery->pGroupbyExpr = pGroupbyExpr; - pQuery->nAggTimeInterval = pQueryMsg->nAggTimeInterval; + pQuery->intervalTime = pQueryMsg->intervalTime; pQuery->slidingTime = pQueryMsg->slidingTime; pQuery->interpoType = pQueryMsg->interpoType; pQuery->intervalTimeUnit = pQueryMsg->intervalTimeUnit; @@ -648,7 +648,7 @@ void *vnodeQueryOnSingleTable(SMeterObj **pMetersObj, SSqlGroupbyExpr *pGroupbyE goto _error; } - SMeterQuerySupportObj *pSupporter = (SMeterQuerySupportObj *)calloc(1, sizeof(SMeterQuerySupportObj)); + STableQuerySupportObj *pSupporter = (STableQuerySupportObj *)calloc(1, sizeof(STableQuerySupportObj)); pSupporter->numOfMeters = 1; pSupporter->pMetersHashTable = taosInitHashTable(pSupporter->numOfMeters, taosIntHash_32, false); @@ -659,7 +659,7 @@ void *vnodeQueryOnSingleTable(SMeterObj **pMetersObj, SSqlGroupbyExpr *pGroupbyE pSupporter->subgroupIdx = -1; pSupporter->pMeterSidExtInfo = NULL; - pQInfo->pMeterQuerySupporter = pSupporter; + pQInfo->pTableQuerySupporter = pSupporter; STSBuf *pTSBuf = NULL; if (pQueryMsg->tsLen > 0) { @@ -670,7 +670,7 @@ void *vnodeQueryOnSingleTable(SMeterObj **pMetersObj, SSqlGroupbyExpr *pGroupbyE tsBufNextPos(pTSBuf); } - if (((*code) = vnodeQuerySingleMeterPrepare(pQInfo, pQInfo->pObj, pSupporter, pTSBuf)) != TSDB_CODE_SUCCESS) { + if (((*code) = vnodeQueryTablePrepare(pQInfo, pQInfo->pObj, pSupporter, pTSBuf)) != TSDB_CODE_SUCCESS) { goto _error; } @@ -739,7 +739,7 @@ void *vnodeQueryOnMultiMeters(SMeterObj **pMetersObj, SSqlGroupbyExpr *pGroupbyE SSchedMsg schedMsg = {0}; - SMeterQuerySupportObj *pSupporter = (SMeterQuerySupportObj *)calloc(1, sizeof(SMeterQuerySupportObj)); + STableQuerySupportObj *pSupporter = (STableQuerySupportObj *)calloc(1, sizeof(STableQuerySupportObj)); pSupporter->numOfMeters = pQueryMsg->numOfSids; pSupporter->pMetersHashTable = taosInitHashTable(pSupporter->numOfMeters, taosIntHash_32, false); @@ -784,7 +784,7 @@ void *vnodeQueryOnMultiMeters(SMeterObj **pMetersObj, SSqlGroupbyExpr *pGroupbyE (SSchema *)pQueryMsg->pTagSchema, pQueryMsg->numOfTagsCols, NULL, 0); } - pQInfo->pMeterQuerySupporter = pSupporter; + pQInfo->pTableQuerySupporter = pSupporter; STSBuf *pTSBuf = NULL; if (pQueryMsg->tsLen > 0) { @@ -794,7 +794,7 @@ void *vnodeQueryOnMultiMeters(SMeterObj **pMetersObj, SSqlGroupbyExpr *pGroupbyE tsBufResetPos(pTSBuf); } - if (((*code) = vnodeMultiMeterQueryPrepare(pQInfo, pQuery, pTSBuf)) != TSDB_CODE_SUCCESS) { + if (((*code) = vnodeSTableQueryPrepare(pQInfo, pQuery, pTSBuf)) != TSDB_CODE_SUCCESS) { goto _error; } @@ -898,8 +898,8 @@ int vnodeSaveQueryResult(void *handle, char *data, int32_t *size) { SSchedMsg schedMsg = {0}; - if (pQInfo->pMeterQuerySupporter != NULL) { - if (pQInfo->pMeterQuerySupporter->pSidSet == NULL) { + if (pQInfo->pTableQuerySupporter != NULL) { + if (pQInfo->pTableQuerySupporter->pSidSet == NULL) { schedMsg.fp = vnodeSingleTableQuery; } else { // group by tag schedMsg.fp = vnodeMultiMeterQuery; @@ -920,8 +920,8 @@ int vnodeSaveQueryResult(void *handle, char *data, int32_t *size) { } static int32_t validateQueryMeterMsg(SQueryMeterMsg *pQueryMsg) { - if (pQueryMsg->nAggTimeInterval < 0) { - dError("qmsg:%p illegal value of aggTimeInterval %" PRId64 "", pQueryMsg, pQueryMsg->nAggTimeInterval); + if (pQueryMsg->intervalTime < 0) { + dError("qmsg:%p illegal value of aggTimeInterval %" PRId64 "", pQueryMsg, pQueryMsg->intervalTime); return -1; } @@ -975,7 +975,7 @@ int32_t vnodeConvertQueryMeterMsg(SQueryMeterMsg *pQueryMsg) { pQueryMsg->queryType = htons(pQueryMsg->queryType); - pQueryMsg->nAggTimeInterval = htobe64(pQueryMsg->nAggTimeInterval); + pQueryMsg->intervalTime = htobe64(pQueryMsg->intervalTime); pQueryMsg->slidingTime = htobe64(pQueryMsg->slidingTime); pQueryMsg->numOfTagsCols = htons(pQueryMsg->numOfTagsCols); @@ -1146,7 +1146,7 @@ int32_t vnodeConvertQueryMeterMsg(SQueryMeterMsg *pQueryMsg) { "offset:%" PRId64, pQueryMsg, pQueryMsg->numOfSids, pQueryMsg->skey, pQueryMsg->ekey, pQueryMsg->numOfGroupCols, pQueryMsg->numOfTagsCols, pQueryMsg->order, pQueryMsg->orderType, pQueryMsg->orderByIdx, - pQueryMsg->numOfOutputCols, pQueryMsg->numOfCols, pQueryMsg->nAggTimeInterval, pQueryMsg->interpoType, + pQueryMsg->numOfOutputCols, pQueryMsg->numOfCols, pQueryMsg->intervalTime, pQueryMsg->interpoType, pQueryMsg->tsLen, pQueryMsg->limit, pQueryMsg->offset); return 0; diff --git a/src/vnode/detail/src/vnodeUtil.c b/src/vnode/detail/src/vnodeUtil.c index 17a94e5b9a392a250cf126c411d471fa5d010370..feef9ed47324c8c32b64f7c5fb156e5a7c52bf21 100644 --- a/src/vnode/detail/src/vnodeUtil.c +++ b/src/vnode/detail/src/vnodeUtil.c @@ -372,18 +372,22 @@ void vnodeUpdateFilterColumnIndex(SQuery* pQuery) { } // set the column index in buffer for arithmetic operation - if (pQuery->pSelectExpr != NULL) { - for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { - SSqlBinaryExprInfo* pBinExprInfo = &pQuery->pSelectExpr[i].pBinExprInfo; - if (pBinExprInfo->pBinExpr != NULL) { - for (int16_t j = 0; j < pBinExprInfo->numOfCols; ++j) { - for (int32_t k = 0; k < pQuery->numOfCols; ++k) { - if (pBinExprInfo->pReqColumns[j].colId == pQuery->colList[k].data.colId) { - pBinExprInfo->pReqColumns[j].colIdxInBuf = pQuery->colList[k].colIdxInBuf; - assert(pQuery->colList[k].colIdxInBuf == k); - break; - } - } + if (pQuery->pSelectExpr == NULL) { + return; + } + + for (int32_t i = 0; i < pQuery->numOfOutputCols; ++i) { + SSqlBinaryExprInfo* pBinExprInfo = &pQuery->pSelectExpr[i].pBinExprInfo; + if (pBinExprInfo->pBinExpr == NULL) { + continue; + } + + for (int16_t j = 0; j < pBinExprInfo->numOfCols; ++j) { + for (int32_t k = 0; k < pQuery->numOfCols; ++k) { + if (pBinExprInfo->pReqColumns[j].colId == pQuery->colList[k].data.colId) { + pBinExprInfo->pReqColumns[j].colIdxInBuf = pQuery->colList[k].colIdxInBuf; + assert(pQuery->colList[k].colIdxInBuf == k); + break; } } }