diff --git a/source/libs/function/src/builtins.c b/source/libs/function/src/builtins.c index e03af279ae..9c004bf1c4 100644 --- a/source/libs/function/src/builtins.c +++ b/source/libs/function/src/builtins.c @@ -1425,6 +1425,17 @@ static int32_t translateIrate(SFunctionNode* pFunc, char* pErrBuf, int32_t len) } static int32_t translateFirstLast(SFunctionNode* pFunc, char* pErrBuf, int32_t len) { + // forbid null as first/last input, since first(c0, null, 1) may have different number of input + int32_t numOfParams = LIST_LENGTH(pFunc->pParameterList); + + for (int32_t i = 0; i < numOfParams; ++i) { + uint8_t nodeType = nodeType(nodesListGetNode(pFunc->pParameterList, i)); + uint8_t paraType = ((SExprNode*)nodesListGetNode(pFunc->pParameterList, i))->resType.type; + if (IS_NULL_TYPE(paraType) && QUERY_NODE_VALUE == nodeType) { + return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName); + } + } + pFunc->node.resType = ((SExprNode*)nodesListGetNode(pFunc->pParameterList, 0))->resType; return TSDB_CODE_SUCCESS; } @@ -1435,6 +1446,15 @@ static int32_t translateFirstLastImpl(SFunctionNode* pFunc, char* pErrBuf, int32 uint8_t paraType = ((SExprNode*)pPara)->resType.type; int32_t paraBytes = ((SExprNode*)pPara)->resType.bytes; if (isPartial) { + int32_t numOfParams = LIST_LENGTH(pFunc->pParameterList); + for (int32_t i = 0; i < numOfParams; ++i) { + uint8_t nodeType = nodeType(nodesListGetNode(pFunc->pParameterList, i)); + uint8_t pType = ((SExprNode*)nodesListGetNode(pFunc->pParameterList, i))->resType.type; + if (IS_NULL_TYPE(pType) && QUERY_NODE_VALUE == nodeType) { + return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName); + } + } + pFunc->node.resType = (SDataType){.bytes = getFirstLastInfoSize(paraBytes) + VARSTR_HEADER_SIZE, .type = TSDB_DATA_TYPE_BINARY}; } else { diff --git a/tests/system-test/2-query/last_row.py b/tests/system-test/2-query/last_row.py index cbe83b5a30..cdb26f7589 100644 --- a/tests/system-test/2-query/last_row.py +++ b/tests/system-test/2-query/last_row.py @@ -221,7 +221,7 @@ class TDTestCase: tdSql.execute("use testdb") # bug need fix - tdSql.query("select last_row(c1 ,NULL) from testdb.t1") + tdSql.error("select last_row(c1 ,NULL) from testdb.t1") error_sql_lists = [ "select last_row from testdb.t1",