diff --git a/src/client/src/tscUtil.c b/src/client/src/tscUtil.c index b47faa32d9100ff33139137b0ba05e2594469a9f..68f7a10779f1e04c9b4c6f8e54dec5e28765f5ca 100644 --- a/src/client/src/tscUtil.c +++ b/src/client/src/tscUtil.c @@ -1340,6 +1340,18 @@ void handleDownstreamOperator(SSqlObj** pSqlObjList, int32_t numOfUpstream, SQue break; } } + + // set input data order to param[1] + if(pex->base.functionId == TSDB_FUNC_FIRST || pex->base.functionId == TSDB_FUNC_FIRST_DST || + pex->base.functionId == TSDB_FUNC_LAST || pex->base.functionId == TSDB_FUNC_LAST) { + // set input order + SQueryInfo* pInputQI = pSqlObjList[0]->cmd.pQueryInfo; + if(pInputQI) { + pex->base.numOfParams = 2; + pex->base.param[1].nType = TSDB_DATA_TYPE_INT; + pex->base.param[1].i64 = pInputQI->order.order; + } + } } tscDebug("0x%"PRIx64" create QInfo 0x%"PRIx64" to execute the main query while all nest queries are ready", pSql->self, pSql->self); diff --git a/src/query/src/qAggMain.c b/src/query/src/qAggMain.c index 6dda83eaba97e3db926963ae9374f9192b370fbf..15d7e49c160d212f530473db5756e28dff79200e 100644 --- a/src/query/src/qAggMain.c +++ b/src/query/src/qAggMain.c @@ -698,10 +698,6 @@ static int32_t dataBlockRequired(SQLFunctionCtx *pCtx, STimeWindow* w, int32_t c // todo: if column in current data block are null, opt for this case static int32_t firstFuncRequired(SQLFunctionCtx *pCtx, STimeWindow* w, int32_t colId) { - if (pCtx->order == TSDB_ORDER_DESC) { - return BLK_DATA_NO_NEEDED; - } - // no result for first query, data block is required if (GET_RES_INFO(pCtx) == NULL || GET_RES_INFO(pCtx)->numOfRes <= 0) { return BLK_DATA_ALL_NEEDED; @@ -710,11 +706,7 @@ static int32_t firstFuncRequired(SQLFunctionCtx *pCtx, STimeWindow* w, int32_t c } } -static int32_t lastFuncRequired(SQLFunctionCtx *pCtx, STimeWindow* w, int32_t colId) { - if (pCtx->order != pCtx->param[0].i64) { - return BLK_DATA_NO_NEEDED; - } - +static int32_t lastFuncRequired(SQLFunctionCtx *pCtx, STimeWindow* w, int32_t colId) { if (GET_RES_INFO(pCtx) == NULL || GET_RES_INFO(pCtx)->numOfRes <= 0) { return BLK_DATA_ALL_NEEDED; } else { @@ -1523,15 +1515,20 @@ static bool first_last_function_setup(SQLFunctionCtx *pCtx, SResultRowCellInfo* } // todo opt for null block -static void first_function(SQLFunctionCtx *pCtx) { - if (pCtx->order == TSDB_ORDER_DESC) { - return; - } - +static void first_function(SQLFunctionCtx *pCtx) { int32_t notNullElems = 0; + int32_t step = 1; + int32_t i = 0; + + if(pCtx->numOfParams == 2) { + if(pCtx->param[1].nType == TSDB_DATA_TYPE_INT && pCtx->param[1].i64 == TSDB_ORDER_DESC) { + step = -1; + i = pCtx->size - 1; + } + } // handle the null value - for (int32_t i = 0; i < pCtx->size; ++i) { + for (int32_t m = 0; m < pCtx->size; ++m, i+=step) { char *data = GET_INPUT_DATA(pCtx, i); if (pCtx->hasNull && isNull(data, pCtx->inputType)) { continue; @@ -1634,16 +1631,20 @@ static void first_dist_func_merge(SQLFunctionCtx *pCtx) { * least one data in this block that is not null.(TODO opt for this case) */ static void last_function(SQLFunctionCtx *pCtx) { - if (pCtx->order != pCtx->param[0].i64) { - return; - } - SResultRowCellInfo* pResInfo = GET_RES_INFO(pCtx); - int32_t notNullElems = 0; - if (pCtx->order == TSDB_ORDER_DESC) { + int32_t step = -1; + int32_t i = pCtx->size - 1; - for (int32_t i = pCtx->size - 1; i >= 0; --i) { + if(pCtx->numOfParams == 2) { + if(pCtx->param[1].nType == TSDB_DATA_TYPE_INT && pCtx->param[1].i64 == TSDB_ORDER_DESC) { + step = 1; + i = 0; + } + } + + if (pCtx->order == TSDB_ORDER_DESC) { + for (int32_t m = pCtx->size - 1; m >= 0; --m, i += step) { char *data = GET_INPUT_DATA(pCtx, i); if (pCtx->hasNull && isNull(data, pCtx->inputType) && (!pCtx->requireNull)) { continue; @@ -1660,7 +1661,7 @@ static void last_function(SQLFunctionCtx *pCtx) { break; } } else { // ascending order - for (int32_t i = pCtx->size - 1; i >= 0; --i) { + for (int32_t m = pCtx->size - 1; m >= 0; --m, i += step) { char *data = GET_INPUT_DATA(pCtx, i); if (pCtx->hasNull && isNull(data, pCtx->inputType) && (!pCtx->requireNull)) { continue; diff --git a/src/query/src/qExecutor.c b/src/query/src/qExecutor.c index b3531c992f693bf680b9bab85ed63a4aa81b9ef3..0efbf5698acba8d99d94b488fc42a0d1a6f4c656 100644 --- a/src/query/src/qExecutor.c +++ b/src/query/src/qExecutor.c @@ -1910,7 +1910,7 @@ static int32_t getGroupbyColumnIndex(SGroupbyExpr *pGroupbyExpr, SSDataBlock* pD static bool functionNeedToExecute(SQueryRuntimeEnv *pRuntimeEnv, SQLFunctionCtx *pCtx) { SResultRowCellInfo *pResInfo = GET_RES_INFO(pCtx); - SQueryAttr* pQueryAttr = pRuntimeEnv->pQueryAttr; + //SQueryAttr* pQueryAttr = pRuntimeEnv->pQueryAttr; // in case of timestamp column, always generated results. int32_t functionId = pCtx->functionId; @@ -1922,14 +1922,14 @@ static bool functionNeedToExecute(SQueryRuntimeEnv *pRuntimeEnv, SQLFunctionCtx return false; } - if (functionId == TSDB_FUNC_FIRST_DST || functionId == TSDB_FUNC_FIRST) { - return QUERY_IS_ASC_QUERY(pQueryAttr); - } + //if (functionId == TSDB_FUNC_FIRST_DST || functionId == TSDB_FUNC_FIRST) { + //return QUERY_IS_ASC_QUERY(pQueryAttr); + //} // denote the order type - if ((functionId == TSDB_FUNC_LAST_DST || functionId == TSDB_FUNC_LAST)) { - return pCtx->param[0].i64 == pQueryAttr->order.order; - } + //if ((functionId == TSDB_FUNC_LAST_DST || functionId == TSDB_FUNC_LAST)) { + // return pCtx->param[0].i64 == pQueryAttr->order.order; + //} // in the reverse table scan, only the following functions need to be executed if (IS_REVERSE_SCAN(pRuntimeEnv) ||