diff --git a/include/libs/parser/parser.h b/include/libs/parser/parser.h index 9e6a033f1088917a2ce39735be1c4750b1425275..2dec203ce8fde0d01a864ab220b267ca6020a565 100644 --- a/include/libs/parser/parser.h +++ b/include/libs/parser/parser.h @@ -108,10 +108,10 @@ typedef struct SQueryStmtInfo { SArray *pUdfInfo; struct SQueryStmtInfo *sibling; // sibling - SArray *pUpstream; // SArray struct SQueryStmtInfo *pDownstream; + SMultiFunctionsDesc info; + SArray *pUpstream; // SArray int32_t havingFieldNum; - SMultiFunctionsDesc info; int32_t exprListLevelIndex; } SQueryStmtInfo; @@ -176,6 +176,7 @@ typedef struct SSourceParam { SExprInfo* createExprInfo(STableMetaInfo* pTableMetaInfo, const char* funcName, SSourceParam* pSource, SSchema* pResSchema, int16_t interSize); int32_t copyExprInfoList(SArray* dst, const SArray* src, uint64_t uid, bool deepcopy); +int32_t getExprFunctionLevel(SQueryStmtInfo* pQueryInfo); STableMetaInfo* getMetaInfo(SQueryStmtInfo* pQueryInfo, int32_t tableIndex); SSchema *getOneColumnSchema(const STableMeta* pTableMeta, int32_t colIndex); diff --git a/source/libs/parser/src/astValidate.c b/source/libs/parser/src/astValidate.c index 8e0f59b07e0b6711a5fededb71b9eb51784142db..a8a1c191f750173ce9c3e4b485dee0e92cb83398 100644 --- a/source/libs/parser/src/astValidate.c +++ b/source/libs/parser/src/astValidate.c @@ -35,6 +35,11 @@ #define COLUMN_INDEX_INITIAL_VAL (-2) #define COLUMN_INDEX_INITIALIZER { COLUMN_INDEX_INITIAL_VAL, COLUMN_INDEX_INITIAL_VAL } +static int32_t resColId = 5000; +int32_t getNewResColId() { + return resColId++; +} + static int32_t validateSelectNodeList(SQueryStmtInfo* pQueryInfo, SArray* pSelNodeList, bool outerQuery, SMsgBuf* pMsgBuf); static int32_t extractFunctionParameterInfo(SQueryStmtInfo* pQueryInfo, int32_t tokenId, STableMetaInfo** pTableMetaInfo, SSchema* columnSchema, tExprNode** pNode, SColumnIndex* pIndex, tSqlExprItem* pParamElem, SMsgBuf* pMsgBuf); @@ -1562,6 +1567,15 @@ int32_t validateSqlNode(SSqlNode* pSqlNode, SQueryStmtInfo* pQueryInfo, SMsgBuf* } } + for(int32_t i = 0; i < getExprFunctionLevel(pQueryInfo); ++i) { + SArray* functionList = extractFunctionList(pQueryInfo->exprList[i]); + extractFunctionDesc(functionList, &pQueryInfo->info); + + if ((code = checkForInvalidExpr(pQueryInfo, pMsgBuf)) != TSDB_CODE_SUCCESS) { + return code; + } + } + return TSDB_CODE_SUCCESS; // Does not build query message here } @@ -1603,7 +1617,11 @@ int32_t checkForInvalidExpr(SQueryStmtInfo* pQueryInfo, SMsgBuf* pMsgBuf) { size_t size = getNumOfExprs(pQueryInfo); for (int32_t i = 0; i < size; ++i) { SExprInfo* pExpr = getExprInfo(pQueryInfo, i); - int32_t functionId = getExprFunctionId(pExpr); + if (pExpr->pExpr->nodeType != TEXPR_FUNCTION_NODE) { + continue; + } + + int32_t functionId = getExprFunctionId(pExpr); if (functionId == FUNCTION_COUNT && TSDB_COL_IS_TAG(pExpr->base.pColumns->flag)) { return buildInvalidOperationMsg(pMsgBuf, msg1); } @@ -1669,11 +1687,6 @@ int32_t checkForInvalidExpr(SQueryStmtInfo* pQueryInfo, SMsgBuf* pMsgBuf) { } } -static int32_t resColId = 5000; -int32_t getNewResColId() { - return resColId++; -} - int32_t addResColumnInfo(SQueryStmtInfo* pQueryInfo, int32_t outputIndex, SSchema* pSchema, SExprInfo* pSqlExpr) { SInternalField* pInfo = insertFieldInfo(&pQueryInfo->fieldsInfo, outputIndex, pSchema); pInfo->pExpr = pSqlExpr; @@ -1787,7 +1800,6 @@ static int32_t checkForAliasName(SMsgBuf* pMsgBuf, char* aliasName) { return TSDB_CODE_SUCCESS; } -static int32_t validateComplexExpr(tSqlExpr* pExpr, SQueryStmtInfo* pQueryInfo, SArray* pColList, int32_t* type, SMsgBuf* pMsgBuf); static int32_t sqlExprToExprNode(tExprNode **pExpr, const tSqlExpr* pSqlExpr, SQueryStmtInfo* pQueryInfo, SArray* pCols, bool* keepTableCols, SMsgBuf* pMsgBuf); static int64_t getTickPerSecond(SVariant* pVariant, int32_t precision, int64_t* tickPerSec, SMsgBuf *pMsgBuf) { @@ -2600,15 +2612,15 @@ static int32_t validateExprLeafFunctionNode(SQueryStmtInfo* pQueryInfo, tSqlExpr return TSDB_CODE_SUCCESS; } -int32_t validateScalarFunctionParamNum(tSqlExprItem* pItem, SMsgBuf* pMsgBuf) { +static int32_t validateScalarFunctionParamNum(tSqlExpr* pSqlExpr, int32_t functionId, SMsgBuf* pMsgBuf) { int32_t code = TSDB_CODE_SUCCESS; - switch (pItem->functionId) { + switch (functionId) { case FUNCTION_CEIL: { - code = checkForkParam(pItem->pNode, 1, pMsgBuf); + code = checkForkParam(pSqlExpr, 1, pMsgBuf); break; } case FUNCTION_LENGTH: { - code = checkForkParam(pItem->pNode, 1, pMsgBuf); + code = checkForkParam(pSqlExpr, 1, pMsgBuf); break; } } @@ -2616,38 +2628,6 @@ int32_t validateScalarFunctionParamNum(tSqlExprItem* pItem, SMsgBuf* pMsgBuf) { return code; } -int32_t validateScalarFunctionParam(SQueryStmtInfo* pQueryInfo, tSqlExpr* pExpr, SArray* pList, int32_t* exprType, SMsgBuf* pMsgBuf) { - int32_t code = TSDB_CODE_SUCCESS; - - SArray* pParamList = pExpr->Expr.paramList; - *exprType = NORMAL_ARITHMETIC; - - for (int32_t i = 0; i < 1; ++i) { - tSqlExprItem* pParamElem = taosArrayGet(pParamList, i); - tSqlExpr* pSqlExpr = pParamElem->pNode; - - int32_t type = pSqlExpr->type; - if (type == SQL_NODE_VALUE) { - // do nothing for scalar function, or maybe the evaluation can be done here - } else if (type == SQL_NODE_SQLFUNCTION) { - code = validateExprLeafFunctionNode(pQueryInfo, pSqlExpr, pMsgBuf); - if (code != TSDB_CODE_SUCCESS) { - return code; - } - } else if (type == SQL_NODE_EXPR) { - code = validateComplexExpr(pSqlExpr, pQueryInfo, pList, exprType, pMsgBuf); - if (code != TSDB_CODE_SUCCESS) { - return code; - } - } else if (type == SQL_NODE_TABLE_COLUMN) { - code = validateExprLeafColumnNode(pQueryInfo, &pSqlExpr->columnName, pList, pMsgBuf); - if (code != TSDB_CODE_SUCCESS) { - return code; - } - } - } -} - SExprInfo* doAddProjectCol(SQueryStmtInfo* pQueryInfo, int32_t outputColIndex, SColumnIndex* pColIndex, const char* aliasName, int32_t colId) { STableMeta* pTableMeta = getMetaInfo(pQueryInfo, pColIndex->tableIndex)->pTableMeta; @@ -2888,57 +2868,6 @@ static int32_t validateExprLeafNode(tSqlExpr* pExpr, SQueryStmtInfo* pQueryInfo, return TSDB_CODE_SUCCESS; } -int32_t validateComplexExpr(tSqlExpr * pExpr, SQueryStmtInfo* pQueryInfo, SArray* pColList, int32_t* type, SMsgBuf* pMsgBuf) { - if (pExpr == NULL) { - return TSDB_CODE_SUCCESS; - } - - int32_t code = TSDB_CODE_SUCCESS; - if (pExpr->type == SQL_NODE_SQLFUNCTION) { - return validateScalarFunctionParam(pQueryInfo, pExpr, pColList, type, pMsgBuf); - } - - tSqlExpr* pLeft = pExpr->pLeft; - if (pLeft->type == SQL_NODE_EXPR) { - code = validateComplexExpr(pLeft, pQueryInfo, pColList, type, pMsgBuf); - if (code != TSDB_CODE_SUCCESS) { - return code; - } - } else { - code = validateExprLeafNode(pLeft, pQueryInfo, pColList, type, pMsgBuf); - if (code != TSDB_CODE_SUCCESS) { - return code; - } - } - - tSqlExpr* pRight = pExpr->pRight; - if (pRight->type == SQL_NODE_EXPR) { - code = validateComplexExpr(pRight, pQueryInfo, pColList, type, pMsgBuf); - if (code != TSDB_CODE_SUCCESS) { - return code; - } - } else { - code = validateExprLeafNode(pRight, pQueryInfo, pColList, type, pMsgBuf); - if (code != TSDB_CODE_SUCCESS) { - return code; - } - } - - // check divide by 0 - if (pExpr->tokenId == TK_DIVIDE && pRight->type == SQL_NODE_VALUE) { - int32_t type1 = pRight->value.nType; - const char* msg1 = "invalid expr (divide by 0)"; - - if (type1 == TSDB_DATA_TYPE_DOUBLE && pRight->value.d < DBL_EPSILON) { - return buildInvalidOperationMsg(pMsgBuf, msg1); - } else if (type1 == TSDB_DATA_TYPE_INT && pRight->value.i == 0) { - return buildInvalidOperationMsg(pMsgBuf, msg1); - } - } - - return TSDB_CODE_SUCCESS; -} - static uint64_t findTmpSourceColumnInNextLevel(SQueryStmtInfo* pQueryInfo, tExprNode *pExpr) { // This function must be a aggregate function, so it must be in the next level pQueryInfo->exprListLevelIndex += 1; @@ -3080,7 +3009,8 @@ int32_t validateSqlExpr(const tSqlExpr* pSqlExpr, SQueryStmtInfo *pQueryInfo, SM } int32_t tokenId = pSqlExpr->tokenId; - if (pRight->type == SQL_NODE_VALUE && pRight->value.nType == TSDB_DATA_TYPE_DOUBLE && pRight->value.d == 0 && tokenId == TK_DIVIDE) { + if (pRight->type == SQL_NODE_VALUE && (pRight->value.nType == TSDB_DATA_TYPE_DOUBLE || pRight->value.nType == TSDB_DATA_TYPE_INT) && + pRight->value.d == 0 && tokenId == TK_DIVIDE) { return buildInvalidOperationMsg(pMsgBuf, "invalid expression (divided by 0)"); } @@ -3098,6 +3028,20 @@ int32_t validateSqlExpr(const tSqlExpr* pSqlExpr, SQueryStmtInfo *pQueryInfo, SM if (ret != TSDB_CODE_SUCCESS) { return ret; } + } else if (pSqlExpr->type == SQL_NODE_SQLFUNCTION) { + bool scalar = false; + int32_t functionId = qIsBuiltinFunction(pSqlExpr->Expr.operand.z, pSqlExpr->Expr.operand.n, &scalar); + if (functionId < 0) { + return buildInvalidOperationMsg(pMsgBuf, "invalid function name"); + } + + // do check the parameter number for scalar function + if (scalar) { + int32_t ret = validateScalarFunctionParamNum(pSqlExpr, functionId, pMsgBuf); + if (ret != TSDB_CODE_SUCCESS) { + return buildInvalidOperationMsg(pMsgBuf, "invalid number of function parameters"); + } + } } return TSDB_CODE_SUCCESS; @@ -3379,14 +3323,14 @@ int32_t validateSelectNodeList(SQueryStmtInfo* pQueryInfo, SArray* pSelNodeList, if (type == SQL_NODE_SQLFUNCTION) { bool scalarFunc = false; pItem->functionId = qIsBuiltinFunction(pItem->pNode->Expr.operand.z, pItem->pNode->Expr.operand.n, &scalarFunc); - if (pItem->functionId == FUNCTION_INVALID_ID) { - int32_t functionId = FUNCTION_INVALID_ID; - bool valid = qIsValidUdf(pQueryInfo->pUdfInfo, pItem->pNode->Expr.operand.z, pItem->pNode->Expr.operand.n, &functionId); - if (!valid) { + if (pItem->functionId == FUNCTION_INVALID_ID) { // temporarily disable the udf +// int32_t functionId = FUNCTION_INVALID_ID; +// bool valid = qIsValidUdf(pQueryInfo->pUdfInfo, pItem->pNode->Expr.operand.z, pItem->pNode->Expr.operand.n, &functionId); +// if (!valid) { return buildInvalidOperationMsg(pMsgBuf, msg5); - } +// } - pItem->functionId = functionId; +// pItem->functionId = functionId; } if (scalarFunc) { // scalar function @@ -3920,12 +3864,6 @@ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQuer validateSqlNode(p, pQueryInfo, &buf); } - SArray* functionList = extractFunctionList(pQueryInfo->exprList[0]); - extractFunctionDesc(functionList, &pQueryInfo->info); - - if ((code = checkForInvalidExpr(pQueryInfo, &buf)) != TSDB_CODE_SUCCESS) { - return code; - } return code; } diff --git a/source/libs/parser/src/queryInfoUtil.c b/source/libs/parser/src/queryInfoUtil.c index 04922ce5ad25bf46764bc4f2ffe206810778b181..0543478674a8a3167908b723eac4ca47aeaaff78 100644 --- a/source/libs/parser/src/queryInfoUtil.c +++ b/source/libs/parser/src/queryInfoUtil.c @@ -223,7 +223,7 @@ void addExprInfoParam(SSqlExpr* pExpr, char* argument, int32_t type, int32_t byt } int32_t getExprFunctionId(SExprInfo *pExprInfo) { - assert(pExprInfo != NULL && pExprInfo->pExpr != NULL && pExprInfo->pExpr->nodeType == TEXPR_UNARYEXPR_NODE); + assert(pExprInfo != NULL && pExprInfo->pExpr != NULL && pExprInfo->pExpr->nodeType == TEXPR_FUNCTION_NODE); return 0; } @@ -350,11 +350,16 @@ bool tscHasColumnFilter(SQueryStmtInfo* pQueryInfo) { return false; } -//void tscClearInterpInfo(SQueryStmtInfo* pQueryInfo) { -// if (!tscIsPointInterpQuery(pQueryInfo)) { -// return; -// } -// -// pQueryInfo->fillType = TSDB_FILL_NONE; -// tfree(pQueryInfo->fillVal); -//} \ No newline at end of file +int32_t getExprFunctionLevel(SQueryStmtInfo* pQueryInfo) { + int32_t n = 10; + + int32_t level = 0; + for(int32_t i = 0; i < n; ++i) { + SArray* pList = pQueryInfo->exprList[i]; + if (taosArrayGetSize(pList) > 0) { + level += 1; + } + } + + return level; +} \ No newline at end of file diff --git a/source/libs/parser/test/parserTests.cpp b/source/libs/parser/test/parserTests.cpp index 6e491cedb03d7753ae99064f01501ec044f2d983..1ecd9e3a08a7bf97ba19e1e1e6e0be610a67bc12 100644 --- a/source/libs/parser/test/parserTests.cpp +++ b/source/libs/parser/test/parserTests.cpp @@ -412,6 +412,16 @@ TEST(testCase, function_Test10) { sqlCheck("select block_dist() from `t.1abc`", true); sqlCheck("select block_dist(a) from `t.1abc`", false); sqlCheck("select count(*) from `t.1abc` interval(1s) group by a", false); + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// + sqlCheck("select length119(a,b) from `t.1abc`", false); + sqlCheck("select length(a,b) from `t.1abc`", false); + sqlCheck("select block_dist() + 20 from `t.1abc`", false); + sqlCheck("select top(a, 20), count(b) from `t.1abc`", false); + sqlCheck("select count(b), c from `t.1abc`", false); + sqlCheck("select last_row(*), count(b) from `t.1abc`", false); + sqlCheck("select last_row(a, b) + 20 from `t.1abc`", false); + sqlCheck("select last_row(count(*)) from `t.1abc`", false); } TEST(testCase, function_Test6) { diff --git a/source/libs/planner/src/planner.c b/source/libs/planner/src/planner.c index e70b4a1280e8348844530e46f7bacdd962774a03..804fe5c3bc59e083ec0731e724ccb5ade77595d0 100644 --- a/source/libs/planner/src/planner.c +++ b/source/libs/planner/src/planner.c @@ -217,42 +217,12 @@ static SQueryPlanNode* doAddTableColumnNode(SQueryStmtInfo* pQueryInfo, STableMe return pNode; } -static int32_t getFunctionLevel(SQueryStmtInfo* pQueryInfo) { - int32_t n = 10; - - int32_t level = 0; - for(int32_t i = 0; i < n; ++i) { - SArray* pList = pQueryInfo->exprList[i]; - if (taosArrayGetSize(pList) > 0) { - level += 1; - } - } - - return level; -} - -static SQueryPlanNode* createOneQueryPlanNode(SArray* p, SQueryPlanNode* pNode, SExprInfo* pExpr, SQueryTableInfo* info) { - if (pExpr->pExpr->nodeType == TEXPR_FUNCTION_NODE) { - bool aggregateFunc = qIsAggregateFunction(pExpr->pExpr->_function.functionName); - if (aggregateFunc) { - int32_t numOfOutput = (int32_t)taosArrayGetSize(p); - return createQueryNode(QNODE_AGGREGATE, "Aggregate", &pNode, 1, p->pData, numOfOutput, info, NULL); - } else { - int32_t numOfOutput = (int32_t)taosArrayGetSize(p); - return createQueryNode(QNODE_PROJECT, "Projection", &pNode, 1, p->pData, numOfOutput, info, NULL); - } - } else { - int32_t numOfOutput = (int32_t)taosArrayGetSize(p); - return createQueryNode(QNODE_PROJECT, "Projection", &pNode, 1, p->pData, numOfOutput, info, NULL); - } -} - static SQueryPlanNode* doCreateQueryPlanForSingleTableImpl(SQueryStmtInfo* pQueryInfo, SQueryPlanNode* pNode, SQueryTableInfo* info) { // group by column not by tag size_t numOfGroupCols = taosArrayGetSize(pQueryInfo->groupbyExpr.columnInfo); // check for aggregation - int32_t level = getFunctionLevel(pQueryInfo); + int32_t level = getExprFunctionLevel(pQueryInfo); for(int32_t i = level - 1; i >= 0; --i) { SArray* p = pQueryInfo->exprList[i]; @@ -344,7 +314,7 @@ static bool isAllAggExpr(SArray* pList) { static void exprInfoPushDown(SQueryStmtInfo* pQueryInfo) { assert(pQueryInfo != NULL); - size_t level = getFunctionLevel(pQueryInfo); + size_t level = getExprFunctionLevel(pQueryInfo); for(int32_t i = 0; i < level - 1; ++i) { SArray* p = pQueryInfo->exprList[i];