From d9d64092496f0aab7aadd3c0fa25fa5f2b18713f Mon Sep 17 00:00:00 2001 From: Ganlin Zhao Date: Tue, 19 Jul 2022 19:47:46 +0800 Subject: [PATCH 1/3] fix(query): forbid use null as input for first/last/last_row TD-17526 --- source/libs/function/src/builtins.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/source/libs/function/src/builtins.c b/source/libs/function/src/builtins.c index e8358319d4..8cc8dff99f 100644 --- a/source/libs/function/src/builtins.c +++ b/source/libs/function/src/builtins.c @@ -1423,6 +1423,16 @@ 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 paraType = ((SExprNode*)nodesListGetNode(pFunc->pParameterList, i))->resType.type; + if (IS_NULL_TYPE(paraType)) { + return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName); + } + } + pFunc->node.resType = ((SExprNode*)nodesListGetNode(pFunc->pParameterList, 0))->resType; return TSDB_CODE_SUCCESS; } @@ -1433,6 +1443,14 @@ 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 pType = ((SExprNode*)nodesListGetNode(pFunc->pParameterList, i))->resType.type; + if (IS_NULL_TYPE(pType)) { + return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName); + } + } + pFunc->node.resType = (SDataType){.bytes = getFirstLastInfoSize(paraBytes) + VARSTR_HEADER_SIZE, .type = TSDB_DATA_TYPE_BINARY}; } else { From 6be20e951dc3c66d56cc604ff22f1def729aefd7 Mon Sep 17 00:00:00 2001 From: Ganlin Zhao Date: Tue, 19 Jul 2022 20:21:43 +0800 Subject: [PATCH 2/3] fix(query): forbid use null as input for first/last/last_row --- source/libs/function/src/builtins.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/libs/function/src/builtins.c b/source/libs/function/src/builtins.c index e9c77e7adf..9c004bf1c4 100644 --- a/source/libs/function/src/builtins.c +++ b/source/libs/function/src/builtins.c @@ -1429,8 +1429,9 @@ static int32_t translateFirstLast(SFunctionNode* pFunc, char* pErrBuf, int32_t l 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)) { + if (IS_NULL_TYPE(paraType) && QUERY_NODE_VALUE == nodeType) { return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName); } } @@ -1447,8 +1448,9 @@ static int32_t translateFirstLastImpl(SFunctionNode* pFunc, char* pErrBuf, int32 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)) { + if (IS_NULL_TYPE(pType) && QUERY_NODE_VALUE == nodeType) { return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName); } } From af4ad5a8376b2d09d933e2b20a4217f6e6fe4601 Mon Sep 17 00:00:00 2001 From: Ganlin Zhao Date: Tue, 19 Jul 2022 20:25:26 +0800 Subject: [PATCH 3/3] fix test case --- tests/system-test/2-query/last_row.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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",