[td-10564] refactor query statement parse procedure.
This commit is contained in:
		
							parent
							
								
									0fcbd2f52c
								
							
						
					
					
						commit
						c3881e1a53
					
				|  | @ -76,6 +76,336 @@ static int32_t evaluateImpl(tSqlExpr* pExpr, int32_t tsPrecision) { | |||
|   return  TSDB_CODE_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| int32_t validateSqlNode(SSqlNode* pSqlNode, SQueryStmtInfo* pQueryInfo, char* msg, int32_t msgBufLen) { | ||||
|   assert(pSqlNode != NULL && (pSqlNode->from == NULL || taosArrayGetSize(pSqlNode->from->list) > 0)); | ||||
| 
 | ||||
|   const char* msg1 = "point interpolation query needs timestamp"; | ||||
|   const char* msg2 = "too many tables in from clause"; | ||||
|   const char* msg3 = "start(end) time of query range required or time range too large"; | ||||
|   const char* msg4 = "interval query not supported, since the result of sub query not include valid timestamp column"; | ||||
|   const char* msg5 = "only tag query not compatible with normal column filter"; | ||||
|   const char* msg6 = "not support stddev/percentile/interp in the outer query yet"; | ||||
|   const char* msg7 = "derivative/twa/irate requires timestamp column exists in subquery"; | ||||
|   const char* msg8 = "condition missing for join query"; | ||||
|   const char* msg9 = "not support 3 level select"; | ||||
| 
 | ||||
|   int32_t  code = TSDB_CODE_SUCCESS; | ||||
|   STableMetaInfo  *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0); | ||||
|   if (pTableMetaInfo == NULL) { | ||||
|     pTableMetaInfo = tscAddEmptyMetaInfo(pQueryInfo); | ||||
|   } | ||||
| 
 | ||||
|   /*
 | ||||
|    * handle the sql expression without from subclause | ||||
|    * select server_status(); | ||||
|    * select server_version(); | ||||
|    * select client_version(); | ||||
|    * select database(); | ||||
|    */ | ||||
|   if (pSqlNode->from == NULL) { | ||||
|     assert(pSqlNode->fillType == NULL && pSqlNode->pGroupby == NULL && pSqlNode->pWhere == NULL && | ||||
|            pSqlNode->pSortOrder == NULL); | ||||
|     return doLocalQueryProcess(pCmd, pQueryInfo, pSqlNode); | ||||
|   } | ||||
| 
 | ||||
|   if (pSqlNode->from->type == SQL_NODE_FROM_SUBQUERY) { | ||||
|     clearAllTableMetaInfo(pQueryInfo, false, pSql->self); | ||||
|     pQueryInfo->numOfTables = 0; | ||||
| 
 | ||||
|     // parse the subquery in the first place
 | ||||
|     int32_t numOfSub = (int32_t)taosArrayGetSize(pSqlNode->from->list); | ||||
|     for (int32_t i = 0; i < numOfSub; ++i) { | ||||
|       // check if there is 3 level select
 | ||||
|       SRelElementPair* subInfo = taosArrayGet(pSqlNode->from->list, i); | ||||
|       SSqlNode* p = taosArrayGetP(subInfo->pSubquery, 0); | ||||
|       if (p->from->type == SQL_NODE_FROM_SUBQUERY) { | ||||
|         return parserSetInvalidOperatorMsg(msg, msgBufLen, msg9); | ||||
|       } | ||||
| 
 | ||||
|       code = doValidateSubquery(pSqlNode, i, pSql, pQueryInfo, tscGetErrorMsgPayload(pCmd)); | ||||
|       if (code != TSDB_CODE_SUCCESS) { | ||||
|         return code; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     int32_t timeWindowQuery = | ||||
|         (TPARSER_HAS_TOKEN(pSqlNode->interval.interval) || TPARSER_HAS_TOKEN(pSqlNode->sessionVal.gap)); | ||||
|     TSDB_QUERY_SET_TYPE(pQueryInfo->type, TSDB_QUERY_TYPE_TABLE_QUERY); | ||||
| 
 | ||||
|     // parse the group by clause in the first place
 | ||||
|     if (validateGroupbyNode(pQueryInfo, pSqlNode->pGroupby, pCmd) != TSDB_CODE_SUCCESS) { | ||||
|       return TSDB_CODE_TSC_INVALID_OPERATION; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     if (validateSelectNodeList(pCmd, pQueryInfo, pSqlNode->pSelNodeList, false, timeWindowQuery, true) != | ||||
|         TSDB_CODE_SUCCESS) { | ||||
|       return TSDB_CODE_TSC_INVALID_OPERATION; | ||||
|     } | ||||
| 
 | ||||
|     // todo NOT support yet
 | ||||
|     for (int32_t i = 0; i < tscNumOfExprs(pQueryInfo); ++i) { | ||||
|       SExprInfo* pExpr = tscExprGet(pQueryInfo, i); | ||||
|       int32_t    f = pExpr->base.functionId; | ||||
|       if (f == TSDB_FUNC_STDDEV || f == TSDB_FUNC_PERCT || f == TSDB_FUNC_INTERP) { | ||||
|         return parserSetInvalidOperatorMsg(msg, msgBufLen, msg6); | ||||
|       } | ||||
| 
 | ||||
|       if ((timeWindowQuery || pQueryInfo->stateWindow) && f == TSDB_FUNC_LAST) { | ||||
|         pExpr->base.numOfParams = 1; | ||||
|         pExpr->base.param[0].i64 = TSDB_ORDER_ASC; | ||||
|         pExpr->base.param[0].nType = TSDB_DATA_TYPE_INT; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     STableMeta* pTableMeta = tscGetMetaInfo(pQueryInfo, 0)->pTableMeta; | ||||
|     SSchema*    pSchema = tscGetTableColumnSchema(pTableMeta, 0); | ||||
| 
 | ||||
|     if (pSchema->type != TSDB_DATA_TYPE_TIMESTAMP) { | ||||
|       int32_t numOfExprs = (int32_t)tscNumOfExprs(pQueryInfo); | ||||
| 
 | ||||
|       for (int32_t i = 0; i < numOfExprs; ++i) { | ||||
|         SExprInfo* pExpr = tscExprGet(pQueryInfo, i); | ||||
| 
 | ||||
|         int32_t f = pExpr->base.functionId; | ||||
|         if (f == TSDB_FUNC_DERIVATIVE || f == TSDB_FUNC_TWA || f == TSDB_FUNC_IRATE) { | ||||
|           return parserSetInvalidOperatorMsg(msg, msgBufLen, msg7); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     // validate the query filter condition info
 | ||||
|     if (pSqlNode->pWhere != NULL) { | ||||
|       if (validateWhereNode(pQueryInfo, &pSqlNode->pWhere, pSql) != TSDB_CODE_SUCCESS) { | ||||
|         return TSDB_CODE_TSC_INVALID_OPERATION; | ||||
|       } | ||||
|     } else { | ||||
|       if (pQueryInfo->numOfTables > 1) { | ||||
|         return parserSetInvalidOperatorMsg(msg, msgBufLen, msg8); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     // validate the interval info
 | ||||
|     if (validateIntervalNode(pSql, pQueryInfo, pSqlNode) != TSDB_CODE_SUCCESS) { | ||||
|       return TSDB_CODE_TSC_INVALID_OPERATION; | ||||
|     } else { | ||||
|       if (validateSessionNode(pCmd, pQueryInfo, pSqlNode) != TSDB_CODE_SUCCESS) { | ||||
|         return TSDB_CODE_TSC_INVALID_OPERATION; | ||||
|       } | ||||
| 
 | ||||
|       // parse the window_state
 | ||||
|       if (validateStateWindowNode(pCmd, pQueryInfo, pSqlNode, false) != TSDB_CODE_SUCCESS) { | ||||
|         return TSDB_CODE_TSC_INVALID_OPERATION; | ||||
|       } | ||||
| 
 | ||||
|       if (isTimeWindowQuery(pQueryInfo)) { | ||||
|         // check if the first column of the nest query result is timestamp column
 | ||||
|         SColumn* pCol = taosArrayGetP(pQueryInfo->colList, 0); | ||||
|         if (pCol->info.type != TSDB_DATA_TYPE_TIMESTAMP) { | ||||
|           return parserSetInvalidOperatorMsg(msg, msgBufLen, msg4); | ||||
|         } | ||||
| 
 | ||||
|         if (validateFunctionsInIntervalOrGroupbyQuery(pCmd, pQueryInfo) != TSDB_CODE_SUCCESS) { | ||||
|           return TSDB_CODE_TSC_INVALID_OPERATION; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     // disable group result mixed up if interval/session window query exists.
 | ||||
|     if (isTimeWindowQuery(pQueryInfo)) { | ||||
|       size_t num = taosArrayGetSize(pQueryInfo->pUpstream); | ||||
|       for(int32_t i = 0; i < num; ++i) { | ||||
|         SQueryInfo* pUp = taosArrayGetP(pQueryInfo->pUpstream, i); | ||||
|         pUp->multigroupResult = false; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     // parse the having clause in the first place
 | ||||
|     int32_t joinQuery = (pSqlNode->from != NULL && taosArrayGetSize(pSqlNode->from->list) > 1); | ||||
|     if (validateHavingClause(pQueryInfo, pSqlNode->pHaving, pCmd, pSqlNode->pSelNodeList, joinQuery, timeWindowQuery) != | ||||
|         TSDB_CODE_SUCCESS) { | ||||
|       return TSDB_CODE_TSC_INVALID_OPERATION; | ||||
|     } | ||||
| 
 | ||||
|     if ((code = validateLimitNode(pCmd, pQueryInfo, pSqlNode, pSql)) != TSDB_CODE_SUCCESS) { | ||||
|       return code; | ||||
|     } | ||||
| 
 | ||||
|     // set order by info
 | ||||
|     if (validateOrderbyNode(pCmd, pQueryInfo, pSqlNode, tscGetTableSchema(pTableMeta)) != TSDB_CODE_SUCCESS) { | ||||
|       return TSDB_CODE_TSC_INVALID_OPERATION; | ||||
|     } | ||||
| 
 | ||||
|     if ((code = doFunctionsCompatibleCheck(pCmd, pQueryInfo, tscGetErrorMsgPayload(pCmd))) != TSDB_CODE_SUCCESS) { | ||||
|       return code; | ||||
|     } | ||||
| 
 | ||||
| //    updateFunctionInterBuf(pQueryInfo, false);
 | ||||
|     updateLastScanOrderIfNeeded(pQueryInfo); | ||||
| 
 | ||||
|     if ((code = validateFillNode(pCmd, pQueryInfo, pSqlNode)) != TSDB_CODE_SUCCESS) { | ||||
|       return code; | ||||
|     } | ||||
|   } else { | ||||
|     pQueryInfo->command = TSDB_SQL_SELECT; | ||||
| 
 | ||||
|     size_t numOfTables = taosArrayGetSize(pSqlNode->from->list); | ||||
|     if (numOfTables > TSDB_MAX_JOIN_TABLE_NUM) { | ||||
|       return parserSetInvalidOperatorMsg(msg, msgBufLen, msg2); | ||||
|     } | ||||
| 
 | ||||
|     // set all query tables, which are maybe more than one.
 | ||||
|     code = doLoadAllTableMeta(pSql, pQueryInfo, pSqlNode, (int32_t) numOfTables); | ||||
|     if (code != TSDB_CODE_SUCCESS) { | ||||
|       return code; | ||||
|     } | ||||
| 
 | ||||
|     bool isSTable = UTIL_TABLE_IS_SUPER_TABLE(pTableMetaInfo); | ||||
| 
 | ||||
|     int32_t type = isSTable? TSDB_QUERY_TYPE_STABLE_QUERY:TSDB_QUERY_TYPE_TABLE_QUERY; | ||||
|     TSDB_QUERY_SET_TYPE(pQueryInfo->type, type); | ||||
| 
 | ||||
|     // parse the group by clause in the first place
 | ||||
|     if (validateGroupbyNode(pQueryInfo, pSqlNode->pGroupby, pCmd) != TSDB_CODE_SUCCESS) { | ||||
|       return TSDB_CODE_TSC_INVALID_OPERATION; | ||||
|     } | ||||
|     pQueryInfo->onlyHasTagCond = true; | ||||
|     // set where info
 | ||||
|     if (pSqlNode->pWhere != NULL) { | ||||
|       if (validateWhereNode(pQueryInfo, &pSqlNode->pWhere, pSql) != TSDB_CODE_SUCCESS) { | ||||
|         return TSDB_CODE_TSC_INVALID_OPERATION; | ||||
|       } | ||||
| 
 | ||||
|       pSqlNode->pWhere = NULL; | ||||
|     } else { | ||||
|       if (taosArrayGetSize(pSqlNode->from->list) > 1) { // Cross join not allowed yet
 | ||||
|         return parserSetInvalidOperatorMsg(msg, msgBufLen, "cross join not supported yet"); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     int32_t joinQuery = (pSqlNode->from != NULL && taosArrayGetSize(pSqlNode->from->list) > 1); | ||||
|     int32_t timeWindowQuery = | ||||
|         (TPARSER_HAS_TOKEN(pSqlNode->interval.interval) || TPARSER_HAS_TOKEN(pSqlNode->sessionVal.gap)); | ||||
| 
 | ||||
|     if (validateSelectNodeList(pCmd, pQueryInfo, pSqlNode->pSelNodeList, joinQuery, timeWindowQuery, false) != | ||||
|         TSDB_CODE_SUCCESS) { | ||||
|       return TSDB_CODE_TSC_INVALID_OPERATION; | ||||
|     } | ||||
| 
 | ||||
|     if (isSTable && tscQueryTags(pQueryInfo) && pQueryInfo->distinct && !pQueryInfo->onlyHasTagCond) { | ||||
|       return TSDB_CODE_TSC_INVALID_OPERATION; | ||||
|     } | ||||
| 
 | ||||
|     // parse the window_state
 | ||||
|     if (validateStateWindowNode(pCmd, pQueryInfo, pSqlNode, isSTable) != TSDB_CODE_SUCCESS) { | ||||
|       return TSDB_CODE_TSC_INVALID_OPERATION; | ||||
|     } | ||||
| 
 | ||||
|     // set order by info
 | ||||
|     if (validateOrderbyNode(pCmd, pQueryInfo, pSqlNode, tscGetTableSchema(pTableMetaInfo->pTableMeta)) != | ||||
|         TSDB_CODE_SUCCESS) { | ||||
|       return TSDB_CODE_TSC_INVALID_OPERATION; | ||||
|     } | ||||
| 
 | ||||
|     // set interval value
 | ||||
|     if (validateIntervalNode(pSql, pQueryInfo, pSqlNode) != TSDB_CODE_SUCCESS) { | ||||
|       return TSDB_CODE_TSC_INVALID_OPERATION; | ||||
|     } | ||||
| 
 | ||||
|     if (tscQueryTags(pQueryInfo)) { | ||||
|       SExprInfo* pExpr1 = tscExprGet(pQueryInfo, 0); | ||||
| 
 | ||||
|       if (pExpr1->base.functionId != TSDB_FUNC_TID_TAG) { | ||||
|         if ((pQueryInfo->colCond && taosArrayGetSize(pQueryInfo->colCond) > 0) || IS_TSWINDOW_SPECIFIED(pQueryInfo->window))  { | ||||
|           return parserSetInvalidOperatorMsg(msg, msgBufLen, msg5); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     // parse the having clause in the first place
 | ||||
|     if (validateHavingClause(pQueryInfo, pSqlNode->pHaving, pCmd, pSqlNode->pSelNodeList, joinQuery, timeWindowQuery) != | ||||
|         TSDB_CODE_SUCCESS) { | ||||
|       return TSDB_CODE_TSC_INVALID_OPERATION; | ||||
|     } | ||||
| 
 | ||||
|     /*
 | ||||
|      * transfer sql functions that need secondary merge into another format | ||||
|      * in dealing with super table queries such as: count/first/last | ||||
|      */ | ||||
|     if (validateSessionNode(pCmd, pQueryInfo, pSqlNode) != TSDB_CODE_SUCCESS) { | ||||
|       return TSDB_CODE_TSC_INVALID_OPERATION; | ||||
|     } | ||||
| 
 | ||||
|     if (isTimeWindowQuery(pQueryInfo) && (validateFunctionsInIntervalOrGroupbyQuery(pCmd, pQueryInfo) != TSDB_CODE_SUCCESS)) { | ||||
|       return TSDB_CODE_TSC_INVALID_OPERATION; | ||||
|     } | ||||
| 
 | ||||
|     if (isSTable) { | ||||
|       tscTansformFuncForSTableQuery(pQueryInfo); | ||||
|       if (hasUnsupportFunctionsForSTableQuery(pCmd, pQueryInfo)) { | ||||
|         return TSDB_CODE_TSC_INVALID_OPERATION; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     // no result due to invalid query time range
 | ||||
|     if (pQueryInfo->window.skey > pQueryInfo->window.ekey) { | ||||
|       pQueryInfo->command = TSDB_SQL_RETRIEVE_EMPTY_RESULT; | ||||
|       return TSDB_CODE_SUCCESS; | ||||
|     } | ||||
| 
 | ||||
|     if (!hasTimestampForPointInterpQuery(pQueryInfo)) { | ||||
|       return parserSetInvalidOperatorMsg(msg, msgBufLen, msg1); | ||||
|     } | ||||
| 
 | ||||
|     // in case of join query, time range is required.
 | ||||
|     if (QUERY_IS_JOIN_QUERY(pQueryInfo->type)) { | ||||
|       uint64_t timeRange = (uint64_t)pQueryInfo->window.ekey - pQueryInfo->window.skey; | ||||
|       if (timeRange == 0 && pQueryInfo->window.skey == 0) { | ||||
|         return parserSetInvalidOperatorMsg(msg, msgBufLen, msg3); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     if ((code = validateLimitNode(pCmd, pQueryInfo, pSqlNode, pSql)) != TSDB_CODE_SUCCESS) { | ||||
|       return code; | ||||
|     } | ||||
| 
 | ||||
|     if ((code = doFunctionsCompatibleCheck(pCmd, pQueryInfo,tscGetErrorMsgPayload(pCmd))) != TSDB_CODE_SUCCESS) { | ||||
|       return code; | ||||
|     } | ||||
| 
 | ||||
|     updateLastScanOrderIfNeeded(pQueryInfo); | ||||
|     tscFieldInfoUpdateOffset(pQueryInfo); | ||||
| //    updateFunctionInterBuf(pQueryInfo, isSTable);
 | ||||
| 
 | ||||
|     if ((code = validateFillNode(pCmd, pQueryInfo, pSqlNode)) != TSDB_CODE_SUCCESS) { | ||||
|       return code; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   { // set the query info
 | ||||
|     pQueryInfo->projectionQuery = tscIsProjectionQuery(pQueryInfo); | ||||
|     pQueryInfo->hasFilter = tscHasColumnFilter(pQueryInfo); | ||||
|     pQueryInfo->simpleAgg = isSimpleAggregateRv(pQueryInfo); | ||||
|     pQueryInfo->onlyTagQuery = onlyTagPrjFunction(pQueryInfo); | ||||
|     pQueryInfo->groupbyColumn = tscGroupbyColumn(pQueryInfo); | ||||
|     pQueryInfo->arithmeticOnAgg   = tsIsArithmeticQueryOnAggResult(pQueryInfo); | ||||
|     pQueryInfo->orderProjectQuery = tscOrderedProjectionQueryOnSTable(pQueryInfo, 0); | ||||
| 
 | ||||
|     SExprInfo** p = NULL; | ||||
|     int32_t numOfExpr = 0; | ||||
|     pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0); | ||||
|     code = createProjectionExpr(pQueryInfo, pTableMetaInfo, &p, &numOfExpr); | ||||
|     if (pQueryInfo->exprList1 == NULL) { | ||||
|       pQueryInfo->exprList1 = taosArrayInit(4, POINTER_BYTES); | ||||
|     } | ||||
| 
 | ||||
|     taosArrayAddBatch(pQueryInfo->exprList1, (void*) p, numOfExpr); | ||||
|     tfree(p); | ||||
|   } | ||||
| 
 | ||||
|   return TSDB_CODE_SUCCESS;  // Does not build query message here
 | ||||
| } | ||||
| 
 | ||||
| int32_t evaluateSqlNode(SSqlNode* pNode, int32_t tsPrecision, char* msg, int32_t msgBufLen) { | ||||
|   assert(pNode != NULL && msg != NULL && msgBufLen > 0); | ||||
|   if (pNode->pWhere == NULL) { | ||||
|  | @ -534,15 +864,33 @@ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQuer | |||
| #endif | ||||
| 
 | ||||
|   SMetaReq req = {0}; | ||||
|   SMetaData data = {0}; | ||||
| 
 | ||||
|   // TODO: check if the qnode info has been cached already
 | ||||
|   req.qNodeEpset = true; | ||||
|   code = qParserExtractRequestedMetaInfo(pInfo, &req, msgBuf, msgBufLen); | ||||
|   if (code != TSDB_CODE_SUCCESS) { | ||||
|     return code; | ||||
|   } | ||||
| 
 | ||||
|   // load the meta data from catalog
 | ||||
| 
 | ||||
|   code = catalogGetMetaData(pCatalog, &req, &data); | ||||
|   if (code != TSDB_CODE_SUCCESS) { | ||||
|     return code; | ||||
|   } | ||||
| 
 | ||||
|   // evaluate the sqlnode
 | ||||
|   STableMeta* pTableMeta = (STableMeta*) taosArrayGetP(data.pTableMeta, 0); | ||||
|   assert(pTableMeta != NULL); | ||||
| 
 | ||||
|   size_t len = taosArrayGetSize(pInfo->list); | ||||
|   for(int32_t i = 0; i < len; ++i) { | ||||
|     SSqlNode* p = taosArrayGetP(pInfo->list, i); | ||||
|     code = evaluateSqlNode(p, pTableMeta->tableInfo.precision, msgBuf, msgBufLen); | ||||
|     if (code != TSDB_CODE_SUCCESS) { | ||||
|       return code; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // convert the sqlnode into queryinfo
 | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue