diff --git a/source/libs/executor/src/executorimpl.c b/source/libs/executor/src/executorimpl.c index 1327ddb48ece4816e817aae39c42a7e4c35ef2d7..bd9bbec6667245857450960a6e04383ab7118afa 100644 --- a/source/libs/executor/src/executorimpl.c +++ b/source/libs/executor/src/executorimpl.c @@ -13,6 +13,7 @@ * along with this program. If not, see . */ +#include #include "filter.h" #include "function.h" #include "functionMgt.h" @@ -803,7 +804,8 @@ static void doAggregateImpl(SOperatorInfo* pOperator, TSKEY startTs, SqlFunction for (int32_t k = 0; k < pOperator->numOfExprs; ++k) { if (functionNeedToExecute(&pCtx[k])) { pCtx[k].startTs = startTs; // this can be set during create the struct - pCtx[k].fpSet.process(&pCtx[k]); + if (pCtx[k].fpSet.process != NULL) + pCtx[k].fpSet.process(&pCtx[k]); } } } @@ -1074,35 +1076,36 @@ void setBlockStatisInfo(SqlFunctionCtx* pCtx, SExprInfo* pExprInfo, SSDataBlock* // set the output buffer for the selectivity + tag query static int32_t setCtxTagColumnInfo(SqlFunctionCtx* pCtx, int32_t numOfOutput) { int32_t num = 0; - int16_t tagLen = 0; SqlFunctionCtx* p = NULL; - SqlFunctionCtx** pTagCtx = taosMemoryCalloc(numOfOutput, POINTER_BYTES); - if (pTagCtx == NULL) { + SqlFunctionCtx** pValCtx = taosMemoryCalloc(numOfOutput, POINTER_BYTES); + if (pValCtx == NULL) { return TSDB_CODE_QRY_OUT_OF_MEMORY; } for (int32_t i = 0; i < numOfOutput; ++i) { - int32_t functionId = pCtx[i].functionId; - - if (functionId == FUNCTION_TAG_DUMMY || functionId == FUNCTION_TS_DUMMY) { - tagLen += pCtx[i].resDataInfo.bytes; - pTagCtx[num++] = &pCtx[i]; - } else if (1 /*(aAggs[functionId].status & FUNCSTATE_SELECTIVITY) != 0*/) { - p = &pCtx[i]; - } else if (functionId == FUNCTION_TS || functionId == FUNCTION_TAG) { - // tag function may be the group by tag column - // ts may be the required primary timestamp column - continue; + if (strcmp(pCtx[i].pExpr->pExpr->_function.functionName, "_select_value") == 0) { + pValCtx[num++] = &pCtx[i]; } else { - // the column may be the normal column, group by normal_column, the functionId is FUNCTION_PRJ + p = &pCtx[i]; } +// if (functionId == FUNCTION_TAG_DUMMY || functionId == FUNCTION_TS_DUMMY) { +// tagLen += pCtx[i].resDataInfo.bytes; +// pTagCtx[num++] = &pCtx[i]; +// } else if (functionId == FUNCTION_TS || functionId == FUNCTION_TAG) { +// // tag function may be the group by tag column +// // ts may be the required primary timestamp column +// continue; +// } else { +// // the column may be the normal column, group by normal_column, the functionId is FUNCTION_PRJ +// } } + if (p != NULL) { - p->subsidiaries.pCtx = pTagCtx; + p->subsidiaries.pCtx = pValCtx; p->subsidiaries.num = num; } else { - taosMemoryFreeClear(pTagCtx); + taosMemoryFreeClear(pValCtx); } return TSDB_CODE_SUCCESS; @@ -2219,6 +2222,8 @@ int32_t doCopyToSDataBlock(SSDataBlock* pBlock, SExprInfo* pExprInfo, SDiskbased pCtx[j].resultInfo = getResultCell(pRow, j, rowCellOffset); if (pCtx[j].fpSet.process) { pCtx[j].fpSet.finalize(&pCtx[j], pBlock); + } else if (strcmp(pCtx[j].pExpr->pExpr->_function.functionName, "_select_value") == 0) { + // do nothing, todo refactor } else { SColumnInfoData* pColInfoData = taosArrayGet(pBlock->pDataBlock, slotId); diff --git a/source/libs/function/inc/builtinsimpl.h b/source/libs/function/inc/builtinsimpl.h index 1f2ad0797d6d185e9d9c40036455e1d0ad622854..97832d007efab147862b4b6697198ba2cb667d02 100644 --- a/source/libs/function/inc/builtinsimpl.h +++ b/source/libs/function/inc/builtinsimpl.h @@ -37,11 +37,11 @@ bool getSumFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv); int32_t sumFunction(SqlFunctionCtx *pCtx); int32_t sumInvertFunction(SqlFunctionCtx *pCtx); -bool minFunctionSetup(SqlFunctionCtx *pCtx, SResultRowEntryInfo* pResultInfo); -bool maxFunctionSetup(SqlFunctionCtx *pCtx, SResultRowEntryInfo* pResultInfo); +bool minmaxFunctionSetup(SqlFunctionCtx *pCtx, SResultRowEntryInfo* pResultInfo); bool getMinmaxFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv); int32_t minFunction(SqlFunctionCtx* pCtx); int32_t maxFunction(SqlFunctionCtx *pCtx); +int32_t minmaxFunctionFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock); bool getAvgFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv); bool avgFunctionSetup(SqlFunctionCtx *pCtx, SResultRowEntryInfo* pResultInfo); @@ -82,6 +82,8 @@ bool histogramFunctionSetup(SqlFunctionCtx *pCtx, SResultRowEntryInfo* pResultIn int32_t histogramFunction(SqlFunctionCtx* pCtx); int32_t histogramFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock); +bool getSelectivityFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv); + #ifdef __cplusplus } #endif diff --git a/source/libs/function/src/builtins.c b/source/libs/function/src/builtins.c index 5aa1b63c7921b0dc0b9383fffba80140491a0439..a7b260777888cad3c1d42a8a14a6d2459483de90 100644 --- a/source/libs/function/src/builtins.c +++ b/source/libs/function/src/builtins.c @@ -509,9 +509,9 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = { .translateFunc = translateInOutNum, .dataRequiredFunc = statisDataRequired, .getEnvFunc = getMinmaxFuncEnv, - .initFunc = minFunctionSetup, + .initFunc = minmaxFunctionSetup, .processFunc = minFunction, - .finalizeFunc = functionFinalize + .finalizeFunc = minmaxFunctionFinalize }, { .name = "max", @@ -520,9 +520,9 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = { .translateFunc = translateInOutNum, .dataRequiredFunc = statisDataRequired, .getEnvFunc = getMinmaxFuncEnv, - .initFunc = maxFunctionSetup, + .initFunc = minmaxFunctionSetup, .processFunc = maxFunction, - .finalizeFunc = functionFinalize + .finalizeFunc = minmaxFunctionFinalize }, { .name = "stddev", @@ -562,7 +562,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = { .classification = FUNC_MGT_AGG_FUNC, .translateFunc = translateApercentile, .getEnvFunc = getMinmaxFuncEnv, - .initFunc = maxFunctionSetup, + .initFunc = minmaxFunctionSetup, .processFunc = maxFunction, .finalizeFunc = functionFinalize }, @@ -581,8 +581,8 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = { .type = FUNCTION_TYPE_BOTTOM, .classification = FUNC_MGT_AGG_FUNC, .translateFunc = translateBottom, - .getEnvFunc = getMinmaxFuncEnv, - .initFunc = maxFunctionSetup, + .getEnvFunc = getTopBotFuncEnv, + .initFunc = functionSetup, .processFunc = maxFunction, .finalizeFunc = functionFinalize }, @@ -603,7 +603,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = { .classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_MULTI_RES_FUNC, .translateFunc = translateLastRow, .getEnvFunc = getMinmaxFuncEnv, - .initFunc = maxFunctionSetup, + .initFunc = minmaxFunctionSetup, .processFunc = maxFunction, .finalizeFunc = functionFinalize }, @@ -1032,8 +1032,8 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = { .type = FUNCTION_TYPE_SELECT_VALUE, .classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SELECT_FUNC, .translateFunc = translateSelectValue, - .getEnvFunc = NULL, - .initFunc = NULL, + .getEnvFunc = getSelectivityFuncEnv, // todo remove this function later. + .initFunc = functionSetup, .sprocessFunc = NULL, .finalizeFunc = NULL } diff --git a/source/libs/function/src/builtinsimpl.c b/source/libs/function/src/builtinsimpl.c index 9c1601b61a00c9e0c5956e1a49d6f880b808b3ef..3d77b7b2184a69f7cf368e3126f5c1b063c3c97d 100644 --- a/source/libs/function/src/builtinsimpl.c +++ b/source/libs/function/src/builtinsimpl.c @@ -37,13 +37,15 @@ typedef struct SAvgRes { int64_t count; } SAvgRes; +typedef struct STuplePos { + int32_t pageId; + int32_t offset; +} STuplePos; + typedef struct STopBotResItem { - SVariant v; - uint64_t uid; // it is a table uid, used to extract tag data during building of the final result for the tag data - struct { - int32_t pageId; - int32_t offset; - } tuplePos; // tuple data of this chosen row + SVariant v; + uint64_t uid; // it is a table uid, used to extract tag data during building of the final result for the tag data + STuplePos tuplePos; // tuple data of this chosen row } STopBotResItem; typedef struct STopBotRes { @@ -616,101 +618,25 @@ EFuncDataRequired statisDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWin return FUNC_DATA_REQUIRED_STATIS_LOAD; } -bool maxFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) { - if (!functionSetup(pCtx, pResultInfo)) { - return false; - } - - char* buf = GET_ROWCELL_INTERBUF(pResultInfo); - switch (pCtx->resDataInfo.type) { - case TSDB_DATA_TYPE_INT: - *((int32_t*)buf) = INT32_MIN; - break; - case TSDB_DATA_TYPE_UINT: - *((uint32_t*)buf) = 0; - break; - case TSDB_DATA_TYPE_FLOAT: - *((float*)buf) = -FLT_MAX; - break; - case TSDB_DATA_TYPE_DOUBLE: - SET_DOUBLE_VAL(((double*)buf), -DBL_MAX); - break; - case TSDB_DATA_TYPE_BIGINT: - *((int64_t*)buf) = INT64_MIN; - break; - case TSDB_DATA_TYPE_UBIGINT: - *((uint64_t*)buf) = 0; - break; - case TSDB_DATA_TYPE_SMALLINT: - *((int16_t*)buf) = INT16_MIN; - break; - case TSDB_DATA_TYPE_USMALLINT: - *((uint16_t*)buf) = 0; - break; - case TSDB_DATA_TYPE_TINYINT: - *((int8_t*)buf) = INT8_MIN; - break; - case TSDB_DATA_TYPE_UTINYINT: - *((uint8_t*)buf) = 0; - break; - case TSDB_DATA_TYPE_BOOL: - *((int8_t*)buf) = 0; - break; - default: - assert(0); - } - return true; -} +typedef struct SMinmaxResInfo { + bool assign; // assign the first value or not + int64_t v; + STuplePos tuplePos; +} SMinmaxResInfo; -bool minFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) { +bool minmaxFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) { if (!functionSetup(pCtx, pResultInfo)) { return false; // not initialized since it has been initialized } - char* buf = GET_ROWCELL_INTERBUF(pResultInfo); - switch (pCtx->resDataInfo.type) { - case TSDB_DATA_TYPE_TINYINT: - *((int8_t*)buf) = INT8_MAX; - break; - case TSDB_DATA_TYPE_UTINYINT: - *(uint8_t*)buf = UINT8_MAX; - break; - case TSDB_DATA_TYPE_SMALLINT: - *((int16_t*)buf) = INT16_MAX; - break; - case TSDB_DATA_TYPE_USMALLINT: - *((uint16_t*)buf) = UINT16_MAX; - break; - case TSDB_DATA_TYPE_INT: - *((int32_t*)buf) = INT32_MAX; - break; - case TSDB_DATA_TYPE_UINT: - *((uint32_t*)buf) = UINT32_MAX; - break; - case TSDB_DATA_TYPE_BIGINT: - *((int64_t*)buf) = INT64_MAX; - break; - case TSDB_DATA_TYPE_UBIGINT: - *((uint64_t*)buf) = UINT64_MAX; - break; - case TSDB_DATA_TYPE_FLOAT: - *((float*)buf) = FLT_MAX; - break; - case TSDB_DATA_TYPE_DOUBLE: - SET_DOUBLE_VAL(((double*)buf), DBL_MAX); - break; - case TSDB_DATA_TYPE_BOOL: - *((int8_t*)buf) = 1; - break; - default: - assert(0); - } - + SMinmaxResInfo* buf = GET_ROWCELL_INTERBUF(pResultInfo); + buf->assign = false; + buf->tuplePos.pageId = -1; return true; } bool getMinmaxFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) { - pEnv->calcMemSize = sizeof(int64_t); + pEnv->calcMemSize = sizeof(SMinmaxResInfo); return true; } @@ -758,6 +684,9 @@ bool getMinmaxFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) { } \ } while (0) +static void saveTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos); +static void copyTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos); + int32_t doMinMaxHelper(SqlFunctionCtx* pCtx, int32_t isMinFunc) { int32_t numOfElems = 0; @@ -768,7 +697,7 @@ int32_t doMinMaxHelper(SqlFunctionCtx* pCtx, int32_t isMinFunc) { int32_t type = pCol->info.type; SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx); - char* buf = GET_ROWCELL_INTERBUF(pResInfo); + SMinmaxResInfo *pBuf = GET_ROWCELL_INTERBUF(pResInfo); // data in current data block are qualified to the query if (pInput->colDataAggIsSet) { @@ -795,11 +724,11 @@ int32_t doMinMaxHelper(SqlFunctionCtx* pCtx, int32_t isMinFunc) { if (IS_SIGNED_NUMERIC_TYPE(type)) { int64_t prev = 0; - GET_TYPED_DATA(prev, int64_t, type, buf); + GET_TYPED_DATA(prev, int64_t, type, pBuf->v); int64_t val = GET_INT64_VAL(tval); if ((prev < val) ^ isMinFunc) { - *(int64_t*)buf = val; + pBuf->v = val; for (int32_t i = 0; i < (pCtx)->subsidiaries.num; ++i) { SqlFunctionCtx* __ctx = pCtx->subsidiaries.pCtx[i]; if (__ctx->functionId == FUNCTION_TS_DUMMY) { // TODO refactor @@ -809,14 +738,16 @@ int32_t doMinMaxHelper(SqlFunctionCtx* pCtx, int32_t isMinFunc) { __ctx->fpSet.process(__ctx); } + + saveTupleData(pCtx, index, pCtx->pSrcBlock, &pBuf->tuplePos); } } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) { uint64_t prev = 0; - GET_TYPED_DATA(prev, uint64_t, type, buf); + GET_TYPED_DATA(prev, uint64_t, type, pBuf->v); uint64_t val = GET_UINT64_VAL(tval); if ((prev < val) ^ isMinFunc) { - *(uint64_t*)buf = val; + pBuf->v = val; for (int32_t i = 0; i < (pCtx)->subsidiaries.num; ++i) { SqlFunctionCtx* __ctx = pCtx->subsidiaries.pCtx[i]; if (__ctx->functionId == FUNCTION_TS_DUMMY) { // TODO refactor @@ -829,12 +760,13 @@ int32_t doMinMaxHelper(SqlFunctionCtx* pCtx, int32_t isMinFunc) { } } else if (type == TSDB_DATA_TYPE_DOUBLE) { double val = GET_DOUBLE_VAL(tval); - UPDATE_DATA(pCtx, *(double*)buf, val, numOfElems, isMinFunc, key); + UPDATE_DATA(pCtx, *(double*)&pBuf->v, val, numOfElems, isMinFunc, key); } else if (type == TSDB_DATA_TYPE_FLOAT) { double val = GET_DOUBLE_VAL(tval); - UPDATE_DATA(pCtx, *(float*)buf, val, numOfElems, isMinFunc, key); + UPDATE_DATA(pCtx, *(float*)&pBuf->v, val, numOfElems, isMinFunc, key); } + pBuf->assign = true; return numOfElems; } @@ -843,47 +775,318 @@ int32_t doMinMaxHelper(SqlFunctionCtx* pCtx, int32_t isMinFunc) { if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) { if (type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_BOOL) { - LOOPCHECK_N(*(int8_t*)buf, pCol, pCtx, int8_t, numOfRows, start, isMinFunc, numOfElems); + int8_t* pData = (int8_t*)pCol->pData; + int8_t* val = (int8_t*)&pBuf->v; + + for (int32_t i = start; i < start + numOfRows; ++i) { + if ((pCol->hasNull) && colDataIsNull_f(pCol->nullbitmap, i)) { + continue; + } + + if (!pBuf->assign) { + *val = pData[i]; + if (pCtx->subsidiaries.num > 0) { + saveTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos); + } + pBuf->assign = true; + } else { + // ignore the equivalent data value + if ((*val) == pData[i]) { + continue; + } + + if ((*val < pData[i]) ^ isMinFunc) { + *val = pData[i]; + if (pCtx->subsidiaries.num > 0) { + copyTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos); + } + } + } + + numOfElems += 1; + } } else if (type == TSDB_DATA_TYPE_SMALLINT) { - LOOPCHECK_N(*(int16_t*)buf, pCol, pCtx, int16_t, numOfRows, start, isMinFunc, numOfElems); + int16_t* pData = (int16_t*)pCol->pData; + int16_t* val = (int16_t*)&pBuf->v; + + for (int32_t i = start; i < start + numOfRows; ++i) { + if ((pCol->hasNull) && colDataIsNull_f(pCol->nullbitmap, i)) { + continue; + } + + if (!pBuf->assign) { + *val = pData[i]; + if (pCtx->subsidiaries.num > 0) { + saveTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos); + } + pBuf->assign = true; + } else { + // ignore the equivalent data value + if ((*val) == pData[i]) { + continue; + } + + if ((*val < pData[i]) ^ isMinFunc) { + *val = pData[i]; + if (pCtx->subsidiaries.num > 0) { + copyTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos); + } + } + } + + numOfElems += 1; + } } else if (type == TSDB_DATA_TYPE_INT) { int32_t* pData = (int32_t*)pCol->pData; - int32_t* val = (int32_t*)buf; + int32_t* val = (int32_t*)&pBuf->v; for (int32_t i = start; i < start + numOfRows; ++i) { if ((pCol->hasNull) && colDataIsNull_f(pCol->nullbitmap, i)) { continue; } - if ((*val < pData[i]) ^ isMinFunc) { + if (!pBuf->assign) { *val = pData[i]; - TSKEY ts = (pCtx->ptsList != NULL) ? GET_TS_DATA(pCtx, i) : 0; - DO_UPDATE_SUBSID_RES(pCtx, ts); + if (pCtx->subsidiaries.num > 0) { + saveTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos); + } + pBuf->assign = true; + } else { + // ignore the equivalent data value + if ((*val) == pData[i]) { + continue; + } + + if ((*val < pData[i]) ^ isMinFunc) { + *val = pData[i]; + if (pCtx->subsidiaries.num > 0) { + copyTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos); + } + } } numOfElems += 1; } - -#if defined(_DEBUG_VIEW) - qDebug("max value updated:%d", *retVal); -#endif } else if (type == TSDB_DATA_TYPE_BIGINT) { - LOOPCHECK_N(*(int64_t*)buf, pCol, pCtx, int64_t, numOfRows, start, isMinFunc, numOfElems); + int64_t* pData = (int64_t*)pCol->pData; + int64_t* val = (int64_t*)&pBuf->v; + + for (int32_t i = start; i < start + numOfRows; ++i) { + if ((pCol->hasNull) && colDataIsNull_f(pCol->nullbitmap, i)) { + continue; + } + + if (!pBuf->assign) { + *val = pData[i]; + if (pCtx->subsidiaries.num > 0) { + saveTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos); + } + pBuf->assign = true; + } else { + // ignore the equivalent data value + if ((*val) == pData[i]) { + continue; + } + + if ((*val < pData[i]) ^ isMinFunc) { + *val = pData[i]; + if (pCtx->subsidiaries.num > 0) { + copyTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos); + } + } + } + + numOfElems += 1; + } } } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) { if (type == TSDB_DATA_TYPE_UTINYINT) { - LOOPCHECK_N(*(uint8_t*)buf, pCol, pCtx, uint8_t, numOfRows, start, isMinFunc, numOfElems); + uint8_t* pData = (uint8_t*)pCol->pData; + uint8_t* val = (uint8_t*)&pBuf->v; + + for (int32_t i = start; i < start + numOfRows; ++i) { + if ((pCol->hasNull) && colDataIsNull_f(pCol->nullbitmap, i)) { + continue; + } + + if (!pBuf->assign) { + *val = pData[i]; + if (pCtx->subsidiaries.num > 0) { + saveTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos); + } + pBuf->assign = true; + } else { + // ignore the equivalent data value + if ((*val) == pData[i]) { + continue; + } + + if ((*val < pData[i]) ^ isMinFunc) { + *val = pData[i]; + if (pCtx->subsidiaries.num > 0) { + copyTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos); + } + } + } + + numOfElems += 1; + } } else if (type == TSDB_DATA_TYPE_USMALLINT) { - LOOPCHECK_N(*(uint16_t*)buf, pCol, pCtx, uint16_t, numOfRows, start, isMinFunc, numOfElems); + uint16_t* pData = (uint16_t*)pCol->pData; + uint16_t* val = (uint16_t*)&pBuf->v; + + for (int32_t i = start; i < start + numOfRows; ++i) { + if ((pCol->hasNull) && colDataIsNull_f(pCol->nullbitmap, i)) { + continue; + } + + if (!pBuf->assign) { + *val = pData[i]; + if (pCtx->subsidiaries.num > 0) { + saveTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos); + } + pBuf->assign = true; + } else { + // ignore the equivalent data value + if ((*val) == pData[i]) { + continue; + } + + if ((*val < pData[i]) ^ isMinFunc) { + *val = pData[i]; + if (pCtx->subsidiaries.num > 0) { + copyTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos); + } + } + } + + numOfElems += 1; + } } else if (type == TSDB_DATA_TYPE_UINT) { - LOOPCHECK_N(*(uint32_t*)buf, pCol, pCtx, uint32_t, numOfRows, start, isMinFunc, numOfElems); + uint32_t* pData = (uint32_t*)pCol->pData; + uint32_t* val = (uint32_t*)&pBuf->v; + + for (int32_t i = start; i < start + numOfRows; ++i) { + if ((pCol->hasNull) && colDataIsNull_f(pCol->nullbitmap, i)) { + continue; + } + + if (!pBuf->assign) { + *val = pData[i]; + if (pCtx->subsidiaries.num > 0) { + saveTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos); + } + pBuf->assign = true; + } else { + // ignore the equivalent data value + if ((*val) == pData[i]) { + continue; + } + + if ((*val < pData[i]) ^ isMinFunc) { + *val = pData[i]; + if (pCtx->subsidiaries.num > 0) { + copyTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos); + } + } + } + + numOfElems += 1; + } } else if (type == TSDB_DATA_TYPE_UBIGINT) { - LOOPCHECK_N(*(uint64_t*)buf, pCol, pCtx, uint64_t, numOfRows, start, isMinFunc, numOfElems); + uint64_t* pData = (uint64_t*)pCol->pData; + uint64_t* val = (uint64_t*)&pBuf->v; + + for (int32_t i = start; i < start + numOfRows; ++i) { + if ((pCol->hasNull) && colDataIsNull_f(pCol->nullbitmap, i)) { + continue; + } + + if (!pBuf->assign) { + *val = pData[i]; + if (pCtx->subsidiaries.num > 0) { + saveTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos); + } + pBuf->assign = true; + } else { + // ignore the equivalent data value + if ((*val) == pData[i]) { + continue; + } + + if ((*val < pData[i]) ^ isMinFunc) { + *val = pData[i]; + if (pCtx->subsidiaries.num > 0) { + copyTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos); + } + } + } + + numOfElems += 1; + } } } else if (type == TSDB_DATA_TYPE_DOUBLE) { - LOOPCHECK_N(*(double*)buf, pCol, pCtx, double, numOfRows, start, isMinFunc, numOfElems); + double* pData = (double*)pCol->pData; + double* val = (double*)&pBuf->v; + + for (int32_t i = start; i < start + numOfRows; ++i) { + if ((pCol->hasNull) && colDataIsNull_f(pCol->nullbitmap, i)) { + continue; + } + + if (!pBuf->assign) { + *val = pData[i]; + if (pCtx->subsidiaries.num > 0) { + saveTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos); + } + pBuf->assign = true; + } else { + // ignore the equivalent data value + if ((*val) == pData[i]) { + continue; + } + + if ((*val < pData[i]) ^ isMinFunc) { + *val = pData[i]; + if (pCtx->subsidiaries.num > 0) { + copyTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos); + } + } + } + + numOfElems += 1; + } } else if (type == TSDB_DATA_TYPE_FLOAT) { - LOOPCHECK_N(*(float*)buf, pCol, pCtx, float, numOfRows, start, isMinFunc, numOfElems); + float* pData = (float*)pCol->pData; + float* val = (float*)&pBuf->v; + + for (int32_t i = start; i < start + numOfRows; ++i) { + if ((pCol->hasNull) && colDataIsNull_f(pCol->nullbitmap, i)) { + continue; + } + + if (!pBuf->assign) { + *val = pData[i]; + if (pCtx->subsidiaries.num > 0) { + saveTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos); + } + pBuf->assign = true; + } else { + // ignore the equivalent data value + if ((*val) == pData[i]) { + continue; + } + + if ((*val < pData[i]) ^ isMinFunc) { + *val = pData[i]; + if (pCtx->subsidiaries.num > 0) { + copyTupleData(pCtx, i, pCtx->pSrcBlock, &pBuf->tuplePos); + } + } + } + + numOfElems += 1; + } } return numOfElems; @@ -901,6 +1104,53 @@ int32_t maxFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; } +int32_t minmaxFunctionFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) { + SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx); + + SMinmaxResInfo* pRes = GET_ROWCELL_INTERBUF(pEntryInfo); + + int32_t slotId = pCtx->pExpr->base.resSchema.slotId; + + SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId); + + // todo assign the tag value + int32_t currentRow = pBlock->info.rows; + colDataAppend(pCol, currentRow, (const char*)&pRes->v, false); + + int32_t pageId = pRes->tuplePos.pageId; + int32_t offset = pRes->tuplePos.offset; + if (pRes->tuplePos.pageId != -1) { + SFilePage* pPage = getBufPage(pCtx->pBuf, pageId); + + bool* nullList = (bool*)((char*)pPage + offset); + char* pStart = (char*)(nullList + pCtx->pSrcBlock->info.numOfCols * sizeof(bool)); + + // todo set the offset value to optimize the performance. + for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) { + SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j]; + + SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0]; + int32_t srcSlotId = pFuncParam->pCol->slotId; + int32_t dstSlotId = pc->pExpr->base.resSchema.slotId; + + int32_t ps = 0; + for (int32_t k = 0; k < srcSlotId; ++k) { + SColumnInfoData* pSrcCol = taosArrayGet(pCtx->pSrcBlock->pDataBlock, k); + ps += pSrcCol->info.bytes; + } + + SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId); + if (nullList[srcSlotId]) { + colDataAppendNULL(pDstCol, currentRow); + } else { + colDataAppend(pDstCol, currentRow, (pStart + ps), false); + } + } + } + + return pEntryInfo->numOfRes; +} + bool getStddevFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) { pEnv->calcMemSize = sizeof(SStddevRes); return true; @@ -1244,6 +1494,14 @@ bool getFirstLastFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) { return true; } +bool getSelectivityFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) { + SColumnNode* pNode = nodesListGetNode(pFunc->pParameterList, 0); + pEnv->calcMemSize = pNode->node.resType.bytes; + return true; +} + + + static FORCE_INLINE TSKEY getRowPTs(SColumnInfoData* pTsColInfo, int32_t rowIndex) { if (pTsColInfo == NULL) { return 0; @@ -1624,9 +1882,6 @@ static STopBotRes* getTopBotOutputInfo(SqlFunctionCtx* pCtx) { static void doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock, uint16_t type, uint64_t uid, SResultRowEntryInfo* pEntryInfo); -static void saveTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STopBotResItem* pItem); -static void copyTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STopBotResItem* pItem); - int32_t topFunction(SqlFunctionCtx* pCtx) { int32_t numOfElems = 0; SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx); @@ -1701,7 +1956,7 @@ void doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSData pItem->uid = uid; // save the data of this tuple - saveTupleData(pCtx, rowIndex, pSrcBlock, pItem); + saveTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos); // allocate the buffer and keep the data of this row into the new allocated buffer pEntryInfo->numOfRes++; @@ -1716,15 +1971,14 @@ void doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSData pItem->uid = uid; // save the data of this tuple by over writing the old data - copyTupleData(pCtx, rowIndex, pSrcBlock, pItem); - + copyTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos); taosheapadjust((void*)pItems, sizeof(STopBotResItem), 0, pEntryInfo->numOfRes - 1, (const void*)&type, topBotResComparFn, NULL, false); } } } -void saveTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STopBotResItem* pItem) { +void saveTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) { SFilePage* pPage = NULL; int32_t completeRowSize = pSrcBlock->info.rowSize + pSrcBlock->info.numOfCols * sizeof(bool); @@ -1740,7 +1994,7 @@ void saveTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pS } } - pItem->tuplePos.pageId = pCtx->curBufPage; + pPos->pageId = pCtx->curBufPage; // keep the current row data, extract method int32_t offset = 0; @@ -1764,17 +2018,17 @@ void saveTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pS offset += pCol->info.bytes; } - pItem->tuplePos.offset = pPage->num; + pPos->offset = pPage->num; pPage->num += completeRowSize; setBufPageDirty(pPage, true); releaseBufPage(pCtx->pBuf, pPage); } -void copyTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STopBotResItem* pItem) { - SFilePage* pPage = getBufPage(pCtx->pBuf, pItem->tuplePos.pageId); +void copyTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) { + SFilePage* pPage = getBufPage(pCtx->pBuf, pPos->pageId); - bool* nullList = (bool*)((char*)pPage + pItem->tuplePos.offset); + bool* nullList = (bool*)((char*)pPage + pPos->offset); char* pStart = (char*)(nullList + pSrcBlock->info.numOfCols * sizeof(bool)); int32_t offset = 0;