diff --git a/include/libs/nodes/plannodes.h b/include/libs/nodes/plannodes.h index 5d00e373cc..6690940a41 100644 --- a/include/libs/nodes/plannodes.h +++ b/include/libs/nodes/plannodes.h @@ -22,7 +22,6 @@ extern "C" { #include "querynodes.h" #include "query.h" -#include "tmsg.h" typedef struct SLogicNode { ENodeType type; diff --git a/include/libs/parser/parser.h b/include/libs/parser/parser.h index d48c059ef1..4ee401f349 100644 --- a/include/libs/parser/parser.h +++ b/include/libs/parser/parser.h @@ -20,86 +20,7 @@ extern "C" { #endif -#if 0 - -#include "parsenodes.h" - -typedef struct SParseContext { - uint64_t requestId; - int32_t acctId; - const char *db; - void *pTransporter; - SEpSet mgmtEpSet; - const char *pSql; // sql string - size_t sqlLen; // length of the sql string - char *pMsg; // extended error message if exists to help identifying the problem in sql statement. - int32_t msgLen; // max length of the msg - - struct SCatalog *pCatalog; -} SParseContext; - -/** - * Parse the sql statement and then return the SQueryStmtInfo as the result of bounded AST. - * @param pSql sql string - * @param length length of the sql string - * @param id operator id, generated by uuid generator - * @param msg extended error message if exists. - * @return error code - */ -int32_t qParseQuerySql(SParseContext* pContext, SQueryNode** pQueryNode); - -/** - * Return true if it is a ddl/dcl sql statement - * @param pQuery - * @return - */ -bool qIsDdlQuery(const SQueryNode* pQueryNode); - -/** - * Destroy logic query plan - * @param pQueryNode - */ -void qDestroyQuery(SQueryNode* pQueryNode); - -/** - * Convert a normal sql statement to only query tags information to enable that the subscribe client can be aware quickly of the true vgroup ids that - * involved in the subscribe procedure. - * @param pSql - * @param length - * @param pConvertSql - * @return - */ -int32_t qParserConvertSql(const char* pStr, size_t length, char** pConvertSql); - -void assignExprInfo(SExprInfo* dst, const SExprInfo* src); -void columnListCopy(SArray* dst, const SArray* src, uint64_t uid); -void columnListDestroy(SArray* pColumnList); - -void dropAllExprInfo(SArray** pExprInfo, int32_t numOfLevel); -void dropOneLevelExprInfo(SArray* pExprInfo); - -typedef struct SSourceParam { - SArray *pExprNodeList; //Array - SArray *pColumnList; //Array - int32_t num; -} 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 copyAllExprInfo(SArray* dst, const SArray* src, bool deepcopy); -int32_t getExprFunctionLevel(const SQueryStmtInfo* pQueryInfo); - -STableMetaInfo* getMetaInfo(const SQueryStmtInfo* pQueryInfo, int32_t tableIndex); -SSchema *getOneColumnSchema(const STableMeta* pTableMeta, int32_t colIndex); - -int32_t getNewResColId(); -void addIntoSourceParam(SSourceParam* pSourceParam, tExprNode* pNode, SColumn* pColumn); -SExprInfo* createBinaryExprInfo(struct tExprNode* pNode, SSchema* pResSchema); - -#else - #include "querynodes.h" -#include "tmsg.h" typedef struct SParseContext { uint64_t requestId; @@ -125,8 +46,6 @@ int32_t qParseQuerySql(SParseContext* pCxt, SQuery** pQuery); void qDestroyQuery(SQuery* pQueryNode); -#endif - #ifdef __cplusplus } #endif diff --git a/include/libs/planner/planner.h b/include/libs/planner/planner.h index ced96ba46c..9d316be54d 100644 --- a/include/libs/planner/planner.h +++ b/include/libs/planner/planner.h @@ -20,199 +20,7 @@ extern "C" { #endif -#if 0 - -#include "query.h" -#include "tmsg.h" -#include "tarray.h" -#include "trpc.h" - -#define QUERY_TYPE_MERGE 1 -#define QUERY_TYPE_PARTIAL 2 -#define QUERY_TYPE_SCAN 3 -#define QUERY_TYPE_MODIFY 4 - -enum OPERATOR_TYPE_E { - OP_Unknown, -#define INCLUDE_AS_ENUM -#include "plannerOp.h" -#undef INCLUDE_AS_ENUM - OP_TotalNum -}; - -enum DATASINK_TYPE_E { - DSINK_Unknown, - DSINK_Dispatch, - DSINK_Insert, - DSINK_TotalNum -}; - -struct SEpSet; -struct SQueryStmtInfo; - -typedef SSchema SSlotSchema; - -typedef struct SDataBlockSchema { - SSlotSchema *pSchema; - int32_t numOfCols; // number of columns - int32_t resultRowSize; - int16_t precision; -} SDataBlockSchema; - -typedef struct SQueryNodeBasicInfo { - int32_t type; // operator type - const char *name; // operator name -} SQueryNodeBasicInfo; - -typedef struct SDataSink { - SQueryNodeBasicInfo info; - SDataBlockSchema schema; -} SDataSink; - -typedef struct SDataDispatcher { - SDataSink sink; -} SDataDispatcher; - -typedef struct SDataInserter { - SDataSink sink; - int32_t numOfTables; - uint32_t size; - char *pData; -} SDataInserter; - -typedef struct SPhyNode { - SQueryNodeBasicInfo info; - SArray *pTargets; // target list to be computed or scanned at this node - SArray *pConditions; // implicitly-ANDed qual conditions - SDataBlockSchema targetSchema; - // children plan to generated result for current node to process - // in case of join, multiple plan nodes exist. - SArray *pChildren; - struct SPhyNode *pParent; -} SPhyNode; - -typedef struct SScanPhyNode { - SPhyNode node; - uint64_t uid; // unique id of the table - int8_t tableType; - int32_t order; // scan order: TSDB_ORDER_ASC|TSDB_ORDER_DESC - int32_t count; // repeat count - int32_t reverse; // reverse scan count -} SScanPhyNode; - -typedef SScanPhyNode SSystemTableScanPhyNode; -typedef SScanPhyNode STagScanPhyNode; - -typedef struct STableScanPhyNode { - SScanPhyNode scan; - uint8_t scanFlag; // denotes reversed scan of data or not - STimeWindow window; - SArray *pTagsConditions; // implicitly-ANDed tag qual conditions -} STableScanPhyNode; - -typedef STableScanPhyNode STableSeqScanPhyNode; - -typedef struct SProjectPhyNode { - SPhyNode node; -} SProjectPhyNode; - -typedef struct SDownstreamSource { - SQueryNodeAddr addr; - uint64_t taskId; - uint64_t schedId; -} SDownstreamSource; - -typedef struct SExchangePhyNode { - SPhyNode node; - uint64_t srcTemplateId; // template id of datasource suplans - SArray *pSrcEndPoints; // SArray, scheduler fill by calling qSetSuplanExecutionNode -} SExchangePhyNode; - -typedef enum EAggAlgo { - AGG_ALGO_PLAIN = 1, // simple agg across all input rows - AGG_ALGO_SORTED, // grouped agg, input must be sorted - AGG_ALGO_HASHED // grouped agg, use internal hashtable -} EAggAlgo; - -typedef enum EAggSplit { - AGG_SPLIT_PRE = 1, // first level agg, maybe don't need calculate the final result - AGG_SPLIT_FINAL // second level agg, must calculate the final result -} EAggSplit; - -typedef struct SAggPhyNode { - SPhyNode node; - EAggAlgo aggAlgo; // algorithm used by agg operator - EAggSplit aggSplit; // distributed splitting mode - SArray *pExprs; // SExprInfo list, these are expression list of group_by_clause and parameter expression of aggregate function - SArray *pGroupByList; // SColIndex list, but these must be column node -} SAggPhyNode; - -typedef struct SSubplanId { - uint64_t queryId; - uint64_t templateId; - uint64_t subplanId; -} SSubplanId; - -typedef struct SSubplan { - SSubplanId id; // unique id of the subplan - int32_t type; // QUERY_TYPE_MERGE|QUERY_TYPE_PARTIAL|QUERY_TYPE_SCAN|QUERY_TYPE_MODIFY - int32_t msgType; // message type for subplan, used to denote the send message type to vnode. - int32_t level; // the execution level of current subplan, starting from 0 in a top-down manner. - SQueryNodeAddr execNode; // for the scan/modify subplan, the optional execution node - SArray *pChildren; // the datasource subplan,from which to fetch the result - SArray *pParents; // the data destination subplan, get data from current subplan - SPhyNode *pNode; // physical plan of current subplan - SDataSink *pDataSink; // data of the subplan flow into the datasink -} SSubplan; - -typedef struct SQueryDag { - uint64_t queryId; - int32_t numOfSubplans; - SArray *pSubplans; // SArray*>. The execution level of subplan, starting from 0. -} SQueryDag; - -struct SQueryNode; - - /** - * Create the physical plan for the query, according to the AST. - * @param pQueryInfo - * @param pDag - * @param requestId - * @return - */ - int32_t qCreateQueryDag(const struct SQueryNode* pNode, struct SQueryDag** pDag, SSchema** pResSchema, int32_t* numOfCols, SArray* pNodeList, uint64_t requestId); - -// Set datasource of this subplan, multiple calls may be made to a subplan. -// @subplan subplan to be schedule -// @templateId templateId of a group of datasource subplans of this @subplan -// @ep one execution location of this group of datasource subplans -void qSetSubplanExecutionNode(SSubplan* subplan, uint64_t templateId, SDownstreamSource* pSource); - -int32_t qExplainQuery(const struct SQueryNode* pQueryInfo, struct SEpSet* pQnode, char** str); - -/** - * Convert to subplan to string for the scheduler to send to the executor - */ -int32_t qSubPlanToString(const SSubplan* subplan, char** str, int32_t* len); - -int32_t qStringToSubplan(const char* str, SSubplan** subplan); - -void qDestroySubplan(SSubplan* pSubplan); - -/** - * Destroy the physical plan. - * @param pQueryPhyNode - * @return - */ -void qDestroyQueryDag(SQueryDag* pDag); - -char* qDagToString(const SQueryDag* pDag); -SQueryDag* qStringToDag(const char* pStr); - -#else - #include "plannodes.h" -#include "query.h" #define QUERY_TYPE_MERGE 1 #define QUERY_TYPE_PARTIAL 2 @@ -266,8 +74,6 @@ SQueryPlan* qStringToQueryPlan(const char* pStr); void qDestroyQueryPlan(SQueryPlan* pPlan); -#endif - #ifdef __cplusplus } #endif diff --git a/source/client/src/clientImpl.c b/source/client/src/clientImpl.c index 85e7344248..2f6eee2f34 100644 --- a/source/client/src/clientImpl.c +++ b/source/client/src/clientImpl.c @@ -198,20 +198,18 @@ int32_t execDdlQuery(SRequestObj* pRequest, SQuery* pQuery) { int32_t getPlan(SRequestObj* pRequest, SQuery* pQuery, SQueryPlan** pDag, SArray* pNodeList) { // pRequest->type = pQuery->type; - // SSchema* pSchema = NULL; - // int32_t numOfCols = 0; - // int32_t code = qCreateQueryDag(pQuery, pDag, &pSchema, &numOfCols, pNodeList, pRequest->requestId); - // if (code != 0) { - // return code; - // } + SPlanContext cxt = { .queryId = pRequest->requestId, .pAstRoot = pQuery->pRoot }; + int32_t code = qCreateQueryPlan(&cxt, pDag); + if (code != 0) { + return code; + } // if (pQuery->type == TSDB_SQL_SELECT) { // setResSchemaInfo(&pRequest->body.resInfo, pSchema, numOfCols); // pRequest->type = TDMT_VND_QUERY; // } - // tfree(pSchema); - // return code; + return code; } void setResSchemaInfo(SReqResultInfo* pResInfo, const SSchema* pSchema, int32_t numOfCols) { diff --git a/source/libs/parser/inc/astCreateFuncs.h b/source/libs/parser/inc/astCreateFuncs.h index b44e621704..08eae91a38 100644 --- a/source/libs/parser/inc/astCreateFuncs.h +++ b/source/libs/parser/inc/astCreateFuncs.h @@ -20,11 +20,18 @@ extern "C" { #endif -#include "querynodes.h" #include "nodesShowStmts.h" -#include "astCreateContext.h" +#include "parser.h" +#include "querynodes.h" #include "ttoken.h" +typedef struct SAstCreateContext { + SParseContext* pQueryCxt; + bool notSupport; + bool valid; + SNode* pRootNode; +} SAstCreateContext; + extern SToken nil_token; SNode* createRawExprNode(SAstCreateContext* pCxt, const SToken* pToken, SNode* pNode); diff --git a/source/libs/parser/inc/parserImpl.h b/source/libs/parser/inc/parserInt.h similarity index 85% rename from source/libs/parser/inc/parserImpl.h rename to source/libs/parser/inc/parserInt.h index 4ff142ae58..3fb3bbcc7f 100644 --- a/source/libs/parser/inc/parserImpl.h +++ b/source/libs/parser/inc/parserInt.h @@ -13,8 +13,8 @@ * along with this program. If not, see . */ -#ifndef _TD_PARSER_IMPL_H_ -#define _TD_PARSER_IMPL_H_ +#ifndef _TD_PARSER_INT_H_ +#define _TD_PARSER_INT_H_ #ifdef __cplusplus extern "C" { @@ -24,10 +24,9 @@ extern "C" { int32_t doParse(SParseContext* pParseCxt, SQuery** pQuery); int32_t doTranslate(SParseContext* pParseCxt, SQuery* pQuery); -int32_t parseQuerySql(SParseContext* pCxt, SQuery** pQuery); #ifdef __cplusplus } #endif -#endif /*_TD_PARSER_IMPL_H_*/ +#endif /*_TD_PARSER_INT_H_*/ diff --git a/source/libs/parser/inc/parserUtil.h b/source/libs/parser/inc/parserUtil.h index 60f496b994..7d30f97ad1 100644 --- a/source/libs/parser/inc/parserUtil.h +++ b/source/libs/parser/inc/parserUtil.h @@ -13,8 +13,8 @@ * along with this program. If not, see . */ -#ifndef TDENGINE_PARSERUTIL_H -#define TDENGINE_PARSERUTIL_H +#ifndef TDENGINE_PARSER_UTIL_H +#define TDENGINE_PARSER_UTIL_H #ifdef __cplusplus extern "C" { @@ -22,7 +22,6 @@ extern "C" { #include "os.h" #include "query.h" -#include "tmsg.h" #include "ttoken.h" typedef struct SMsgBuf { @@ -54,4 +53,4 @@ STableComInfo getTableInfo(const STableMeta* pTableMeta); } #endif -#endif // TDENGINE_PARSERUTIL_H +#endif // TDENGINE_PARSER_UTIL_H diff --git a/source/libs/parser/src/astCreateContext.c b/source/libs/parser/src/astCreateContext.c deleted file mode 100644 index a8c82780ca..0000000000 --- a/source/libs/parser/src/astCreateContext.c +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the GNU Affero General Public License, version 3 - * or later ("AGPL"), as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include "ttoken.h" -#include "astCreateContext.h" - -int32_t createAstCreateContext(SParseContext* pQueryCxt, SAstCreateContext* pCxt) { - pCxt->pQueryCxt = pQueryCxt; - pCxt->notSupport = false; - pCxt->valid = true; - pCxt->pRootNode = NULL; - return TSDB_CODE_SUCCESS; -} - -int32_t destroyAstCreateContext(SAstCreateContext* pCxt) { - return TSDB_CODE_SUCCESS; -} diff --git a/source/libs/parser/src/astParse.c b/source/libs/parser/src/astParse.c new file mode 100644 index 0000000000..a27f562d42 --- /dev/null +++ b/source/libs/parser/src/astParse.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include "parserInt.h" + +#include "astCreateFuncs.h" +#include "ttoken.h" + +typedef void* (*FMalloc)(size_t); +typedef void (*FFree)(void*); + +extern void* NewParseAlloc(FMalloc); +extern void NewParse(void*, int, SToken, void*); +extern void NewParseFree(void*, FFree); +extern void NewParseTrace(FILE*, char*); + +static uint32_t toNewTokenId(uint32_t tokenId) { + switch (tokenId) { + case TK_OR: + return NEW_TK_OR; + case TK_AND: + return NEW_TK_AND; + case TK_UNION: + return NEW_TK_UNION; + case TK_ALL: + return NEW_TK_ALL; + case TK_MINUS: + return NEW_TK_NK_MINUS; + case TK_PLUS: + return NEW_TK_NK_PLUS; + case TK_STAR: + return NEW_TK_NK_STAR; + case TK_SLASH: + return NEW_TK_NK_SLASH; + case TK_REM: + return NEW_TK_NK_REM; + case TK_SHOW: + return NEW_TK_SHOW; + case TK_DATABASES: + return NEW_TK_DATABASES; + case TK_INTEGER: + return NEW_TK_NK_INTEGER; + case TK_FLOAT: + return NEW_TK_NK_FLOAT; + case TK_STRING: + return NEW_TK_NK_STRING; + case TK_BOOL: + return NEW_TK_NK_BOOL; + case TK_TIMESTAMP: + return NEW_TK_TIMESTAMP; + case TK_VARIABLE: + return NEW_TK_NK_VARIABLE; + case TK_COMMA: + return NEW_TK_NK_COMMA; + case TK_ID: + return NEW_TK_NK_ID; + case TK_LP: + return NEW_TK_NK_LP; + case TK_RP: + return NEW_TK_NK_RP; + case TK_DOT: + return NEW_TK_NK_DOT; + case TK_BETWEEN: + return NEW_TK_BETWEEN; + case TK_NOT: + return NEW_TK_NOT; + case TK_IS: + return NEW_TK_IS; + case TK_NULL: + return NEW_TK_NULL; + case TK_LT: + return NEW_TK_NK_LT; + case TK_GT: + return NEW_TK_NK_GT; + case TK_LE: + return NEW_TK_NK_LE; + case TK_GE: + return NEW_TK_NK_GE; + case TK_NE: + return NEW_TK_NK_NE; + case TK_EQ: + return NEW_TK_NK_EQ; + case TK_LIKE: + return NEW_TK_LIKE; + case TK_MATCH: + return NEW_TK_MATCH; + case TK_NMATCH: + return NEW_TK_NMATCH; + case TK_IN: + return NEW_TK_IN; + case TK_SELECT: + return NEW_TK_SELECT; + case TK_DISTINCT: + return NEW_TK_DISTINCT; + case TK_WHERE: + return NEW_TK_WHERE; + case TK_AS: + return NEW_TK_AS; + case TK_FROM: + return NEW_TK_FROM; + case TK_JOIN: + return NEW_TK_JOIN; + // case TK_PARTITION: + // return NEW_TK_PARTITION; + case TK_SESSION: + return NEW_TK_SESSION; + case TK_STATE_WINDOW: + return NEW_TK_STATE_WINDOW; + case TK_INTERVAL: + return NEW_TK_INTERVAL; + case TK_SLIDING: + return NEW_TK_SLIDING; + case TK_FILL: + return NEW_TK_FILL; + // case TK_VALUE: + // return NEW_TK_VALUE; + case TK_NONE: + return NEW_TK_NONE; + case TK_PREV: + return NEW_TK_PREV; + case TK_LINEAR: + return NEW_TK_LINEAR; + // case TK_NEXT: + // return NEW_TK_NEXT; + case TK_GROUP: + return NEW_TK_GROUP; + case TK_HAVING: + return NEW_TK_HAVING; + case TK_ORDER: + return NEW_TK_ORDER; + case TK_BY: + return NEW_TK_BY; + case TK_ASC: + return NEW_TK_ASC; + case TK_DESC: + return NEW_TK_DESC; + case TK_SLIMIT: + return NEW_TK_SLIMIT; + case TK_SOFFSET: + return NEW_TK_SOFFSET; + case TK_LIMIT: + return NEW_TK_LIMIT; + case TK_OFFSET: + return NEW_TK_OFFSET; + case TK_SPACE: + case NEW_TK_ON: + case NEW_TK_INNER: + break; + default: + printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!tokenId = %d\n", tokenId); + } + return tokenId; +} + +static uint32_t getToken(const char* z, uint32_t* tokenId) { + uint32_t n = tGetToken(z, tokenId); + *tokenId = toNewTokenId(*tokenId); + return n; +} + +static bool isCmd(const SNode* pRootNode) { + if (NULL == pRootNode) { + return true; + } + switch (nodeType(pRootNode)) { + case QUERY_NODE_SELECT_STMT: + return false; + default: + break; + } + return true; +} + +int32_t doParse(SParseContext* pParseCxt, SQuery** pQuery) { + SAstCreateContext cxt = { .pQueryCxt = pParseCxt, .notSupport = false, .valid = true, .pRootNode = NULL}; + void *pParser = NewParseAlloc(malloc); + int32_t i = 0; + while (1) { + SToken t0 = {0}; + if (cxt.pQueryCxt->pSql[i] == 0) { + NewParse(pParser, 0, t0, &cxt); + goto abort_parse; + } + t0.n = getToken((char *)&cxt.pQueryCxt->pSql[i], &t0.type); + t0.z = (char *)(cxt.pQueryCxt->pSql + i); + i += t0.n; + + switch (t0.type) { + case TK_SPACE: + case TK_COMMENT: { + break; + } + case TK_SEMI: { + NewParse(pParser, 0, t0, &cxt); + goto abort_parse; + } + case TK_QUESTION: + case TK_ILLEGAL: { + snprintf(cxt.pQueryCxt->pMsg, cxt.pQueryCxt->msgLen, "unrecognized token: \"%s\"", t0.z); + cxt.valid = false; + goto abort_parse; + } + case TK_HEX: + case TK_OCT: + case TK_BIN: { + snprintf(cxt.pQueryCxt->pMsg, cxt.pQueryCxt->msgLen, "unsupported token: \"%s\"", t0.z); + cxt.valid = false; + goto abort_parse; + } + default: + NewParse(pParser, t0.type, t0, &cxt); + // NewParseTrace(stdout, ""); + if (!cxt.valid) { + goto abort_parse; + } + } + } + +abort_parse: + NewParseFree(pParser, free); + if (cxt.valid) { + *pQuery = calloc(1, sizeof(SQuery)); + (*pQuery)->isCmd = isCmd(cxt.pRootNode); + (*pQuery)->pRoot = cxt.pRootNode; + } + return cxt.valid ? TSDB_CODE_SUCCESS : TSDB_CODE_FAILED; +} diff --git a/source/libs/parser/src/parserImpl.c b/source/libs/parser/src/astTranslate.c similarity index 83% rename from source/libs/parser/src/parserImpl.c rename to source/libs/parser/src/astTranslate.c index 8312a1b0b3..27230b2e79 100644 --- a/source/libs/parser/src/parserImpl.c +++ b/source/libs/parser/src/astTranslate.c @@ -13,238 +13,12 @@ * along with this program. If not, see . */ -#include "parserImpl.h" +#include "parserInt.h" -#include "astCreateContext.h" #include "catalog.h" #include "functionMgt.h" #include "parserUtil.h" -#include "tglobal.h" -#include "tname.h" #include "ttime.h" -#include "ttoken.h" - -typedef void* (*FMalloc)(size_t); -typedef void (*FFree)(void*); - -extern void* NewParseAlloc(FMalloc); -extern void NewParse(void*, int, SToken, void*); -extern void NewParseFree(void*, FFree); -extern void NewParseTrace(FILE*, char*); - -static uint32_t toNewTokenId(uint32_t tokenId) { - switch (tokenId) { - case TK_OR: - return NEW_TK_OR; - case TK_AND: - return NEW_TK_AND; - case TK_UNION: - return NEW_TK_UNION; - case TK_ALL: - return NEW_TK_ALL; - case TK_MINUS: - return NEW_TK_NK_MINUS; - case TK_PLUS: - return NEW_TK_NK_PLUS; - case TK_STAR: - return NEW_TK_NK_STAR; - case TK_SLASH: - return NEW_TK_NK_SLASH; - case TK_REM: - return NEW_TK_NK_REM; - case TK_SHOW: - return NEW_TK_SHOW; - case TK_DATABASES: - return NEW_TK_DATABASES; - case TK_INTEGER: - return NEW_TK_NK_INTEGER; - case TK_FLOAT: - return NEW_TK_NK_FLOAT; - case TK_STRING: - return NEW_TK_NK_STRING; - case TK_BOOL: - return NEW_TK_NK_BOOL; - case TK_TIMESTAMP: - return NEW_TK_TIMESTAMP; - case TK_VARIABLE: - return NEW_TK_NK_VARIABLE; - case TK_COMMA: - return NEW_TK_NK_COMMA; - case TK_ID: - return NEW_TK_NK_ID; - case TK_LP: - return NEW_TK_NK_LP; - case TK_RP: - return NEW_TK_NK_RP; - case TK_DOT: - return NEW_TK_NK_DOT; - case TK_BETWEEN: - return NEW_TK_BETWEEN; - case TK_NOT: - return NEW_TK_NOT; - case TK_IS: - return NEW_TK_IS; - case TK_NULL: - return NEW_TK_NULL; - case TK_LT: - return NEW_TK_NK_LT; - case TK_GT: - return NEW_TK_NK_GT; - case TK_LE: - return NEW_TK_NK_LE; - case TK_GE: - return NEW_TK_NK_GE; - case TK_NE: - return NEW_TK_NK_NE; - case TK_EQ: - return NEW_TK_NK_EQ; - case TK_LIKE: - return NEW_TK_LIKE; - case TK_MATCH: - return NEW_TK_MATCH; - case TK_NMATCH: - return NEW_TK_NMATCH; - case TK_IN: - return NEW_TK_IN; - case TK_SELECT: - return NEW_TK_SELECT; - case TK_DISTINCT: - return NEW_TK_DISTINCT; - case TK_WHERE: - return NEW_TK_WHERE; - case TK_AS: - return NEW_TK_AS; - case TK_FROM: - return NEW_TK_FROM; - case TK_JOIN: - return NEW_TK_JOIN; - // case TK_PARTITION: - // return NEW_TK_PARTITION; - case TK_SESSION: - return NEW_TK_SESSION; - case TK_STATE_WINDOW: - return NEW_TK_STATE_WINDOW; - case TK_INTERVAL: - return NEW_TK_INTERVAL; - case TK_SLIDING: - return NEW_TK_SLIDING; - case TK_FILL: - return NEW_TK_FILL; - // case TK_VALUE: - // return NEW_TK_VALUE; - case TK_NONE: - return NEW_TK_NONE; - case TK_PREV: - return NEW_TK_PREV; - case TK_LINEAR: - return NEW_TK_LINEAR; - // case TK_NEXT: - // return NEW_TK_NEXT; - case TK_GROUP: - return NEW_TK_GROUP; - case TK_HAVING: - return NEW_TK_HAVING; - case TK_ORDER: - return NEW_TK_ORDER; - case TK_BY: - return NEW_TK_BY; - case TK_ASC: - return NEW_TK_ASC; - case TK_DESC: - return NEW_TK_DESC; - case TK_SLIMIT: - return NEW_TK_SLIMIT; - case TK_SOFFSET: - return NEW_TK_SOFFSET; - case TK_LIMIT: - return NEW_TK_LIMIT; - case TK_OFFSET: - return NEW_TK_OFFSET; - case TK_SPACE: - case NEW_TK_ON: - case NEW_TK_INNER: - break; - default: - printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!tokenId = %d\n", tokenId); - } - return tokenId; -} - -static uint32_t getToken(const char* z, uint32_t* tokenId) { - uint32_t n = tGetToken(z, tokenId); - *tokenId = toNewTokenId(*tokenId); - return n; -} - -static bool isCmd(const SNode* pRootNode) { - if (NULL == pRootNode) { - return true; - } - switch (nodeType(pRootNode)) { - case QUERY_NODE_SELECT_STMT: - return false; - default: - break; - } - return true; -} - -int32_t doParse(SParseContext* pParseCxt, SQuery** pQuery) { - SAstCreateContext cxt; - createAstCreateContext(pParseCxt, &cxt); - void *pParser = NewParseAlloc(malloc); - int32_t i = 0; - while (1) { - SToken t0 = {0}; - if (cxt.pQueryCxt->pSql[i] == 0) { - NewParse(pParser, 0, t0, &cxt); - goto abort_parse; - } - t0.n = getToken((char *)&cxt.pQueryCxt->pSql[i], &t0.type); - t0.z = (char *)(cxt.pQueryCxt->pSql + i); - i += t0.n; - - switch (t0.type) { - case TK_SPACE: - case TK_COMMENT: { - break; - } - case TK_SEMI: { - NewParse(pParser, 0, t0, &cxt); - goto abort_parse; - } - case TK_QUESTION: - case TK_ILLEGAL: { - snprintf(cxt.pQueryCxt->pMsg, cxt.pQueryCxt->msgLen, "unrecognized token: \"%s\"", t0.z); - cxt.valid = false; - goto abort_parse; - } - case TK_HEX: - case TK_OCT: - case TK_BIN: { - snprintf(cxt.pQueryCxt->pMsg, cxt.pQueryCxt->msgLen, "unsupported token: \"%s\"", t0.z); - cxt.valid = false; - goto abort_parse; - } - default: - NewParse(pParser, t0.type, t0, &cxt); - // NewParseTrace(stdout, ""); - if (!cxt.valid) { - goto abort_parse; - } - } - } - -abort_parse: - NewParseFree(pParser, free); - destroyAstCreateContext(&cxt); - if (cxt.valid) { - *pQuery = calloc(1, sizeof(SQuery)); - (*pQuery)->isCmd = isCmd(cxt.pRootNode); - (*pQuery)->pRoot = cxt.pRootNode; - } - return cxt.valid ? TSDB_CODE_SUCCESS : TSDB_CODE_FAILED; -} static bool afterGroupBy(ESqlClause clause) { return clause > SQL_CLAUSE_GROUP_BY; @@ -1064,11 +838,3 @@ int32_t doTranslate(SParseContext* pParseCxt, SQuery* pQuery) { } return code; } - -int32_t parseQuerySql(SParseContext* pCxt, SQuery** pQuery) { - int32_t code = doParse(pCxt, pQuery); - if (TSDB_CODE_SUCCESS == code) { - code = doTranslate(pCxt, *pQuery); - } - return code; -} diff --git a/source/libs/parser/src/parser.c b/source/libs/parser/src/parser.c index 599924ab17..075485d49d 100644 --- a/source/libs/parser/src/parser.c +++ b/source/libs/parser/src/parser.c @@ -267,7 +267,7 @@ void qDestroyQuery(SQueryNode* pQueryNode) { #include "parser.h" #include "insertParser.h" -#include "parserImpl.h" +#include "parserInt.h" #include "ttoken.h" static bool isInsertSql(const char* pStr, size_t length) { @@ -281,11 +281,19 @@ static bool isInsertSql(const char* pStr, size_t length) { } while (1); } +static int32_t parseSqlIntoAst(SParseContext* pCxt, SQuery** pQuery) { + int32_t code = doParse(pCxt, pQuery); + if (TSDB_CODE_SUCCESS == code) { + code = doTranslate(pCxt, *pQuery); + } + return code; +} + int32_t qParseQuerySql(SParseContext* pCxt, SQuery** pQuery) { if (isInsertSql(pCxt->pSql, pCxt->sqlLen)) { return parseInsertSql(pCxt, pQuery); } else { - return parseQuerySql(pCxt, pQuery); + return parseSqlIntoAst(pCxt, pQuery); } } diff --git a/source/libs/parser/test/newParserTest.cpp b/source/libs/parser/test/parserTest.cpp similarity index 99% rename from source/libs/parser/test/newParserTest.cpp rename to source/libs/parser/test/parserTest.cpp index d030931cba..b0e6aaf560 100644 --- a/source/libs/parser/test/newParserTest.cpp +++ b/source/libs/parser/test/parserTest.cpp @@ -18,7 +18,7 @@ #include -#include "parserImpl.h" +#include "parserInt.h" using namespace std; using namespace testing; diff --git a/source/libs/planner/inc/plannerImpl.h b/source/libs/planner/inc/plannerInt.h similarity index 61% rename from source/libs/planner/inc/plannerImpl.h rename to source/libs/planner/inc/plannerInt.h index 559d614829..ca7e09dba1 100644 --- a/source/libs/planner/inc/plannerImpl.h +++ b/source/libs/planner/inc/plannerInt.h @@ -20,11 +20,29 @@ extern "C" { #endif -#include "plannodes.h" #include "planner.h" -int32_t createLogicPlan(SNode* pNode, SLogicNode** pLogicNode); +#define CHECK_ALLOC(p, res) \ + do { \ + if (NULL == (p)) { \ + pCxt->errCode = TSDB_CODE_OUT_OF_MEMORY; \ + return (res); \ + } \ + } while (0) + +#define CHECK_CODE(exec, res) \ + do { \ + int32_t code = (exec); \ + if (TSDB_CODE_SUCCESS != code) { \ + pCxt->errCode = code; \ + return (res); \ + } \ + } while (0) + +int32_t createLogicPlan(SPlanContext* pCxt, SLogicNode** pLogicNode); +int32_t optimize(SPlanContext* pCxt, SLogicNode* pLogicNode); int32_t createPhysiPlan(SLogicNode* pLogicNode, SPhysiNode** pPhyNode); +int32_t buildPhysiPlan(SPlanContext* pCxt, SLogicNode* pLogicNode, SQueryPlan** pPlan); #ifdef __cplusplus } diff --git a/source/libs/planner/src/logicPlan.c b/source/libs/planner/src/logicPlan.c index 6ba17f0627..b97248e986 100644 --- a/source/libs/planner/src/logicPlan.c +++ b/source/libs/planner/src/logicPlan.c @@ -13,658 +13,357 @@ * along with this program. If not, see . */ -#if 0 - -#include -#include "function.h" -#include "os.h" -#include "parser.h" #include "plannerInt.h" -typedef struct SFillEssInfo { - int32_t fillType; // fill type - int64_t *val; // fill value -} SFillEssInfo; - -typedef struct SJoinCond { - bool tagExists; // denote if tag condition exists or not - SColumn *tagCond[2]; - SColumn *colCond[2]; -} SJoinCond; - -static SArray* createQueryPlanImpl(const SQueryStmtInfo* pQueryInfo); -static void doDestroyQueryNode(SQueryPlanNode* pQueryNode); - -int32_t printExprInfo(char* buf, const SQueryPlanNode* pQueryNode, int32_t len); -int32_t optimizeQueryPlan(struct SQueryPlanNode* pQueryNode) { - return 0; -} - -static int32_t createModificationOpPlan(const SQueryNode* pNode, SQueryPlanNode** pQueryPlan) { - SVnodeModifOpStmtInfo* pModifStmtInfo = (SVnodeModifOpStmtInfo*)pNode; - - *pQueryPlan = calloc(1, sizeof(SQueryPlanNode)); - SArray* blocks = taosArrayInit(taosArrayGetSize(pModifStmtInfo->pDataBlocks), POINTER_BYTES); - - SDataPayloadInfo* pPayload = calloc(1, sizeof(SDataPayloadInfo)); - if (NULL == *pQueryPlan || NULL == blocks || NULL == pPayload) { - return TSDB_CODE_TSC_OUT_OF_MEMORY; - } - - (*pQueryPlan)->info.type = QNODE_MODIFY; - taosArrayAddAll(blocks, pModifStmtInfo->pDataBlocks); - - if (pNode->type == TSDB_SQL_INSERT) { - pPayload->msgType = TDMT_VND_SUBMIT; - } else if (pNode->type == TSDB_SQL_CREATE_TABLE) { - pPayload->msgType = TDMT_VND_CREATE_TABLE; - } - - pPayload->payload = blocks; - (*pQueryPlan)->pExtInfo = pPayload; - - return TSDB_CODE_SUCCESS; -} - -int32_t createSelectPlan(const SQueryStmtInfo* pSelect, SQueryPlanNode** pQueryPlan) { - SArray* pDownstream = createQueryPlanImpl(pSelect); - assert(taosArrayGetSize(pDownstream) == 1); - - *pQueryPlan = taosArrayGetP(pDownstream, 0); - taosArrayDestroy(pDownstream); - return TSDB_CODE_SUCCESS; -} - -int32_t createQueryPlan(const SQueryNode* pNode, SQueryPlanNode** pQueryPlan) { - switch (queryNodeType(pNode)) { - case TSDB_SQL_SELECT: { - return createSelectPlan((const SQueryStmtInfo*)pNode, pQueryPlan); - } - - case TSDB_SQL_INSERT: - case TSDB_SQL_CREATE_TABLE: - return createModificationOpPlan(pNode, pQueryPlan); - - default: - return TSDB_CODE_FAILED; - } -} - -int32_t queryPlanToSql(struct SQueryPlanNode* pQueryNode, char** sql) { - return 0; -} - -void destroyQueryPlan(SQueryPlanNode* pQueryNode) { - if (pQueryNode == NULL) { - return; - } - - doDestroyQueryNode(pQueryNode); -} - -//====================================================================================================================== - -static SQueryPlanNode* createQueryNode(int32_t type, const char* name, SQueryPlanNode** pChildrenNode, int32_t numOfChildren, - SExprInfo** pExpr, int32_t numOfOutput, const void* pExtInfo) { - SQueryPlanNode* pNode = calloc(1, sizeof(SQueryPlanNode)); - - pNode->info.type = type; - pNode->info.name = strdup(name); - pNode->numOfExpr = numOfOutput; - - pNode->pExpr = taosArrayInit(numOfOutput, POINTER_BYTES); - taosArrayAddBatch(pNode->pExpr, pExpr, numOfOutput); - assert(pNode->numOfExpr == numOfOutput); - - pNode->pChildren = taosArrayInit(4, POINTER_BYTES); - for(int32_t i = 0; i < numOfChildren; ++i) { - taosArrayPush(pNode->pChildren, &pChildrenNode[i]); - } - - switch(type) { - case QNODE_TAGSCAN: - case QNODE_STREAMSCAN: - case QNODE_TABLESCAN: { - SQueryTableInfo* info = calloc(1, sizeof(SQueryTableInfo)); - memcpy(info, pExtInfo, sizeof(SQueryTableInfo)); - info->tableName = strdup(((SQueryTableInfo*) pExtInfo)->tableName); - pNode->pExtInfo = info; - break; - } - - case QNODE_TIMEWINDOW: { - SInterval* pInterval = calloc(1, sizeof(SInterval)); - pNode->pExtInfo = pInterval; - memcpy(pInterval, pExtInfo, sizeof(SInterval)); - break; - } - - case QNODE_STATEWINDOW: { - SColumn* psw = calloc(1, sizeof(SColumn)); - pNode->pExtInfo = psw; - memcpy(psw, pExtInfo, sizeof(SColumn)); - break; - } - - case QNODE_SESSIONWINDOW: { - SSessionWindow *pSessionWindow = calloc(1, sizeof(SSessionWindow)); - pNode->pExtInfo = pSessionWindow; - memcpy(pSessionWindow, pExtInfo, sizeof(struct SSessionWindow)); - break; - } - - case QNODE_GROUPBY: { - SGroupbyExpr* p = (SGroupbyExpr*) pExtInfo; - - SGroupbyExpr* pGroupbyExpr = calloc(1, sizeof(SGroupbyExpr)); - pGroupbyExpr->groupbyTag = p->groupbyTag; - pGroupbyExpr->columnInfo = taosArrayDup(p->columnInfo); - - pNode->pExtInfo = pGroupbyExpr; - break; - } - - case QNODE_FILL: { // todo !! - pNode->pExtInfo = (void*)pExtInfo; - break; - } - - case QNODE_LIMIT: { - pNode->pExtInfo = calloc(1, sizeof(SLimit)); - memcpy(pNode->pExtInfo, pExtInfo, sizeof(SLimit)); - break; - } - - case QNODE_SORT: { - pNode->pExtInfo = taosArrayDup(pExtInfo); - break; - } - - default: - break; - } - - return pNode; -} - -static SQueryPlanNode* doAddTableColumnNode(const SQueryStmtInfo* pQueryInfo, SQueryTableInfo* info, SArray* pExprs, SArray* tableCols) { - if (pQueryInfo->info.onlyTagQuery) { - int32_t num = (int32_t) taosArrayGetSize(pExprs); - SQueryPlanNode* pNode = createQueryNode(QNODE_TAGSCAN, "TableTagScan", NULL, 0, pExprs->pData, num, info); - - if (pQueryInfo->info.distinct) { - pNode = createQueryNode(QNODE_DISTINCT, "Distinct", &pNode, 1, pExprs->pData, num, NULL); - } - return pNode; - } - - SQueryPlanNode* pNode = NULL; - if (pQueryInfo->info.continueQuery) { - pNode = createQueryNode(QNODE_STREAMSCAN, "StreamScan", NULL, 0, NULL, 0, info); - } else { - pNode = createQueryNode(QNODE_TABLESCAN, "TableScan", NULL, 0, NULL, 0, info); - } - - if (!pQueryInfo->info.projectionQuery) { - SArray* p = pQueryInfo->exprList[0]; - - // table source column projection, generate the projection expr - int32_t numOfCols = (int32_t) taosArrayGetSize(tableCols); - - pNode->numOfExpr = numOfCols; - pNode->pExpr = taosArrayInit(numOfCols, POINTER_BYTES); - for(int32_t i = 0; i < numOfCols; ++i) { - SExprInfo* pExprInfo = taosArrayGetP(p, i); - SColumn* pCol = pExprInfo->base.pColumns; - - SSchema schema = createSchema(pCol->info.type, pCol->info.bytes, pCol->info.colId, pCol->name); - - tExprNode* pExprNode = pExprInfo->pExpr->_function.pChild[0]; - SExprInfo* px = createBinaryExprInfo(pExprNode, &schema); - taosArrayPush(pNode->pExpr, &px); - } - } - - return pNode; -} - -static SQueryPlanNode* doCreateQueryPlanForSingleTableImpl(const 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 = getExprFunctionLevel(pQueryInfo); - - for(int32_t i = level - 1; i >= 0; --i) { - SArray* p = pQueryInfo->exprList[i]; - size_t num = taosArrayGetSize(p); - - bool aggregateFunc = false; - for(int32_t j = 0; j < num; ++j) { - SExprInfo* pExpr = (SExprInfo*)taosArrayGetP(p, 0); - if (pExpr->pExpr->nodeType != TEXPR_FUNCTION_NODE) { - continue; - } - - aggregateFunc = qIsAggregateFunction(pExpr->pExpr->_function.functionName); - if (aggregateFunc) { - break; - } - } - - if (aggregateFunc) { - if (pQueryInfo->interval.interval > 0) { - pNode = createQueryNode(QNODE_TIMEWINDOW, "TimeWindowAgg", &pNode, 1, p->pData, num, &pQueryInfo->interval); - } else if (pQueryInfo->sessionWindow.gap > 0) { - pNode = createQueryNode(QNODE_SESSIONWINDOW, "SessionWindowAgg", &pNode, 1, p->pData, num, &pQueryInfo->sessionWindow); - } else if (pQueryInfo->stateWindow.col.info.colId > 0) { - pNode = createQueryNode(QNODE_STATEWINDOW, "StateWindowAgg", &pNode, 1, p->pData, num, &pQueryInfo->stateWindow); - } else if (numOfGroupCols != 0 && !pQueryInfo->groupbyExpr.groupbyTag) { - pNode = createQueryNode(QNODE_GROUPBY, "Groupby", &pNode, 1, p->pData, num, &pQueryInfo->groupbyExpr); - } else { - pNode = createQueryNode(QNODE_AGGREGATE, "Aggregate", &pNode, 1, p->pData, num, NULL); - } - } else { - // here we can push down the projection to tablescan operator. - pNode->numOfExpr = num; - taosArrayAddAll(pNode->pExpr, p); - } - } - - if (pQueryInfo->havingFieldNum > 0) { -// int32_t numOfExpr = (int32_t)taosArrayGetSize(pQueryInfo->exprList1); -// pNode = createQueryNode(QNODE_PROJECT, "Projection", &pNode, 1, pQueryInfo->exprList1->pData, numOfExpr, NULL); - } - - if (pQueryInfo->fillType != TSDB_FILL_NONE) { - SFillEssInfo* pInfo = calloc(1, sizeof(SFillEssInfo)); - pInfo->fillType = pQueryInfo->fillType; - pInfo->val = calloc(pNode->numOfExpr, sizeof(int64_t)); - memcpy(pInfo->val, pQueryInfo->fillVal, pNode->numOfExpr); - - SArray* p = pQueryInfo->exprList[0]; // top expression in select clause - pNode = createQueryNode(QNODE_FILL, "Fill", &pNode, 1, p->pData, taosArrayGetSize(p), pInfo); - } - - if (pQueryInfo->order != NULL) { - SArray* pList = pQueryInfo->exprList[0]; - pNode = createQueryNode(QNODE_SORT, "Sort", &pNode, 1, pList->pData, taosArrayGetSize(pList), pQueryInfo->order); - } - - if (pQueryInfo->limit.limit != -1 || pQueryInfo->limit.offset != 0) { - pNode = createQueryNode(QNODE_LIMIT, "Limit", &pNode, 1, NULL, 0, &pQueryInfo->limit); - } - - return pNode; -} - -static SQueryPlanNode* doCreateQueryPlanForSingleTable(const SQueryStmtInfo* pQueryInfo, STableMetaInfo* pTableMetaInfo, SArray* pExprs, - SArray* tableCols) { - char name[TSDB_TABLE_FNAME_LEN] = {0}; - tstrncpy(name, pTableMetaInfo->name.tname, TSDB_TABLE_FNAME_LEN); - - SQueryTableInfo info = {.tableName = strdup(name), .uid = pTableMetaInfo->pTableMeta->uid,}; - info.window = pQueryInfo->window; - info.pMeta = pTableMetaInfo; - - // handle the only tag query - SQueryPlanNode* pNode = doAddTableColumnNode(pQueryInfo, &info, pExprs, tableCols); - if (pQueryInfo->info.onlyTagQuery) { - tfree(info.tableName); - return pNode; - } - - SQueryPlanNode* pNode1 = doCreateQueryPlanForSingleTableImpl(pQueryInfo, pNode, &info); - tfree(info.tableName); - return pNode1; -} - -static bool isAllAggExpr(SArray* pList) { - assert(pList != NULL); - - for (int32_t k = 0; k < taosArrayGetSize(pList); ++k) { - SExprInfo* p = taosArrayGetP(pList, k); - if (p->pExpr->nodeType != TEXPR_FUNCTION_NODE || !qIsAggregateFunction(p->pExpr->_function.functionName)) { - return false; - } - } - - return true; -} - -SArray* createQueryPlanImpl(const SQueryStmtInfo* pQueryInfo) { - SArray* pDownstream = NULL; - - if (pQueryInfo->pDownstream != NULL && taosArrayGetSize(pQueryInfo->pDownstream) > 0) { // subquery in the from clause - pDownstream = taosArrayInit(4, POINTER_BYTES); - - size_t size = taosArrayGetSize(pQueryInfo->pDownstream); - for(int32_t i = 0; i < size; ++i) { - SQueryStmtInfo* pq = taosArrayGet(pQueryInfo->pDownstream, i); - SArray* p = createQueryPlanImpl(pq); - taosArrayAddBatch(pDownstream, p->pData, (int32_t) taosArrayGetSize(p)); - } - } - - if (pQueryInfo->numOfTables > 1) { // it is a join query - // 1. separate the select clause according to table - taosArrayDestroy(pDownstream); - pDownstream = taosArrayInit(5, POINTER_BYTES); - - for(int32_t i = 0; i < pQueryInfo->numOfTables; ++i) { - STableMetaInfo* pTableMetaInfo = pQueryInfo->pTableMetaInfo[i]; - uint64_t uid = pTableMetaInfo->pTableMeta->uid; - - SArray* exprList = taosArrayInit(4, POINTER_BYTES); - if (copyExprInfoList(exprList, pQueryInfo->exprList[0], uid, true) != 0) { - terrno = TSDB_CODE_TSC_OUT_OF_MEMORY; - exit(-1); - } - - // 2. create the query execution node - char name[TSDB_TABLE_FNAME_LEN] = {0}; - tNameExtractFullName(&pTableMetaInfo->name, name); - SQueryTableInfo info = {.tableName = strdup(name), .uid = pTableMetaInfo->pTableMeta->uid,}; - - // 3. get the required table column list - SArray* tableColumnList = taosArrayInit(4, sizeof(SColumn)); - columnListCopy(tableColumnList, pQueryInfo->colList, uid); - - // 4. add the projection query node - SQueryPlanNode* pNode = doAddTableColumnNode(pQueryInfo, &info, exprList, tableColumnList); - columnListDestroy(tableColumnList); - taosArrayPush(pDownstream, &pNode); - } - - // 3. add the join node here - SQueryTableInfo info = {0}; - int32_t num = (int32_t) taosArrayGetSize(pQueryInfo->exprList[0]); - SQueryPlanNode* pNode = createQueryNode(QNODE_JOIN, "Join", pDownstream->pData, pQueryInfo->numOfTables, - pQueryInfo->exprList[0]->pData, num, NULL); - - // 4. add the aggregation or projection execution node - pNode = doCreateQueryPlanForSingleTableImpl(pQueryInfo, pNode, &info); - pDownstream = taosArrayInit(5, POINTER_BYTES); - taosArrayPush(pDownstream, &pNode); - } else { // only one table, normal query process - STableMetaInfo* pTableMetaInfo = pQueryInfo->pTableMetaInfo[0]; - SQueryPlanNode* pNode = doCreateQueryPlanForSingleTable(pQueryInfo, pTableMetaInfo, pQueryInfo->exprList[0], pQueryInfo->colList); - pDownstream = taosArrayInit(5, POINTER_BYTES); - taosArrayPush(pDownstream, &pNode); - } - - return pDownstream; -} - -static void doDestroyQueryNode(SQueryPlanNode* pQueryNode) { - int32_t type = queryNodeType(pQueryNode); - if (type == QNODE_MODIFY) { - SDataPayloadInfo* pInfo = pQueryNode->pExtInfo; - - size_t size = taosArrayGetSize(pInfo->payload); - for (int32_t i = 0; i < size; ++i) { - SVgDataBlocks* pBlock = taosArrayGetP(pInfo->payload, i); - tfree(pBlock); - } - - taosArrayDestroy(pInfo->payload); - } - - if (type == QNODE_STREAMSCAN || type == QNODE_TABLESCAN) { - SQueryTableInfo* pQueryTableInfo = pQueryNode->pExtInfo; - tfree(pQueryTableInfo->tableName); - } - - taosArrayDestroy(pQueryNode->pExpr); - - tfree(pQueryNode->pExtInfo); - tfree(pQueryNode->pSchema); - tfree(pQueryNode->info.name); - - if (pQueryNode->pChildren != NULL) { - int32_t size = (int32_t) taosArrayGetSize(pQueryNode->pChildren); - for(int32_t i = 0; i < size; ++i) { - SQueryPlanNode* p = taosArrayGetP(pQueryNode->pChildren, i); - doDestroyQueryNode(p); - } - - taosArrayDestroy(pQueryNode->pChildren); - } - - tfree(pQueryNode); -} - -static int32_t doPrintPlan(char* buf, SQueryPlanNode* pQueryNode, int32_t level, int32_t totalLen) { - if (level > 0) { - sprintf(buf + totalLen, "%*c", level, ' '); - totalLen += level; - } - - int32_t len1 = sprintf(buf + totalLen, "%s(", pQueryNode->info.name); - int32_t len = len1 + totalLen; - - switch(pQueryNode->info.type) { - case QNODE_STREAMSCAN: - case QNODE_TABLESCAN: { - SQueryTableInfo* pInfo = (SQueryTableInfo*)pQueryNode->pExtInfo; - len1 = sprintf(buf + len, "%s #%" PRIu64, pInfo->tableName, pInfo->uid); - assert(len1 > 0); - len += len1; - - len1 = sprintf(buf + len, " , cols:"); - assert(len1 > 0); - len += len1; - - len = printExprInfo(buf, pQueryNode, len); - len1 = sprintf(buf + len, ")"); - assert(len1 > 0); - - // todo print filter info - len1 = sprintf(buf + len, ") filters:(nil)"); - len += len1; - - len1 = sprintf(buf + len, " time_range: %" PRId64 " - %" PRId64"\n", pInfo->window.skey, pInfo->window.ekey); - len += len1; - break; - } - - case QNODE_PROJECT: { - len1 = sprintf(buf + len, "cols:"); - assert(len1 > 0); - len += len1; - - len = printExprInfo(buf, pQueryNode, len); - len1 = sprintf(buf + len, ")"); - len += len1; - - // todo print filter info - len1 = sprintf(buf + len, " filters:(nil)\n"); - len += len1; - break; - } - - case QNODE_AGGREGATE: { - len = printExprInfo(buf, pQueryNode, len); - len1 = sprintf(buf + len, ")\n"); - len += len1; - - break; - } - - case QNODE_TIMEWINDOW: { - len = printExprInfo(buf, pQueryNode, len); - len1 = sprintf(buf + len, ") "); - len += len1; - - SInterval* pInterval = pQueryNode->pExtInfo; - - // todo dynamic return the time precision - len1 = sprintf(buf + len, "interval:%" PRId64 "(%s), sliding:%" PRId64 "(%s), offset:%" PRId64 "(%s)\n", - pInterval->interval, TSDB_TIME_PRECISION_MILLI_STR, pInterval->sliding, - TSDB_TIME_PRECISION_MILLI_STR, pInterval->offset, TSDB_TIME_PRECISION_MILLI_STR); - len += len1; - - break; - } - - case QNODE_STATEWINDOW: { - len = printExprInfo(buf, pQueryNode, len); - len1 = sprintf(buf + len, ") "); - len += len1; - - SColumn* pCol = pQueryNode->pExtInfo; - len1 = sprintf(buf + len, "col:%s #%d\n", pCol->name, pCol->info.colId); - len += len1; - break; - } - - case QNODE_SESSIONWINDOW: { - len = printExprInfo(buf, pQueryNode, len); - - len1 = sprintf(buf + len, ") "); - len += len1; - - struct SSessionWindow* ps = pQueryNode->pExtInfo; - len1 = sprintf(buf + len, "col:[%s #%d], gap:%" PRId64 " (ms) \n", ps->col.name, ps->col.info.colId, ps->gap); - len += len1; - break; - } - - case QNODE_GROUPBY: { - len = printExprInfo(buf, pQueryNode, len); - - SGroupbyExpr* pGroupbyExpr = pQueryNode->pExtInfo; - len1 = sprintf(buf + len, ") groupby_col: "); - len += len1; - - for (int32_t i = 0; i < taosArrayGetSize(pGroupbyExpr->columnInfo); ++i) { - SColumn* pCol = taosArrayGet(pGroupbyExpr->columnInfo, i); - len1 = sprintf(buf + len, "[%s #%d] ", pCol->name, pCol->info.colId); - len += len1; - } - - len += sprintf(buf + len, "\n"); - break; - } - - case QNODE_FILL: { - SFillEssInfo* pEssInfo = pQueryNode->pExtInfo; - len1 = sprintf(buf + len, "%d", pEssInfo->fillType); - len += len1; - - if (pEssInfo->fillType == TSDB_FILL_SET_VALUE) { - len1 = sprintf(buf + len, ", val:"); - len += len1; - - // todo get the correct fill data type - for (int32_t i = 0; i < pQueryNode->numOfExpr; ++i) { - len1 = sprintf(buf + len, "%" PRId64, pEssInfo->val[i]); - len += len1; - - if (i < pQueryNode->numOfExpr - 1) { - len1 = sprintf(buf + len, ", "); - len += len1; - } +#include "functionMgt.h" + +typedef struct SLogicPlanContext { + int32_t errCode; + int32_t planNodeId; +} SLogicPlanContext; + +static SLogicNode* createQueryLogicNode(SLogicPlanContext* pCxt, SNode* pStmt); +static SLogicNode* createLogicNodeByTable(SLogicPlanContext* pCxt, SSelectStmt* pSelect, SNode* pTable); + +typedef struct SRewriteExprCxt { + int32_t errCode; + SNodeList* pExprs; +} SRewriteExprCxt; + +static EDealRes doRewriteExpr(SNode** pNode, void* pContext) { + switch (nodeType(*pNode)) { + case QUERY_NODE_OPERATOR: + case QUERY_NODE_LOGIC_CONDITION: + case QUERY_NODE_FUNCTION: { + SRewriteExprCxt* pCxt = (SRewriteExprCxt*)pContext; + SNode* pExpr; + int32_t index = 0; + FOREACH(pExpr, pCxt->pExprs) { + if (QUERY_NODE_GROUPING_SET == nodeType(pExpr)) { + pExpr = nodesListGetNode(((SGroupingSetNode*)pExpr)->pParameterList, 0); } + if (nodesEqualNode(pExpr, *pNode)) { + SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN); + CHECK_ALLOC(pCol, DEAL_RES_ERROR); + SExprNode* pToBeRewrittenExpr = (SExprNode*)(*pNode); + pCol->node.resType = pToBeRewrittenExpr->resType; + strcpy(pCol->node.aliasName, pToBeRewrittenExpr->aliasName); + strcpy(pCol->colName, ((SExprNode*)pExpr)->aliasName); + nodesDestroyNode(*pNode); + *pNode = (SNode*)pCol; + return DEAL_RES_IGNORE_CHILD; + } + ++index; } - - len1 = sprintf(buf + len, ")\n"); - len += len1; break; } - - case QNODE_LIMIT: { - SLimit* pVal = pQueryNode->pExtInfo; - len1 = sprintf(buf + len, "limit: %" PRId64 ", offset: %" PRId64 ")\n", pVal->limit, pVal->offset); - len += len1; + default: break; - } - - case QNODE_DISTINCT: - case QNODE_TAGSCAN: { - len1 = sprintf(buf + len, "cols: "); - len += len1; - - len = printExprInfo(buf, pQueryNode, len); - - len1 = sprintf(buf + len, ")\n"); - len += len1; - - break; - } - - case QNODE_SORT: { - len1 = sprintf(buf + len, "cols:"); - len += len1; - - SArray* pSort = pQueryNode->pExtInfo; - for (int32_t i = 0; i < taosArrayGetSize(pSort); ++i) { - SOrder* p = taosArrayGet(pSort, i); - len1 = sprintf(buf + len, " [%s #%d %s]", p->col.name, p->col.info.colId, p->order == TSDB_ORDER_ASC? "ASC":"DESC"); - - len += len1; - } - - len1 = sprintf(buf + len, ")\n"); - len += len1; - break; - } - - case QNODE_JOIN: { - // print join condition - len1 = sprintf(buf + len, ")\n"); - len += len1; - break; - } } - return len; + return DEAL_RES_CONTINUE; } -int32_t printExprInfo(char* buf, const SQueryPlanNode* pQueryNode, int32_t len) { - int32_t len1 = 0; +typedef struct SNameExprCxt { + int32_t planNodeId; + int32_t rewriteId; +} SNameExprCxt; - for (int32_t i = 0; i < pQueryNode->numOfExpr; ++i) { - SExprInfo* pExprInfo = taosArrayGetP(pQueryNode->pExpr, i); +static EDealRes doNameExpr(SNode* pNode, void* pContext) { + switch (nodeType(pNode)) { + case QUERY_NODE_OPERATOR: + case QUERY_NODE_LOGIC_CONDITION: + case QUERY_NODE_FUNCTION: { + SNameExprCxt* pCxt = (SNameExprCxt*)pContext; + sprintf(((SExprNode*)pNode)->aliasName, "#expr_%d_%d", pCxt->planNodeId, pCxt->rewriteId++); + return DEAL_RES_IGNORE_CHILD; + } + default: + break; + } - SSqlExpr* pExpr = &pExprInfo->base; - len1 = sprintf(buf + len, "%s [%s #%d]", pExpr->token, pExpr->resSchema.name, pExpr->resSchema.colId); - assert(len1 > 0); + return DEAL_RES_CONTINUE; +} - len += len1; - if (i < pQueryNode->numOfExpr - 1) { - len1 = sprintf(buf + len, ", "); - len += len1; +static int32_t rewriteExpr(int32_t planNodeId, int32_t rewriteId, SNodeList* pExprs, SSelectStmt* pSelect, ESqlClause clause) { + SNameExprCxt nameCxt = { .planNodeId = planNodeId, .rewriteId = rewriteId }; + nodesWalkList(pExprs, doNameExpr, &nameCxt); + SRewriteExprCxt cxt = { .errCode = TSDB_CODE_SUCCESS, .pExprs = pExprs }; + nodesRewriteSelectStmt(pSelect, clause, doRewriteExpr, &cxt); + return cxt.errCode; +} + +static SLogicNode* pushLogicNode(SLogicPlanContext* pCxt, SLogicNode* pRoot, SLogicNode* pNode) { + if (TSDB_CODE_SUCCESS != pCxt->errCode) { + goto error; + } + + if (NULL == pRoot) { + return pNode; + } + + if (NULL == pNode) { + return pRoot; + } + + if (NULL == pNode->pChildren) { + pNode->pChildren = nodesMakeList(); + if (NULL == pNode->pChildren) { + goto error; } } - - return len; + if (TSDB_CODE_SUCCESS != nodesListAppend(pNode->pChildren, (SNode*)pRoot)) { + goto error; + } + pRoot->pParent = pNode; + return pNode; +error: + nodesDestroyNode((SNode*)pNode); + return pRoot; } -int32_t queryPlanToStringImpl(char* buf, SQueryPlanNode* pQueryNode, int32_t level, int32_t totalLen) { - int32_t len = doPrintPlan(buf, pQueryNode, level, totalLen); +static SLogicNode* createScanLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect, SRealTableNode* pRealTable) { + SScanLogicNode* pScan = (SScanLogicNode*)nodesMakeNode(QUERY_NODE_LOGIC_PLAN_SCAN); + CHECK_ALLOC(pScan, NULL); + pScan->node.id = pCxt->planNodeId++; - for(int32_t i = 0; i < taosArrayGetSize(pQueryNode->pChildren); ++i) { - SQueryPlanNode* p1 = taosArrayGetP(pQueryNode->pChildren, i); - int32_t len1 = queryPlanToStringImpl(buf, p1, level + 1, len); - len = len1; + pScan->pMeta = pRealTable->pMeta; + + // set columns to scan + SNodeList* pCols = NULL; + CHECK_CODE(nodesCollectColumns(pSelect, SQL_CLAUSE_FROM, pRealTable->table.tableAlias, &pCols), (SLogicNode*)pScan); + if (NULL != pCols) { + pScan->pScanCols = nodesCloneList(pCols); + CHECK_ALLOC(pScan->pScanCols, (SLogicNode*)pScan); } - return len; + // set output + if (NULL != pCols) { + pScan->node.pTargets = nodesCloneList(pCols); + CHECK_ALLOC(pScan->node.pTargets, (SLogicNode*)pScan); + } + + pScan->scanType = SCAN_TYPE_TABLE; + pScan->scanFlag = MAIN_SCAN; + pScan->scanRange = TSWINDOW_INITIALIZER; + + return (SLogicNode*)pScan; } -int32_t queryPlanToString(struct SQueryPlanNode* pQueryNode, char** str) { - assert(pQueryNode); - *str = calloc(1, 4096); - - int32_t len = sprintf(*str, "===== logic plan =====\n"); - queryPlanToStringImpl(*str, pQueryNode, 0, len); - - return TSDB_CODE_SUCCESS; +static SLogicNode* createSubqueryLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect, STempTableNode* pTable) { + SLogicNode* pRoot = createQueryLogicNode(pCxt, pTable->pSubquery); + CHECK_ALLOC(pRoot, NULL); + SNode* pNode; + FOREACH(pNode, pRoot->pTargets) { + strcpy(((SColumnNode*)pNode)->tableAlias, pTable->table.tableAlias); + } + return pRoot; } -SQueryPlanNode* queryPlanFromString() { +static SLogicNode* createJoinLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect, SJoinTableNode* pJoinTable) { + SJoinLogicNode* pJoin = (SJoinLogicNode*)nodesMakeNode(QUERY_NODE_LOGIC_PLAN_JOIN); + CHECK_ALLOC(pJoin, NULL); + pJoin->node.id = pCxt->planNodeId++; + + pJoin->joinType = pJoinTable->joinType; + + // set left and right node + pJoin->node.pChildren = nodesMakeList(); + CHECK_ALLOC(pJoin->node.pChildren, (SLogicNode*)pJoin); + SLogicNode* pLeft = createLogicNodeByTable(pCxt, pSelect, pJoinTable->pLeft); + CHECK_ALLOC(pLeft, (SLogicNode*)pJoin); + CHECK_CODE(nodesListAppend(pJoin->node.pChildren, (SNode*)pLeft), (SLogicNode*)pJoin); + SLogicNode* pRight = createLogicNodeByTable(pCxt, pSelect, pJoinTable->pRight); + CHECK_ALLOC(pRight, (SLogicNode*)pJoin); + CHECK_CODE(nodesListAppend(pJoin->node.pChildren, (SNode*)pRight), (SLogicNode*)pJoin); + + // set on conditions + if (NULL != pJoinTable->pOnCond) { + pJoin->pOnConditions = nodesCloneNode(pJoinTable->pOnCond); + CHECK_ALLOC(pJoin->pOnConditions, (SLogicNode*)pJoin); + } + + // set the output + pJoin->node.pTargets = nodesCloneList(pLeft->pTargets); + CHECK_ALLOC(pJoin->node.pTargets, (SLogicNode*)pJoin); + SNodeList* pTargets = nodesCloneList(pRight->pTargets); + CHECK_ALLOC(pTargets, (SLogicNode*)pJoin); + nodesListAppendList(pJoin->node.pTargets, pTargets); + + return (SLogicNode*)pJoin; +} + +static SLogicNode* createLogicNodeByTable(SLogicPlanContext* pCxt, SSelectStmt* pSelect, SNode* pTable) { + switch (nodeType(pTable)) { + case QUERY_NODE_REAL_TABLE: + return createScanLogicNode(pCxt, pSelect, (SRealTableNode*)pTable); + case QUERY_NODE_TEMP_TABLE: + return createSubqueryLogicNode(pCxt, pSelect, (STempTableNode*)pTable); + case QUERY_NODE_JOIN_TABLE: + return createJoinLogicNode(pCxt, pSelect, (SJoinTableNode*)pTable); + default: + break; + } return NULL; } -#endif +typedef struct SCreateColumnCxt { + int32_t errCode; + SNodeList* pList; +} SCreateColumnCxt; + +static EDealRes doCreateColumn(SNode* pNode, void* pContext) { + SCreateColumnCxt* pCxt = (SCreateColumnCxt*)pContext; + switch (nodeType(pNode)) { + case QUERY_NODE_COLUMN: { + SNode* pCol = nodesCloneNode(pNode); + CHECK_ALLOC(pCol, DEAL_RES_ERROR); + CHECK_CODE(nodesListAppend(pCxt->pList, pCol), DEAL_RES_ERROR); + return DEAL_RES_IGNORE_CHILD; + } + case QUERY_NODE_OPERATOR: + case QUERY_NODE_LOGIC_CONDITION: + case QUERY_NODE_FUNCTION: { + SExprNode* pExpr = (SExprNode*)pNode; + SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN); + CHECK_ALLOC(pCol, DEAL_RES_ERROR); + pCol->node.resType = pExpr->resType; + strcpy(pCol->colName, pExpr->aliasName); + CHECK_CODE(nodesListAppend(pCxt->pList, (SNode*)pCol), DEAL_RES_ERROR); + return DEAL_RES_IGNORE_CHILD; + } + default: + break; + } + + return DEAL_RES_CONTINUE; +} + +static SNodeList* createColumnByRewriteExps(SLogicPlanContext* pCxt, SNodeList* pExprs) { + SCreateColumnCxt cxt = { .errCode = TSDB_CODE_SUCCESS, .pList = nodesMakeList() }; + CHECK_ALLOC(cxt.pList, NULL); + + nodesWalkList(pExprs, doCreateColumn, &cxt); + if (TSDB_CODE_SUCCESS != cxt.errCode) { + nodesDestroyList(cxt.pList); + return NULL; + } + return cxt.pList; +} + +static SLogicNode* createAggLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect) { + SNodeList* pAggFuncs = NULL; + CHECK_CODE(nodesCollectFuncs(pSelect, fmIsAggFunc, &pAggFuncs), NULL); + if (NULL == pAggFuncs && NULL == pSelect->pGroupByList) { + return NULL; + } + + SAggLogicNode* pAgg = (SAggLogicNode*)nodesMakeNode(QUERY_NODE_LOGIC_PLAN_AGG); + CHECK_ALLOC(pAgg, NULL); + pAgg->node.id = pCxt->planNodeId++; + + // set grouyp keys, agg funcs and having conditions + if (NULL != pSelect->pGroupByList) { + pAgg->pGroupKeys = nodesCloneList(pSelect->pGroupByList); + CHECK_ALLOC(pAgg->pGroupKeys, (SLogicNode*)pAgg); + } + if (NULL != pAggFuncs) { + pAgg->pAggFuncs = nodesCloneList(pAggFuncs); + CHECK_ALLOC(pAgg->pAggFuncs, (SLogicNode*)pAgg); + } + + // rewrite the expression in subsequent clauses + CHECK_CODE(rewriteExpr(pAgg->node.id, 1, pAgg->pGroupKeys, pSelect, SQL_CLAUSE_GROUP_BY), (SLogicNode*)pAgg); + CHECK_CODE(rewriteExpr(pAgg->node.id, 1 + LIST_LENGTH(pAgg->pGroupKeys), pAgg->pAggFuncs, pSelect, SQL_CLAUSE_GROUP_BY), (SLogicNode*)pAgg); + + if (NULL != pSelect->pHaving) { + pAgg->node.pConditions = nodesCloneNode(pSelect->pHaving); + CHECK_ALLOC(pAgg->node.pConditions, (SLogicNode*)pAgg); + } + + // set the output + pAgg->node.pTargets = nodesMakeList(); + CHECK_ALLOC(pAgg->node.pTargets, (SLogicNode*)pAgg); + if (NULL != pAgg->pGroupKeys) { + SNodeList* pTargets = createColumnByRewriteExps(pCxt, pAgg->pGroupKeys); + CHECK_ALLOC(pAgg->node.pTargets, (SLogicNode*)pAgg); + nodesListAppendList(pAgg->node.pTargets, pTargets); + } + if (NULL != pAgg->pAggFuncs) { + SNodeList* pTargets = createColumnByRewriteExps(pCxt, pAgg->pAggFuncs); + CHECK_ALLOC(pTargets, (SLogicNode*)pAgg); + nodesListAppendList(pAgg->node.pTargets, pTargets); + } + + return (SLogicNode*)pAgg; +} + +static SNodeList* createColumnByProjections(SLogicPlanContext* pCxt, SNodeList* pExprs) { + SNodeList* pList = nodesMakeList(); + CHECK_ALLOC(pList, NULL); + SNode* pNode; + FOREACH(pNode, pExprs) { + SExprNode* pExpr = (SExprNode*)pNode; + SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN); + if (NULL == pCol) { + goto error; + } + pCol->node.resType = pExpr->resType; + strcpy(pCol->colName, pExpr->aliasName); + if (TSDB_CODE_SUCCESS != nodesListAppend(pList, (SNode*)pCol)) { + goto error; + } + } + return pList; +error: + nodesDestroyList(pList); + return NULL; +} + +static SLogicNode* createProjectLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect) { + SProjectLogicNode* pProject = (SProjectLogicNode*)nodesMakeNode(QUERY_NODE_LOGIC_PLAN_PROJECT); + CHECK_ALLOC(pProject, NULL); + pProject->node.id = pCxt->planNodeId++; + + pProject->pProjections = nodesCloneList(pSelect->pProjectionList); + + pProject->node.pTargets = createColumnByProjections(pCxt,pSelect->pProjectionList); + CHECK_ALLOC(pProject->node.pTargets, (SLogicNode*)pProject); + + return (SLogicNode*)pProject; +} + +static SLogicNode* createSelectLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect) { + SLogicNode* pRoot = createLogicNodeByTable(pCxt, pSelect, pSelect->pFromTable); + if (TSDB_CODE_SUCCESS == pCxt->errCode && NULL != pSelect->pWhere) { + pRoot->pConditions = nodesCloneNode(pSelect->pWhere); + CHECK_ALLOC(pRoot->pConditions, pRoot); + } + if (TSDB_CODE_SUCCESS == pCxt->errCode) { + pRoot = pushLogicNode(pCxt, pRoot, createAggLogicNode(pCxt, pSelect)); + } + if (TSDB_CODE_SUCCESS == pCxt->errCode) { + pRoot = pushLogicNode(pCxt, pRoot, createProjectLogicNode(pCxt, pSelect)); + } + return pRoot; +} + +static SLogicNode* createQueryLogicNode(SLogicPlanContext* pCxt, SNode* pStmt) { + switch (nodeType(pStmt)) { + case QUERY_NODE_SELECT_STMT: + return createSelectLogicNode(pCxt, (SSelectStmt*)pStmt); + default: + break; + } +} + +int32_t createLogicPlan(SPlanContext* pCxt, SLogicNode** pLogicNode) { + SLogicPlanContext cxt = { .errCode = TSDB_CODE_SUCCESS, .planNodeId = 1 }; + SLogicNode* pRoot = createQueryLogicNode(&cxt, pCxt->pAstRoot); + if (TSDB_CODE_SUCCESS != cxt.errCode) { + nodesDestroyNode((SNode*)pRoot); + return cxt.errCode; + } + *pLogicNode = pRoot; + return TSDB_CODE_SUCCESS; +} diff --git a/source/libs/planner/src/physicalPlan.c b/source/libs/planner/src/physicalPlan.c index 9c927ca8e7..93848e2c3e 100644 --- a/source/libs/planner/src/physicalPlan.c +++ b/source/libs/planner/src/physicalPlan.c @@ -492,3 +492,483 @@ void qDestroySubplan(SSubplan* pSubplan) { } #endif + +#include "plannerInt.h" + +#include "functionMgt.h" + +typedef struct SSubLogicPlan { + SNode* pRoot; // SLogicNode + bool haveSuperTable; + bool haveSystemTable; +} SSubLogicPlan; + +int32_t splitLogicPlan(SSubLogicPlan* pLogicPlan) { + // todo + return TSDB_CODE_SUCCESS; +} + +typedef struct SSlotIndex { + int16_t dataBlockId; + int16_t slotId; +} SSlotIndex; + +typedef struct SPhysiPlanContext { + int32_t errCode; + int16_t nextDataBlockId; + SArray* pLocationHelper; +} SPhysiPlanContext; + +static int32_t getSlotKey(SNode* pNode, char* pKey) { + if (QUERY_NODE_COLUMN == nodeType(pNode)) { + SColumnNode* pCol = (SColumnNode*)pNode; + if ('\0' == pCol->tableAlias[0]) { + return sprintf(pKey, "%s", pCol->colName); + } + return sprintf(pKey, "%s.%s", pCol->tableAlias, pCol->colName); + } + return sprintf(pKey, "%s", ((SExprNode*)pNode)->aliasName); +} + +static SNode* createSlotDesc(SPhysiPlanContext* pCxt, const SNode* pNode, int16_t slotId) { + SSlotDescNode* pSlot = (SSlotDescNode*)nodesMakeNode(QUERY_NODE_SLOT_DESC); + CHECK_ALLOC(pSlot, NULL); + pSlot->slotId = slotId; + pSlot->dataType = ((SExprNode*)pNode)->resType; + pSlot->reserve = false; + pSlot->output = false; + return (SNode*)pSlot; +} + +static SNode* createTarget(SNode* pNode, int16_t dataBlockId, int16_t slotId) { + STargetNode* pTarget = (STargetNode*)nodesMakeNode(QUERY_NODE_TARGET); + if (NULL == pTarget) { + return NULL; + } + pTarget->dataBlockId = dataBlockId; + pTarget->slotId = slotId; + pTarget->pExpr = pNode; + return (SNode*)pTarget; +} + +static int32_t addDataBlockDesc(SPhysiPlanContext* pCxt, SNodeList* pList, SDataBlockDescNode* pDataBlockDesc) { + SHashObj* pHash = NULL; + if (NULL == pDataBlockDesc->pSlots) { + pDataBlockDesc->pSlots = nodesMakeList(); + CHECK_ALLOC(pDataBlockDesc->pSlots, TSDB_CODE_OUT_OF_MEMORY); + + pHash = taosHashInit(LIST_LENGTH(pList), taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK); + CHECK_ALLOC(pHash, TSDB_CODE_OUT_OF_MEMORY); + if (NULL == taosArrayInsert(pCxt->pLocationHelper, pDataBlockDesc->dataBlockId, &pHash)) { + taosHashCleanup(pHash); + return TSDB_CODE_OUT_OF_MEMORY; + } + } else { + pHash = taosArrayGetP(pCxt->pLocationHelper, pDataBlockDesc->dataBlockId); + } + + SNode* pNode = NULL; + int16_t slotId = taosHashGetSize(pHash); + FOREACH(pNode, pList) { + SNode* pSlot = createSlotDesc(pCxt, pNode, slotId); + CHECK_ALLOC(pSlot, TSDB_CODE_OUT_OF_MEMORY); + if (TSDB_CODE_SUCCESS != nodesListAppend(pDataBlockDesc->pSlots, (SNode*)pSlot)) { + nodesDestroyNode(pSlot); + return TSDB_CODE_OUT_OF_MEMORY; + } + + SSlotIndex index = { .dataBlockId = pDataBlockDesc->dataBlockId, .slotId = slotId }; + char name[TSDB_TABLE_NAME_LEN + TSDB_COL_NAME_LEN]; + int32_t len = getSlotKey(pNode, name); + CHECK_CODE(taosHashPut(pHash, name, len, &index, sizeof(SSlotIndex)), TSDB_CODE_OUT_OF_MEMORY); + + SNode* pTarget = createTarget(pNode, pDataBlockDesc->dataBlockId, slotId); + CHECK_ALLOC(pTarget, TSDB_CODE_OUT_OF_MEMORY); + REPLACE_NODE(pTarget); + + ++slotId; + } + return TSDB_CODE_SUCCESS; +} + +typedef struct SSetSlotIdCxt { + int32_t errCode; + SHashObj* pLeftHash; + SHashObj* pRightHash; +} SSetSlotIdCxt; + +static EDealRes doSetSlotId(SNode* pNode, void* pContext) { + if (QUERY_NODE_COLUMN == nodeType(pNode) && 0 != strcmp(((SColumnNode*)pNode)->colName, "*")) { + SSetSlotIdCxt* pCxt = (SSetSlotIdCxt*)pContext; + char name[TSDB_TABLE_NAME_LEN + TSDB_COL_NAME_LEN]; + int32_t len = getSlotKey(pNode, name); + SSlotIndex* pIndex = taosHashGet(pCxt->pLeftHash, name, len); + if (NULL == pIndex) { + pIndex = taosHashGet(pCxt->pRightHash, name, len); + } + // pIndex is definitely not NULL, otherwise it is a bug + ((SColumnNode*)pNode)->dataBlockId = pIndex->dataBlockId; + ((SColumnNode*)pNode)->slotId = pIndex->slotId; + CHECK_ALLOC(pNode, DEAL_RES_ERROR); + return DEAL_RES_IGNORE_CHILD; + } + return DEAL_RES_CONTINUE; +} + +static SNode* setNodeSlotId(SPhysiPlanContext* pCxt, int16_t leftDataBlockId, int16_t rightDataBlockId, SNode* pNode) { + SNode* pRes = nodesCloneNode(pNode); + CHECK_ALLOC(pRes, NULL); + SSetSlotIdCxt cxt = { .errCode = TSDB_CODE_SUCCESS, .pLeftHash = taosArrayGetP(pCxt->pLocationHelper, leftDataBlockId), + .pRightHash = (rightDataBlockId < 0 ? NULL : taosArrayGetP(pCxt->pLocationHelper, rightDataBlockId)) }; + nodesWalkNode(pRes, doSetSlotId, &cxt); + if (TSDB_CODE_SUCCESS != cxt.errCode) { + nodesDestroyNode(pRes); + return NULL; + } + return pRes; +} + +static SNodeList* setListSlotId(SPhysiPlanContext* pCxt, int16_t leftDataBlockId, int16_t rightDataBlockId, SNodeList* pList) { + SNodeList* pRes = nodesCloneList(pList); + CHECK_ALLOC(pRes, NULL); + SSetSlotIdCxt cxt = { .errCode = TSDB_CODE_SUCCESS, .pLeftHash = taosArrayGetP(pCxt->pLocationHelper, leftDataBlockId), + .pRightHash = (rightDataBlockId < 0 ? NULL : taosArrayGetP(pCxt->pLocationHelper, rightDataBlockId)) }; + nodesWalkList(pRes, doSetSlotId, &cxt); + if (TSDB_CODE_SUCCESS != cxt.errCode) { + nodesDestroyList(pRes); + return NULL; + } + return pRes; +} + +static SPhysiNode* makePhysiNode(SPhysiPlanContext* pCxt, ENodeType type) { + SPhysiNode* pPhysiNode = (SPhysiNode*)nodesMakeNode(type); + if (NULL == pPhysiNode) { + return NULL; + } + pPhysiNode->outputDataBlockDesc.dataBlockId = pCxt->nextDataBlockId++; + pPhysiNode->outputDataBlockDesc.type = QUERY_NODE_DATABLOCK_DESC; + return pPhysiNode; +} + +static int32_t setConditionsSlotId(SPhysiPlanContext* pCxt, const SLogicNode* pLogicNode, SPhysiNode* pPhysiNode) { + if (NULL != pLogicNode->pConditions) { + pPhysiNode->pConditions = setNodeSlotId(pCxt, pPhysiNode->outputDataBlockDesc.dataBlockId, -1, pLogicNode->pConditions); + CHECK_ALLOC(pPhysiNode->pConditions, TSDB_CODE_OUT_OF_MEMORY); + } + return TSDB_CODE_SUCCESS; +} + +static int32_t setSlotOutput(SPhysiPlanContext* pCxt, SNodeList* pTargets, SDataBlockDescNode* pDataBlockDesc) { + SHashObj* pHash = taosArrayGetP(pCxt->pLocationHelper, pDataBlockDesc->dataBlockId); + char name[TSDB_TABLE_NAME_LEN + TSDB_COL_NAME_LEN]; + SNode* pNode; + FOREACH(pNode, pTargets) { + int32_t len = getSlotKey(pNode, name); + SSlotIndex* pIndex = taosHashGet(pHash, name, len); + ((SSlotDescNode*)nodesListGetNode(pDataBlockDesc->pSlots, pIndex->slotId))->output = true; + } + + return TSDB_CODE_SUCCESS; +} + +static int32_t initScanPhysiNode(SPhysiPlanContext* pCxt, SScanLogicNode* pScanLogicNode, SScanPhysiNode* pScanPhysiNode) { + if (NULL != pScanLogicNode->pScanCols) { + pScanPhysiNode->pScanCols = nodesCloneList(pScanLogicNode->pScanCols); + CHECK_ALLOC(pScanPhysiNode->pScanCols, TSDB_CODE_OUT_OF_MEMORY); + } + // Data block describe also needs to be set without scanning column, such as SELECT COUNT(*) FROM t + CHECK_CODE(addDataBlockDesc(pCxt, pScanPhysiNode->pScanCols, &pScanPhysiNode->node.outputDataBlockDesc), TSDB_CODE_OUT_OF_MEMORY); + + CHECK_CODE(setConditionsSlotId(pCxt, (const SLogicNode*)pScanLogicNode, (SPhysiNode*)pScanPhysiNode), TSDB_CODE_OUT_OF_MEMORY); + + CHECK_CODE(setSlotOutput(pCxt, pScanLogicNode->node.pTargets, &pScanPhysiNode->node.outputDataBlockDesc), TSDB_CODE_OUT_OF_MEMORY); + + pScanPhysiNode->uid = pScanLogicNode->pMeta->uid; + pScanPhysiNode->tableType = pScanLogicNode->pMeta->tableType; + pScanPhysiNode->order = TSDB_ORDER_ASC; + pScanPhysiNode->count = 1; + pScanPhysiNode->reverse = 0; + + return TSDB_CODE_SUCCESS; +} + +static SPhysiNode* createTagScanPhysiNode(SPhysiPlanContext* pCxt, SScanLogicNode* pScanLogicNode) { + STagScanPhysiNode* pTagScan = (STagScanPhysiNode*)makePhysiNode(pCxt, QUERY_NODE_PHYSICAL_PLAN_TAG_SCAN); + CHECK_ALLOC(pTagScan, NULL); + CHECK_CODE(initScanPhysiNode(pCxt, pScanLogicNode, (SScanPhysiNode*)pTagScan), (SPhysiNode*)pTagScan); + return (SPhysiNode*)pTagScan; +} + +static SPhysiNode* createTableScanPhysiNode(SPhysiPlanContext* pCxt, SScanLogicNode* pScanLogicNode) { + STableScanPhysiNode* pTableScan = (STableScanPhysiNode*)makePhysiNode(pCxt, QUERY_NODE_PHYSICAL_PLAN_TABLE_SCAN); + CHECK_ALLOC(pTableScan, NULL); + CHECK_CODE(initScanPhysiNode(pCxt, pScanLogicNode, (SScanPhysiNode*)pTableScan), (SPhysiNode*)pTableScan); + pTableScan->scanFlag = pScanLogicNode->scanFlag; + pTableScan->scanRange = pScanLogicNode->scanRange; + return (SPhysiNode*)pTableScan; +} + +static SPhysiNode* createScanPhysiNode(SPhysiPlanContext* pCxt, SScanLogicNode* pScanLogicNode) { + switch (pScanLogicNode->scanType) { + case SCAN_TYPE_TAG: + return createTagScanPhysiNode(pCxt, pScanLogicNode); + case SCAN_TYPE_TABLE: + return createTableScanPhysiNode(pCxt, pScanLogicNode); + case SCAN_TYPE_STABLE: + case SCAN_TYPE_STREAM: + break; + default: + break; + } + return NULL; +} + +static SNodeList* createJoinOutputCols(SPhysiPlanContext* pCxt, SDataBlockDescNode* pLeftDesc, SDataBlockDescNode* pRightDesc) { + SNodeList* pCols = nodesMakeList(); + CHECK_ALLOC(pCols, NULL); + SNode* pNode; + FOREACH(pNode, pLeftDesc->pSlots) { + SSlotDescNode* pSlot = (SSlotDescNode*)pNode; + SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN); + if (NULL == pCol) { + goto error; + } + pCol->node.resType = pSlot->dataType; + pCol->dataBlockId = pLeftDesc->dataBlockId; + pCol->slotId = pSlot->slotId; + pCol->colId = -1; + if (TSDB_CODE_SUCCESS != nodesListAppend(pCols, (SNode*)pCol)) { + goto error; + } + } + FOREACH(pNode, pRightDesc->pSlots) { + SSlotDescNode* pSlot = (SSlotDescNode*)pNode; + SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN); + if (NULL == pCol) { + goto error; + } + pCol->node.resType = pSlot->dataType; + pCol->dataBlockId = pRightDesc->dataBlockId; + pCol->slotId = pSlot->slotId; + pCol->colId = -1; + if (TSDB_CODE_SUCCESS != nodesListAppend(pCols, (SNode*)pCol)) { + goto error; + } + } + return pCols; +error: + nodesDestroyList(pCols); + return NULL; +} + +static SPhysiNode* createJoinPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, SJoinLogicNode* pJoinLogicNode) { + SJoinPhysiNode* pJoin = (SJoinPhysiNode*)makePhysiNode(pCxt, QUERY_NODE_PHYSICAL_PLAN_JOIN); + CHECK_ALLOC(pJoin, NULL); + + SDataBlockDescNode* pLeftDesc = &((SPhysiNode*)nodesListGetNode(pChildren, 0))->outputDataBlockDesc; + SDataBlockDescNode* pRightDesc = &((SPhysiNode*)nodesListGetNode(pChildren, 1))->outputDataBlockDesc; + pJoin->pOnConditions = setNodeSlotId(pCxt, pLeftDesc->dataBlockId, pRightDesc->dataBlockId, pJoinLogicNode->pOnConditions); + CHECK_ALLOC(pJoin->pOnConditions, (SPhysiNode*)pJoin); + + pJoin->pTargets = createJoinOutputCols(pCxt, pLeftDesc, pRightDesc); + CHECK_ALLOC(pJoin->pTargets, (SPhysiNode*)pJoin); + CHECK_CODE(addDataBlockDesc(pCxt, pJoin->pTargets, &pJoin->node.outputDataBlockDesc), (SPhysiNode*)pJoin); + + CHECK_CODE(setConditionsSlotId(pCxt, (const SLogicNode*)pJoinLogicNode, (SPhysiNode*)pJoin), (SPhysiNode*)pJoin); + + CHECK_CODE(setSlotOutput(pCxt, pJoinLogicNode->node.pTargets, &pJoin->node.outputDataBlockDesc), (SPhysiNode*)pJoin); + + return (SPhysiNode*)pJoin; +} + +typedef struct SRewritePrecalcExprsCxt { + int32_t errCode; + int32_t planNodeId; + int32_t rewriteId; + SNodeList* pPrecalcExprs; +} SRewritePrecalcExprsCxt; + +static EDealRes collectAndRewrite(SRewritePrecalcExprsCxt* pCxt, SNode** pNode) { + SNode* pExpr = nodesCloneNode(*pNode); + CHECK_ALLOC(pExpr, DEAL_RES_ERROR); + if (nodesListAppend(pCxt->pPrecalcExprs, pExpr)) { + nodesDestroyNode(pExpr); + return DEAL_RES_ERROR; + } + SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN); + if (NULL == pCol) { + nodesDestroyNode(pExpr); + return DEAL_RES_ERROR; + } + SExprNode* pRewrittenExpr = (SExprNode*)pExpr; + pCol->node.resType = pRewrittenExpr->resType; + if ('\0' != pRewrittenExpr->aliasName[0]) { + strcpy(pCol->colName, pRewrittenExpr->aliasName); + } else { + snprintf(pRewrittenExpr->aliasName, sizeof(pRewrittenExpr->aliasName), "#expr_%d_%d", pCxt->planNodeId, pCxt->rewriteId); + strcpy(pCol->colName, pRewrittenExpr->aliasName); + } + nodesDestroyNode(*pNode); + *pNode = (SNode*)pCol; + return DEAL_RES_IGNORE_CHILD; +} + +static EDealRes doRewritePrecalcExprs(SNode** pNode, void* pContext) { + SRewritePrecalcExprsCxt* pCxt = (SRewritePrecalcExprsCxt*)pContext; + switch (nodeType(*pNode)) { + case QUERY_NODE_OPERATOR: + case QUERY_NODE_LOGIC_CONDITION: { + return collectAndRewrite(pContext, pNode); + } + case QUERY_NODE_FUNCTION: { + if (!fmIsAggFunc(((SFunctionNode*)(*pNode))->funcId)) { + return collectAndRewrite(pContext, pNode); + } + } + default: + break; + } + return DEAL_RES_CONTINUE; +} + +static int32_t rewritePrecalcExprs(SPhysiPlanContext* pCxt, SNodeList* pList, SNodeList** pPrecalcExprs, SNodeList** pRewrittenList) { + if (NULL == pList) { + return TSDB_CODE_SUCCESS; + } + + if (NULL == *pPrecalcExprs) { + *pPrecalcExprs = nodesMakeList(); + CHECK_ALLOC(*pPrecalcExprs, TSDB_CODE_OUT_OF_MEMORY); + } + if (NULL == *pRewrittenList) { + *pRewrittenList = nodesMakeList(); + CHECK_ALLOC(*pRewrittenList, TSDB_CODE_OUT_OF_MEMORY); + } + SNode* pNode = NULL; + FOREACH(pNode, pList) { + SNode* pNew = NULL; + if (QUERY_NODE_GROUPING_SET == nodeType(pNode)) { + pNew = nodesCloneNode(nodesListGetNode(((SGroupingSetNode*)pNode)->pParameterList, 0)); + } else { + pNew = nodesCloneNode(pNode); + } + CHECK_ALLOC(pNew, TSDB_CODE_OUT_OF_MEMORY); + CHECK_CODE(nodesListAppend(*pRewrittenList, pNew), TSDB_CODE_OUT_OF_MEMORY); + } + SRewritePrecalcExprsCxt cxt = { .errCode = TSDB_CODE_SUCCESS, .pPrecalcExprs = *pPrecalcExprs }; + nodesRewriteList(*pRewrittenList, doRewritePrecalcExprs, &cxt); + if (0 == LIST_LENGTH(cxt.pPrecalcExprs)) { + nodesDestroyList(cxt.pPrecalcExprs); + *pPrecalcExprs = NULL; + } + return cxt.errCode; +} + +static SPhysiNode* createAggPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, SAggLogicNode* pAggLogicNode) { + SAggPhysiNode* pAgg = (SAggPhysiNode*)makePhysiNode(pCxt, QUERY_NODE_PHYSICAL_PLAN_AGG); + CHECK_ALLOC(pAgg, NULL); + + SNodeList* pPrecalcExprs = NULL; + SNodeList* pGroupKeys = NULL; + SNodeList* pAggFuncs = NULL; + CHECK_CODE(rewritePrecalcExprs(pCxt, pAggLogicNode->pGroupKeys, &pPrecalcExprs, &pGroupKeys), (SPhysiNode*)pAgg); + CHECK_CODE(rewritePrecalcExprs(pCxt, pAggLogicNode->pAggFuncs, &pPrecalcExprs, &pAggFuncs), (SPhysiNode*)pAgg); + + SDataBlockDescNode* pChildTupe = &(((SPhysiNode*)nodesListGetNode(pChildren, 0))->outputDataBlockDesc); + // push down expression to outputDataBlockDesc of child node + if (NULL != pPrecalcExprs) { + pAgg->pExprs = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pPrecalcExprs); + CHECK_ALLOC(pAgg->pExprs, (SPhysiNode*)pAgg); + CHECK_CODE(addDataBlockDesc(pCxt, pAgg->pExprs, pChildTupe), (SPhysiNode*)pAgg); + } + + if (NULL != pGroupKeys) { + pAgg->pGroupKeys = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pGroupKeys); + CHECK_ALLOC(pAgg->pGroupKeys, (SPhysiNode*)pAgg); + CHECK_CODE(addDataBlockDesc(pCxt, pAgg->pGroupKeys, &pAgg->node.outputDataBlockDesc), (SPhysiNode*)pAgg); + } + + if (NULL != pAggFuncs) { + pAgg->pAggFuncs = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pAggFuncs); + CHECK_ALLOC(pAgg->pAggFuncs, (SPhysiNode*)pAgg); + CHECK_CODE(addDataBlockDesc(pCxt, pAgg->pAggFuncs, &pAgg->node.outputDataBlockDesc), (SPhysiNode*)pAgg); + } + + CHECK_CODE(setConditionsSlotId(pCxt, (const SLogicNode*)pAggLogicNode, (SPhysiNode*)pAgg), (SPhysiNode*)pAgg); + + CHECK_CODE(setSlotOutput(pCxt, pAggLogicNode->node.pTargets, &pAgg->node.outputDataBlockDesc), (SPhysiNode*)pAgg); + + return (SPhysiNode*)pAgg; +} + +static SPhysiNode* createProjectPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, SProjectLogicNode* pProjectLogicNode) { + SProjectPhysiNode* pProject = (SProjectPhysiNode*)makePhysiNode(pCxt, QUERY_NODE_PHYSICAL_PLAN_PROJECT); + CHECK_ALLOC(pProject, NULL); + + pProject->pProjections = setListSlotId(pCxt, ((SPhysiNode*)nodesListGetNode(pChildren, 0))->outputDataBlockDesc.dataBlockId, -1, pProjectLogicNode->pProjections); + CHECK_ALLOC(pProject->pProjections, (SPhysiNode*)pProject); + CHECK_CODE(addDataBlockDesc(pCxt, pProject->pProjections, &pProject->node.outputDataBlockDesc), (SPhysiNode*)pProject); + + CHECK_CODE(setConditionsSlotId(pCxt, (const SLogicNode*)pProjectLogicNode, (SPhysiNode*)pProject), (SPhysiNode*)pProject); + + return (SPhysiNode*)pProject; +} + +static SPhysiNode* createPhysiNode(SPhysiPlanContext* pCxt, SLogicNode* pLogicPlan) { + SNodeList* pChildren = nodesMakeList(); + CHECK_ALLOC(pChildren, NULL); + + SNode* pLogicChild; + FOREACH(pLogicChild, pLogicPlan->pChildren) { + SNode* pChildPhyNode = (SNode*)createPhysiNode(pCxt, (SLogicNode*)pLogicChild); + if (TSDB_CODE_SUCCESS != nodesListAppend(pChildren, pChildPhyNode)) { + pCxt->errCode = TSDB_CODE_OUT_OF_MEMORY; + nodesDestroyList(pChildren); + return NULL; + } + } + + SPhysiNode* pPhyNode = NULL; + switch (nodeType(pLogicPlan)) { + case QUERY_NODE_LOGIC_PLAN_SCAN: + pPhyNode = createScanPhysiNode(pCxt, (SScanLogicNode*)pLogicPlan); + break; + case QUERY_NODE_LOGIC_PLAN_JOIN: + pPhyNode = createJoinPhysiNode(pCxt, pChildren, (SJoinLogicNode*)pLogicPlan); + break; + case QUERY_NODE_LOGIC_PLAN_AGG: + pPhyNode = createAggPhysiNode(pCxt, pChildren, (SAggLogicNode*)pLogicPlan); + break; + case QUERY_NODE_LOGIC_PLAN_PROJECT: + pPhyNode = createProjectPhysiNode(pCxt, pChildren, (SProjectLogicNode*)pLogicPlan); + break; + default: + break; + } + + pPhyNode->pChildren = pChildren; + SNode* pChild; + FOREACH(pChild, pPhyNode->pChildren) { + ((SPhysiNode*)pChild)->pParent = pPhyNode; + } + + return pPhyNode; +} + +int32_t createPhysiPlan(SLogicNode* pLogicNode, SPhysiNode** pPhyNode) { + SPhysiPlanContext cxt = { .errCode = TSDB_CODE_SUCCESS, .nextDataBlockId = 0, .pLocationHelper = taosArrayInit(32, POINTER_BYTES) }; + if (NULL == cxt.pLocationHelper) { + return TSDB_CODE_OUT_OF_MEMORY; + } + *pPhyNode = createPhysiNode(&cxt, pLogicNode); + return cxt.errCode; +} + +int32_t buildPhysiPlan(SPlanContext* pCxt, SLogicNode* pLogicNode, SQueryPlan** pPlan) { + // split + // scale out + // maping + // create + return TSDB_CODE_SUCCESS; +} diff --git a/source/libs/planner/src/physicalPlanJson.c b/source/libs/planner/src/physicalPlanJson.c deleted file mode 100644 index 1a69a9d84c..0000000000 --- a/source/libs/planner/src/physicalPlanJson.c +++ /dev/null @@ -1,1227 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the GNU Affero General Public License, version 3 - * or later ("AGPL"), as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#if 0 - -#include "plannerInt.h" -#include "parser.h" -#include "cJSON.h" - -typedef bool (*FToJson)(const void* obj, cJSON* json); -typedef bool (*FFromJson)(const cJSON* json, void* obj); - -static char* getString(const cJSON* json, const char* name) { - char* p = cJSON_GetStringValue(cJSON_GetObjectItem(json, name)); - return strdup(p); -} - -static void copyString(const cJSON* json, const char* name, char* dst) { - strcpy(dst, cJSON_GetStringValue(cJSON_GetObjectItem(json, name))); -} - -static uint64_t getBigintFromString(const cJSON* json, const char* name) { - char* val = getString(json, name); - uint64_t intVal = strtoul(val, NULL, 10); - tfree(val); - - return intVal; -} - -static int64_t getNumber(const cJSON* json, const char* name) { - double d = cJSON_GetNumberValue(cJSON_GetObjectItem(json, name)); - return (int64_t) d; -} - -static bool addObject(cJSON* json, const char* name, FToJson func, const void* obj) { - if (NULL == obj) { - return true; - } - - cJSON* jObj = cJSON_CreateObject(); - if (NULL == jObj || !func(obj, jObj)) { - cJSON_Delete(jObj); - return false; - } - return cJSON_AddItemToObject(json, name, jObj); -} - -static bool addItem(cJSON* json, FToJson func, const void* obj) { - cJSON* jObj = cJSON_CreateObject(); - if (NULL == jObj || !func(obj, jObj)) { - cJSON_Delete(jObj); - return false; - } - return cJSON_AddItemToArray(json, jObj); -} - -static bool fromObject(const cJSON* json, const char* name, FFromJson func, void* obj, bool required) { - cJSON* jObj = cJSON_GetObjectItem(json, name); - if (NULL == jObj) { - return !required; - } - return func(jObj, obj); -} - -static bool fromObjectWithAlloc(const cJSON* json, const char* name, FFromJson func, void** obj, int32_t size, bool required) { - cJSON* jObj = cJSON_GetObjectItem(json, name); - if (NULL == jObj) { - return !required; - } - *obj = calloc(1, size); - if (NULL == *obj) { - return false; - } - return func(jObj, *obj); -} - -static const char* jkPnodeType = "Type"; -static int32_t getPnodeTypeSize(cJSON* json) { - switch (getNumber(json, jkPnodeType)) { - case OP_StreamScan: - case OP_TableScan: - case OP_TableSeqScan: - return sizeof(STableScanPhyNode); - case OP_TagScan: - return sizeof(STagScanPhyNode); - case OP_SystemTableScan: - return sizeof(SSystemTableScanPhyNode); - case OP_Aggregate: - return sizeof(SAggPhyNode); - case OP_Exchange: - return sizeof(SExchangePhyNode); - default: - break; - }; - return -1; -} - -static bool fromPnode(const cJSON* json, const char* name, FFromJson func, void** obj) { - cJSON* jObj = cJSON_GetObjectItem(json, name); - if (NULL == jObj) { - return true; - } - *obj = calloc(1, getPnodeTypeSize(jObj)); - if (NULL == *obj) { - return false; - } - return func(jObj, *obj); -} - -static bool fromPnodeArray(const cJSON* json, const char* name, FFromJson func, SArray** array) { - const cJSON* jArray = cJSON_GetObjectItem(json, name); - int32_t size = (NULL == jArray ? 0 : cJSON_GetArraySize(jArray)); - if (size > 0) { - *array = taosArrayInit(size, POINTER_BYTES); - if (NULL == *array) { - return false; - } - } - for (int32_t i = 0; i < size; ++i) { - cJSON* jItem = cJSON_GetArrayItem(jArray, i); - void* item = calloc(1, getPnodeTypeSize(jItem)); - if (NULL == item || !func(jItem, item)) { - return false; - } - taosArrayPush(*array, &item); - } - return true; -} - -static bool addTarray(cJSON* json, const char* name, FToJson func, const SArray* array, bool isPoint) { - size_t size = (NULL == array) ? 0 : taosArrayGetSize(array); - if (size > 0) { - cJSON* jArray = cJSON_AddArrayToObject(json, name); - if (NULL == jArray) { - return false; - } - for (size_t i = 0; i < size; ++i) { - if (!addItem(jArray, func, isPoint ? taosArrayGetP(array, i) : taosArrayGet(array, i))) { - return false; - } - } - } - return true; -} - -static bool addInlineArray(cJSON* json, const char* name, FToJson func, const SArray* array) { - return addTarray(json, name, func, array, false); -} - -static bool addArray(cJSON* json, const char* name, FToJson func, const SArray* array) { - return addTarray(json, name, func, array, true); -} - -static bool fromTarray(const cJSON* json, const char* name, FFromJson func, SArray** array, int32_t itemSize, bool isPoint) { - const cJSON* jArray = cJSON_GetObjectItem(json, name); - int32_t size = (NULL == jArray ? 0 : cJSON_GetArraySize(jArray)); - if (size > 0) { - *array = taosArrayInit(size, isPoint ? POINTER_BYTES : itemSize); - if (NULL == *array) { - return false; - } - } - for (int32_t i = 0; i < size; ++i) { - void* item = calloc(1, itemSize); - if (NULL == item || !func(cJSON_GetArrayItem(jArray, i), item)) { - return false; - } - taosArrayPush(*array, isPoint ? &item : item); - } - return true; -} - -static bool fromInlineArray(const cJSON* json, const char* name, FFromJson func, SArray** array, int32_t itemSize) { - return fromTarray(json, name, func, array, itemSize, false); -} - -static bool fromArray(const cJSON* json, const char* name, FFromJson func, SArray** array, int32_t itemSize) { - return fromTarray(json, name, func, array, itemSize, true); -} - -static bool addRawArray(cJSON* json, const char* name, FToJson func, const void* array, int32_t itemSize, int32_t size) { - if (size > 0) { - cJSON* jArray = cJSON_AddArrayToObject(json, name); - if (NULL == jArray) { - return false; - } - for (size_t i = 0; i < size; ++i) { - if (!addItem(jArray, func, (const char*)array + itemSize * i)) { - return false; - } - } - } - return true; -} - -static const cJSON* getArray(const cJSON* json, const char* name, int32_t* size) { - const cJSON* jArray = cJSON_GetObjectItem(json, name); - *size = (NULL == jArray ? 0 : cJSON_GetArraySize(jArray)); - return jArray; -} - -static bool fromItem(const cJSON* jArray, FFromJson func, void* array, int32_t itemSize, int32_t size) { - for (int32_t i = 0; i < size; ++i) { - if (!func(cJSON_GetArrayItem(jArray, i), (char*)array + itemSize * i)) { - return false; - } - } - return true; -} - -static bool fromRawArrayWithAlloc(const cJSON* json, const char* name, FFromJson func, void** array, int32_t itemSize, int32_t* size) { - const cJSON* jArray = getArray(json, name, size); - if (*size > 0) { - *array = calloc(1, itemSize * (*size)); - if (NULL == *array) { - return false; - } - } - return fromItem(jArray, func, *array, itemSize, *size); -} - -static bool fromRawArray(const cJSON* json, const char* name, FFromJson func, void* array, int32_t itemSize, int32_t* size) { - const cJSON* jArray = getArray(json, name, size); - return fromItem(jArray, func, array, itemSize, *size); -} - -static const char* jkSchemaType = "Type"; -static const char* jkSchemaColId = "ColId"; -static const char* jkSchemaBytes = "Bytes"; -// The 'name' field do not need to be serialized. -static bool schemaToJson(const void* obj, cJSON* jSchema) { - const SSlotSchema* schema = (const SSlotSchema*)obj; - bool res = cJSON_AddNumberToObject(jSchema, jkSchemaType, schema->type); - if (res) { - res = cJSON_AddNumberToObject(jSchema, jkSchemaColId, schema->colId); - } - if (res) { - res = cJSON_AddNumberToObject(jSchema, jkSchemaBytes, schema->bytes); - } - return res; -} - -static bool schemaFromJson(const cJSON* json, void* obj) { - SSlotSchema* schema = (SSlotSchema*)obj; - schema->type = getNumber(json, jkSchemaType); - schema->colId = getNumber(json, jkSchemaColId); - schema->bytes = getNumber(json, jkSchemaBytes); - return true; -} - -static const char* jkDataBlockSchemaSlotSchema = "SlotSchema"; -static const char* jkDataBlockSchemaResultRowSize = "resultRowSize"; -static const char* jkDataBlockSchemaPrecision = "Precision"; - -static bool dataBlockSchemaToJson(const void* obj, cJSON* json) { - const SDataBlockSchema* schema = (const SDataBlockSchema*)obj; - bool res = addRawArray(json, jkDataBlockSchemaSlotSchema, schemaToJson, schema->pSchema, sizeof(SSlotSchema), schema->numOfCols); - if (res) { - res = cJSON_AddNumberToObject(json, jkDataBlockSchemaResultRowSize, schema->resultRowSize); - } - if (res) { - res = cJSON_AddNumberToObject(json, jkDataBlockSchemaPrecision, schema->precision); - } - return res; -} - -static bool dataBlockSchemaFromJson(const cJSON* json, void* obj) { - SDataBlockSchema* schema = (SDataBlockSchema*)obj; - schema->resultRowSize = getNumber(json, jkDataBlockSchemaResultRowSize); - schema->precision = getNumber(json, jkDataBlockSchemaPrecision); - - return fromRawArrayWithAlloc(json, jkDataBlockSchemaSlotSchema, schemaFromJson, (void**)&(schema->pSchema), sizeof(SSlotSchema), &schema->numOfCols); -} - -static const char* jkColumnFilterInfoLowerRelOptr = "LowerRelOptr"; -static const char* jkColumnFilterInfoUpperRelOptr = "UpperRelOptr"; -static const char* jkColumnFilterInfoFilterstr = "Filterstr"; -static const char* jkColumnFilterInfoLowerBnd = "LowerBnd"; -static const char* jkColumnFilterInfoUpperBnd = "UpperBnd"; - -static bool columnFilterInfoToJson(const void* obj, cJSON* jFilter) { - const SColumnFilterInfo* filter = (const SColumnFilterInfo*)obj; - bool res = cJSON_AddNumberToObject(jFilter, jkColumnFilterInfoLowerRelOptr, filter->lowerRelOptr); - if (res) { - res = cJSON_AddNumberToObject(jFilter, jkColumnFilterInfoUpperRelOptr, filter->upperRelOptr); - } - if (res) { - res = cJSON_AddNumberToObject(jFilter, jkColumnFilterInfoFilterstr, filter->filterstr); - } - if (res) { - res = cJSON_AddNumberToObject(jFilter, jkColumnFilterInfoLowerBnd, filter->lowerBndd); - } - if (res) { - res = cJSON_AddNumberToObject(jFilter, jkColumnFilterInfoUpperBnd, filter->upperBndd); - } - return res; -} - -static bool columnFilterInfoFromJson(const cJSON* json, void* obj) { - SColumnFilterInfo* filter = (SColumnFilterInfo*)obj; - filter->lowerRelOptr = getNumber(json, jkColumnFilterInfoLowerRelOptr); - filter->upperRelOptr = getNumber(json, jkColumnFilterInfoUpperRelOptr); - filter->filterstr = getNumber(json, jkColumnFilterInfoFilterstr); - filter->lowerBndd = getNumber(json, jkColumnFilterInfoLowerBnd); - filter->upperBndd = getNumber(json, jkColumnFilterInfoUpperBnd); - return true; -} - -static const char* jkColumnInfoColId = "ColId"; -static const char* jkColumnInfoType = "Type"; -static const char* jkColumnInfoBytes = "Bytes"; -static const char* jkColumnInfoFilterList = "FilterList"; - -static bool columnInfoToJson(const void* obj, cJSON* jCol) { - const SColumnInfo* col = (const SColumnInfo*)obj; - bool res = cJSON_AddNumberToObject(jCol, jkColumnInfoColId, col->colId); - if (res) { - res = cJSON_AddNumberToObject(jCol, jkColumnInfoType, col->type); - } - if (res) { - res = cJSON_AddNumberToObject(jCol, jkColumnInfoBytes, col->bytes); - } - - if (res) { // TODO: temporarily disable it -// res = addRawArray(jCol, jkColumnInfoFilterList, columnFilterInfoToJson, col->flist.filterInfo, sizeof(SColumnFilterInfo), col->flist.numOfFilters); - } - - return res; -} - -static bool columnInfoFromJson(const cJSON* json, void* obj) { - SColumnInfo* col = (SColumnInfo*)obj; - col->colId = getNumber(json, jkColumnInfoColId); - col->type = getNumber(json, jkColumnInfoType); - col->bytes = getNumber(json, jkColumnInfoBytes); - int32_t size = 0; - bool res = fromRawArrayWithAlloc(json, jkColumnInfoFilterList, columnFilterInfoFromJson, (void**)&col->flist.filterInfo, sizeof(SColumnFilterInfo), &size); - col->flist.numOfFilters = size; - return res; -} - -static const char* jkColumnTableId = "TableId"; -static const char* jkColumnFlag = "Flag"; -static const char* jkColumnInfo = "Info"; - -static bool columnToJson(const void* obj, cJSON* jCol) { - const SColumn* col = (const SColumn*)obj; - bool res = cJSON_AddNumberToObject(jCol, jkColumnTableId, col->uid); - if (res) { - res = cJSON_AddNumberToObject(jCol, jkColumnFlag, col->flag); - } - if (res) { - res = addObject(jCol, jkColumnInfo, columnInfoToJson, &col->info); - } - return res; -} - -static bool columnFromJson(const cJSON* json, void* obj) { - SColumn* col = (SColumn*)obj; - col->uid = getNumber(json, jkColumnTableId); - col->flag = getNumber(json, jkColumnFlag); - return fromObject(json, jkColumnInfo, columnInfoFromJson, &col->info, true); -} - -static bool exprNodeToJson(const void* obj, cJSON* jExprInfo); -static bool exprNodeFromJson(const cJSON* json, void* obj); - -static const char* jkExprNodeOper = "Oper"; -static const char* jkExprNodeLeft = "Left"; -static const char* jkExprNodeRight = "Right"; - -static bool operatorToJson(const void* obj, cJSON* jOper) { - const tExprNode* exprInfo = (const tExprNode*)obj; - bool res = cJSON_AddNumberToObject(jOper, jkExprNodeOper, exprInfo->_node.optr); - if (res) { - res = addObject(jOper, jkExprNodeLeft, exprNodeToJson, exprInfo->_node.pLeft); - } - if (res) { - res = addObject(jOper, jkExprNodeRight, exprNodeToJson, exprInfo->_node.pRight); - } - return res; -} - -static bool operatorFromJson(const cJSON* json, void* obj) { - tExprNode* exprInfo = (tExprNode*)obj; - exprInfo->_node.optr = getNumber(json, jkExprNodeOper); - bool res = fromObject(json, jkExprNodeLeft, exprNodeFromJson, exprInfo->_node.pLeft, false); - if (res) { - res = fromObject(json, jkExprNodeRight, exprNodeFromJson, exprInfo->_node.pRight, false); - } - return res; -} - -static const char* jkFunctionName = "Name"; -static const char* jkFunctionChild = "Child"; - -static bool functionToJson(const void* obj, cJSON* jFunc) { - const tExprNode* exprInfo = (const tExprNode*)obj; - bool res = cJSON_AddStringToObject(jFunc, jkFunctionName, exprInfo->_function.functionName); - if (res && NULL != exprInfo->_function.pChild) { - res = addRawArray(jFunc, jkFunctionChild, exprNodeToJson, exprInfo->_function.pChild, sizeof(tExprNode*), exprInfo->_function.num); - } - return res; -} - -static bool functionFromJson(const cJSON* json, void* obj) { - tExprNode* exprInfo = (tExprNode*)obj; - copyString(json, jkFunctionName, exprInfo->_function.functionName); - exprInfo->_function.pChild = calloc(1, sizeof(tExprNode*)); - if (NULL == exprInfo->_function.pChild) { - return false; - } - return fromRawArrayWithAlloc(json, jkFunctionChild, exprNodeFromJson, (void**)exprInfo->_function.pChild, sizeof(tExprNode*), &exprInfo->_function.num); -} - -static const char* jkVariantType = "Type"; -static const char* jkVariantLen = "Len"; -static const char* jkVariantvalues = "values"; -static const char* jkVariantValue = "Value"; - -static bool variantToJson(const void* obj, cJSON* jVar) { - const SVariant* var = (const SVariant*)obj; - bool res = cJSON_AddNumberToObject(jVar, jkVariantType, var->nType); - if (res) { - res = cJSON_AddNumberToObject(jVar, jkVariantLen, var->nLen); - } - if (res) { - if (0/* in */) { - res = addArray(jVar, jkVariantvalues, variantToJson, var->arr); - } else if (IS_NUMERIC_TYPE(var->nType)) { - res = cJSON_AddNumberToObject(jVar, jkVariantValue, var->d); - } else { - res = cJSON_AddStringToObject(jVar, jkVariantValue, var->pz); - } - } - return res; -} - -static bool variantFromJson(const cJSON* json, void* obj) { - SVariant* var = (SVariant*)obj; - var->nType = getNumber(json, jkVariantType); - var->nLen = getNumber(json, jkVariantLen); - if (0/* in */) { - return fromArray(json, jkVariantvalues, variantFromJson, &var->arr, sizeof(SVariant)); - } else if (IS_NUMERIC_TYPE(var->nType)) { - var->d = getNumber(json, jkVariantValue); - } else { - var->pz = getString(json, jkVariantValue); - } - return true; -} - -static const char* jkExprNodeType = "Type"; -static const char* jkExprNodeOperator = "Operator"; -static const char* jkExprNodeFunction = "Function"; -static const char* jkExprNodeColumn = "Column"; -static const char* jkExprNodeValue = "Value"; - -static bool exprNodeToJson(const void* obj, cJSON* jExprInfo) { - const tExprNode* exprInfo = *(const tExprNode**)obj; - bool res = cJSON_AddNumberToObject(jExprInfo, jkExprNodeType, exprInfo->nodeType); - if (res) { - switch (exprInfo->nodeType) { - case TEXPR_BINARYEXPR_NODE: - case TEXPR_UNARYEXPR_NODE: - res = addObject(jExprInfo, jkExprNodeOperator, operatorToJson, exprInfo); - break; - case TEXPR_FUNCTION_NODE: - res = addObject(jExprInfo, jkExprNodeFunction, functionToJson, exprInfo); - break; - case TEXPR_COL_NODE: - res = addObject(jExprInfo, jkExprNodeColumn, schemaToJson, exprInfo->pSchema); - break; - case TEXPR_VALUE_NODE: - res = addObject(jExprInfo, jkExprNodeValue, variantToJson, exprInfo->pVal); - break; - default: - res = false; - break; - } - } - return res; -} - -static bool exprNodeFromJson(const cJSON* json, void* obj) { - tExprNode* exprInfo = (tExprNode*)obj; - exprInfo->nodeType = getNumber(json, jkExprNodeType); - switch (exprInfo->nodeType) { - case TEXPR_BINARYEXPR_NODE: - case TEXPR_UNARYEXPR_NODE: - return fromObject(json, jkExprNodeOperator, operatorFromJson, exprInfo, false); - case TEXPR_FUNCTION_NODE: - return fromObject(json, jkExprNodeFunction, functionFromJson, exprInfo, false); - case TEXPR_COL_NODE: - return fromObjectWithAlloc(json, jkExprNodeColumn, schemaFromJson, (void**)&exprInfo->pSchema, sizeof(SSchema), false); - case TEXPR_VALUE_NODE: - return fromObject(json, jkExprNodeValue, variantFromJson, exprInfo->pVal, false); - default: - break; - } - return false; -} - -static const char* jkSqlExprSchema = "Schema"; -static const char* jkSqlExprColumns = "Columns"; -static const char* jkSqlExprInterBytes = "InterBytes"; -static const char* jkSqlExprParams = "Params"; -// token does not need to be serialized. -static bool sqlExprToJson(const void* obj, cJSON* jExpr) { - const SSqlExpr* expr = (const SSqlExpr*)obj; - bool res = addObject(jExpr, jkSqlExprSchema, schemaToJson, &expr->resSchema); - if (res) { - res = addRawArray(jExpr, jkSqlExprColumns, columnToJson, expr->pColumns, sizeof(SColumn), expr->numOfCols); - } - if (res) { - res = cJSON_AddNumberToObject(jExpr, jkSqlExprInterBytes, expr->interBytes); - } - if (res) { - res = addRawArray(jExpr, jkSqlExprParams, variantToJson, expr->param, sizeof(SVariant), expr->numOfParams); - } - return res; -} - -static bool sqlExprFromJson(const cJSON* json, void* obj) { - SSqlExpr* expr = (SSqlExpr*)obj; - bool res = fromObject(json, jkSqlExprSchema, schemaFromJson, &expr->resSchema, false); - if (res) { - res = fromRawArrayWithAlloc(json, jkSqlExprColumns, columnFromJson, (void**)&expr->pColumns, sizeof(SColumn), &expr->numOfCols); - } - if (res) { - expr->interBytes = getNumber(json, jkSqlExprInterBytes); - } - if (res) { - int32_t size = 0; - res = fromRawArray(json, jkSqlExprParams, variantFromJson, expr->param, sizeof(SVariant), &size); - expr->numOfParams = size; - } - return res; -} - -static const char* jkExprInfoBase = "Base"; -static const char* jkExprInfoExpr = "Expr"; - -static bool exprInfoToJson(const void* obj, cJSON* jExprInfo) { - const SExprInfo* exprInfo = (const SExprInfo*)obj; - bool res = addObject(jExprInfo, jkExprInfoBase, sqlExprToJson, &exprInfo->base); - if (res) { - res = addObject(jExprInfo, jkExprInfoExpr, exprNodeToJson, &exprInfo->pExpr); - } - return res; -} - -static bool exprInfoFromJson(const cJSON* json, void* obj) { - SExprInfo* exprInfo = (SExprInfo*)obj; - bool res = fromObject(json, jkExprInfoBase, sqlExprFromJson, &exprInfo->base, true); - if (res) { - res = fromObjectWithAlloc(json, jkExprInfoExpr, exprNodeFromJson, (void**)&exprInfo->pExpr, sizeof(tExprNode), true); - } - return res; -} - -static const char* jkTimeWindowStartKey = "StartKey"; -static const char* jkTimeWindowEndKey = "EndKey"; - -static bool timeWindowToJson(const void* obj, cJSON* json) { - const STimeWindow* win = (const STimeWindow*)obj; - - char tmp[40] = {0}; - snprintf(tmp, tListLen(tmp),"%"PRId64, win->skey); - - bool res = cJSON_AddStringToObject(json, jkTimeWindowStartKey, tmp); - if (res) { - memset(tmp, 0, tListLen(tmp)); - snprintf(tmp, tListLen(tmp),"%"PRId64, win->ekey); - res = cJSON_AddStringToObject(json, jkTimeWindowEndKey, tmp); - } - return res; -} - -static bool timeWindowFromJson(const cJSON* json, void* obj) { - STimeWindow* win = (STimeWindow*)obj; - win->skey = getBigintFromString(json, jkTimeWindowStartKey); - win->ekey = getBigintFromString(json, jkTimeWindowEndKey); - return true; -} - -static const char* jkScanNodeTableId = "TableId"; -static const char* jkScanNodeTableType = "TableType"; -static const char* jkScanNodeTableOrder = "Order"; -static const char* jkScanNodeTableCount = "Count"; -static const char* jkScanNodeTableRevCount = "Reverse"; - -static bool scanNodeToJson(const void* obj, cJSON* json) { - const SScanPhyNode* pNode = (const SScanPhyNode*)obj; - - char uid[40] = {0}; - snprintf(uid, tListLen(uid), "%"PRIu64, pNode->uid); - bool res = cJSON_AddStringToObject(json, jkScanNodeTableId, uid); - - if (res) { - res = cJSON_AddNumberToObject(json, jkScanNodeTableType, pNode->tableType); - } - - if (res) { - res = cJSON_AddNumberToObject(json, jkScanNodeTableOrder, pNode->order); - } - - if (res) { - res = cJSON_AddNumberToObject(json, jkScanNodeTableCount, pNode->count); - } - - if (res) { - res = cJSON_AddNumberToObject(json, jkScanNodeTableRevCount, pNode->reverse); - } - - return res; -} - -static bool scanNodeFromJson(const cJSON* json, void* obj) { - SScanPhyNode* pNode = (SScanPhyNode*)obj; - - pNode->uid = getBigintFromString(json, jkScanNodeTableId); - pNode->tableType = getNumber(json, jkScanNodeTableType); - pNode->count = getNumber(json, jkScanNodeTableCount); - pNode->order = getNumber(json, jkScanNodeTableOrder); - pNode->reverse = getNumber(json, jkScanNodeTableRevCount); - return true; -} - -static const char* jkColIndexColId = "ColId"; -static const char* jkColIndexColIndex = "ColIndex"; -static const char* jkColIndexFlag = "Flag"; -static const char* jkColIndexName = "Name"; - -static bool colIndexToJson(const void* obj, cJSON* json) { - const SColIndex* col = (const SColIndex*)obj; - bool res = cJSON_AddNumberToObject(json, jkColIndexColId, col->colId); - if (res) { - res = cJSON_AddNumberToObject(json, jkColIndexColIndex, col->colIndex); - } - if (res) { - res = cJSON_AddNumberToObject(json, jkColIndexFlag, col->flag); - } - if (res) { - res = cJSON_AddStringToObject(json, jkColIndexName, col->name); - } - return res; -} - -static bool colIndexFromJson(const cJSON* json, void* obj) { - SColIndex* col = (SColIndex*)obj; - col->colId = getNumber(json, jkColIndexColId); - col->colIndex = getNumber(json, jkColIndexColIndex); - col->flag = getNumber(json, jkColIndexFlag); - copyString(json, jkColIndexName, col->name); - return true; -} - -static const char* jkAggNodeAggAlgo = "AggAlgo"; -static const char* jkAggNodeAggSplit = "AggSplit"; -static const char* jkAggNodeExprs = "Exprs"; -static const char* jkAggNodeGroupByList = "GroupByList"; - -static bool aggNodeToJson(const void* obj, cJSON* json) { - const SAggPhyNode* agg = (const SAggPhyNode*)obj; - bool res = cJSON_AddNumberToObject(json, jkAggNodeAggAlgo, agg->aggAlgo); - if (res) { - res = cJSON_AddNumberToObject(json, jkAggNodeAggSplit, agg->aggSplit); - } - if (res) { - res = addArray(json, jkAggNodeExprs, exprInfoToJson, agg->pExprs); - } - if (res) { - res = addArray(json, jkAggNodeGroupByList, colIndexToJson, agg->pGroupByList); - } - return res; -} - -static bool aggNodeFromJson(const cJSON* json, void* obj) { - SAggPhyNode* agg = (SAggPhyNode*)obj; - agg->aggAlgo = getNumber(json, jkAggNodeAggAlgo); - agg->aggSplit = getNumber(json, jkAggNodeAggSplit); - bool res = fromArray(json, jkAggNodeExprs, exprInfoFromJson, &agg->pExprs, sizeof(SExprInfo)); - if (res) { - res = fromArray(json, jkAggNodeGroupByList, colIndexFromJson, &agg->pGroupByList, sizeof(SExprInfo)); - } - return res; -} - -static const char* jkTableScanNodeFlag = "Flag"; -static const char* jkTableScanNodeWindow = "Window"; -static const char* jkTableScanNodeTagsConditions = "TagsConditions"; - -static bool tableScanNodeToJson(const void* obj, cJSON* json) { - const STableScanPhyNode* scan = (const STableScanPhyNode*)obj; - bool res = scanNodeToJson(obj, json); - if (res) { - res = cJSON_AddNumberToObject(json, jkTableScanNodeFlag, scan->scanFlag); - } - if (res) { - res = addObject(json, jkTableScanNodeWindow, timeWindowToJson, &scan->window); - } - if (res) { - res = addArray(json, jkTableScanNodeTagsConditions, exprInfoToJson, scan->pTagsConditions); - } - return res; -} - -static bool tableScanNodeFromJson(const cJSON* json, void* obj) { - STableScanPhyNode* scan = (STableScanPhyNode*)obj; - bool res = scanNodeFromJson(json, obj); - if (res) { - scan->scanFlag = getNumber(json, jkTableScanNodeFlag); - } - if (res) { - res = fromObject(json, jkTableScanNodeWindow, timeWindowFromJson, &scan->window, true); - } - if (res) { - res = fromArray(json, jkTableScanNodeTagsConditions, exprInfoFromJson, &scan->pTagsConditions, sizeof(SExprInfo)); - } - return res; -} - -static const char* jkEpAddrFqdn = "Fqdn"; -static const char* jkEpAddrPort = "Port"; - -static bool epAddrToJson(const void* obj, cJSON* json) { - const SEp* ep = (const SEp*)obj; - bool res = cJSON_AddStringToObject(json, jkEpAddrFqdn, ep->fqdn); - if (res) { - res = cJSON_AddNumberToObject(json, jkEpAddrPort, ep->port); - } - return res; -} - -static bool epAddrFromJson(const cJSON* json, void* obj) { - SEp* ep = (SEp*)obj; - copyString(json, jkEpAddrFqdn, ep->fqdn); - ep->port = getNumber(json, jkEpAddrPort); - return true; -} - -static const char* jkNodeAddrId = "NodeId"; -static const char* jkNodeAddrInUse = "InUse"; -static const char* jkNodeAddrEpAddrs = "Ep"; -static const char* jkNodeAddr = "NodeAddr"; -static const char* jkNodeTaskId = "TaskId"; -static const char* jkNodeTaskSchedId = "SchedId"; - -static bool queryNodeAddrToJson(const void* obj, cJSON* json) { - const SQueryNodeAddr* pAddr = (const SQueryNodeAddr*) obj; - bool res = cJSON_AddNumberToObject(json, jkNodeAddrId, pAddr->nodeId); - - if (res) { - res = cJSON_AddNumberToObject(json, jkNodeAddrInUse, pAddr->epset.inUse); - } - - if (res) { - res = addRawArray(json, jkNodeAddrEpAddrs, epAddrToJson, pAddr->epset.eps, sizeof(SEp), pAddr->epset.numOfEps); - } - return res; -} - -static bool queryNodeAddrFromJson(const cJSON* json, void* obj) { - SQueryNodeAddr* pAddr = (SQueryNodeAddr*) obj; - - pAddr->nodeId = getNumber(json, jkNodeAddrId); - pAddr->epset.inUse = getNumber(json, jkNodeAddrInUse); - - int32_t numOfEps = 0; - bool res = fromRawArray(json, jkNodeAddrEpAddrs, epAddrFromJson, pAddr->epset.eps, sizeof(SEp), &numOfEps); - pAddr->epset.numOfEps = numOfEps; - return res; -} - -static bool nodeAddrToJson(const void* obj, cJSON* json) { - const SDownstreamSource* pSource = (const SDownstreamSource*) obj; - bool res = cJSON_AddNumberToObject(json, jkNodeTaskId, pSource->taskId); - - if (res) { - char t[30] = {0}; - snprintf(t, tListLen(t), "%"PRIu64, pSource->schedId); - res = cJSON_AddStringToObject(json, jkNodeTaskSchedId, t); - } - - if (res) { - res = addObject(json, jkNodeAddr, queryNodeAddrToJson, &pSource->addr); - } - return res; -} - -static bool nodeAddrFromJson(const cJSON* json, void* obj) { - SDownstreamSource* pSource = (SDownstreamSource*)obj; - pSource->taskId = getNumber(json, jkNodeTaskId); - - pSource->schedId = getBigintFromString(json, jkNodeTaskSchedId); - bool res = fromObject(json, jkNodeAddr, queryNodeAddrFromJson, &pSource->addr, true); - return res; -} - -static const char* jkExchangeNodeSrcTemplateId = "SrcTemplateId"; -static const char* jkExchangeNodeSrcEndPoints = "SrcAddrs"; - -static bool exchangeNodeToJson(const void* obj, cJSON* json) { - const SExchangePhyNode* exchange = (const SExchangePhyNode*)obj; - bool res = cJSON_AddNumberToObject(json, jkExchangeNodeSrcTemplateId, exchange->srcTemplateId); - if (res) { - res = addRawArray(json, jkExchangeNodeSrcEndPoints, nodeAddrToJson, exchange->pSrcEndPoints->pData, sizeof(SDownstreamSource), taosArrayGetSize(exchange->pSrcEndPoints)); - } - return res; -} - -static bool exchangeNodeFromJson(const cJSON* json, void* obj) { - SExchangePhyNode* exchange = (SExchangePhyNode*)obj; - exchange->srcTemplateId = getNumber(json, jkExchangeNodeSrcTemplateId); - return fromInlineArray(json, jkExchangeNodeSrcEndPoints, nodeAddrFromJson, &exchange->pSrcEndPoints, sizeof(SDownstreamSource)); -} - -static bool specificPhyNodeToJson(const void* obj, cJSON* json) { - const SPhyNode* phyNode = (const SPhyNode*)obj; - switch (phyNode->info.type) { - case OP_StreamScan: - case OP_TableScan: - case OP_TableSeqScan: - return tableScanNodeToJson(obj, json); - case OP_TagScan: - case OP_SystemTableScan: - return scanNodeToJson(obj, json); - case OP_Aggregate: - return aggNodeToJson(obj, json); - case OP_Project: - return true; - // case OP_Groupby: - case OP_Limit: - case OP_SLimit: - case OP_TimeWindow: - case OP_SessionWindow: - case OP_StateWindow: - case OP_Fill: - case OP_MultiTableAggregate: - case OP_MultiTableTimeInterval: - case OP_Filter: - case OP_Distinct: - case OP_Join: - case OP_AllTimeWindow: - case OP_AllMultiTableTimeInterval: - case OP_Order: - break; // todo - case OP_Exchange: - return exchangeNodeToJson(obj, json); - default: - break; - } - return false; -} - -static bool specificPhyNodeFromJson(const cJSON* json, void* obj) { - SPhyNode* phyNode = (SPhyNode*)obj; - switch (phyNode->info.type) { - case OP_StreamScan: - case OP_TableScan: - case OP_TableSeqScan: - return tableScanNodeFromJson(json, obj); - case OP_TagScan: - case OP_SystemTableScan: - return scanNodeFromJson(json, obj); - case OP_Aggregate: - return aggNodeFromJson(json, obj); - case OP_Project: - return true; - // case OP_Groupby: - case OP_Limit: - case OP_SLimit: - case OP_TimeWindow: - case OP_SessionWindow: - case OP_StateWindow: - case OP_Fill: - case OP_MultiTableAggregate: - case OP_MultiTableTimeInterval: - case OP_Filter: - case OP_Distinct: - case OP_Join: - case OP_AllTimeWindow: - case OP_AllMultiTableTimeInterval: - case OP_Order: - break; // todo - case OP_Exchange: - return exchangeNodeFromJson(json, obj); - default: - break; - } - return false; -} - -static const char* jkPnodeName = "Name"; -static const char* jkPnodeTargets = "Targets"; -static const char* jkPnodeConditions = "Conditions"; -static const char* jkPnodeSchema = "TargetSchema"; -static const char* jkPnodeChildren = "Children"; -// The 'pParent' field do not need to be serialized. -static bool phyNodeToJson(const void* obj, cJSON* jNode) { - const SPhyNode* phyNode = (const SPhyNode*)obj; - bool res = cJSON_AddNumberToObject(jNode, jkPnodeType, phyNode->info.type); - if (res) { - res = cJSON_AddStringToObject(jNode, jkPnodeName, phyNode->info.name); - } - if (res) { - res = addArray(jNode, jkPnodeTargets, exprInfoToJson, phyNode->pTargets); - } - if (res) { - res = addArray(jNode, jkPnodeConditions, exprInfoToJson, phyNode->pConditions); - } - if (res) { - res = addObject(jNode, jkPnodeSchema, dataBlockSchemaToJson, &phyNode->targetSchema); - } - if (res) { - res = addArray(jNode, jkPnodeChildren, phyNodeToJson, phyNode->pChildren); - } - if (res) { - res = addObject(jNode, phyNode->info.name, specificPhyNodeToJson, phyNode); - } - return res; -} - -static bool phyNodeFromJson(const cJSON* json, void* obj) { - SPhyNode* node = (SPhyNode*) obj; - - node->info.type = getNumber(json, jkPnodeType); - node->info.name = opTypeToOpName(node->info.type); - - bool res = fromArray(json, jkPnodeTargets, exprInfoFromJson, &node->pTargets, sizeof(SExprInfo)); - if (res) { - res = fromArray(json, jkPnodeConditions, exprInfoFromJson, &node->pConditions, sizeof(SExprInfo)); - } - if (res) { - res = fromObject(json, jkPnodeSchema, dataBlockSchemaFromJson, &node->targetSchema, true); - } - if (res) { - res = fromPnodeArray(json, jkPnodeChildren, phyNodeFromJson, &node->pChildren); - } - if (res) { - res = fromObject(json, node->info.name, specificPhyNodeFromJson, node, true); - } - return res; -} - -static const char* jkInserterNumOfTables = "NumOfTables"; -static const char* jkInserterDataSize = "DataSize"; - -static bool inserterToJson(const void* obj, cJSON* json) { - const SDataInserter* inserter = (const SDataInserter*)obj; - bool res = cJSON_AddNumberToObject(json, jkInserterNumOfTables, inserter->numOfTables); - if (res) { - res = cJSON_AddNumberToObject(json, jkInserterDataSize, inserter->size); - } - // todo pData - return res; -} - -static bool inserterFromJson(const cJSON* json, void* obj) { - SDataInserter* inserter = (SDataInserter*)obj; - inserter->numOfTables = getNumber(json, jkInserterNumOfTables); - inserter->size = getNumber(json, jkInserterDataSize); - // todo pData -} - -static bool specificDataSinkToJson(const void* obj, cJSON* json) { - const SDataSink* dsink = (const SDataSink*)obj; - switch (dsink->info.type) { - case DSINK_Dispatch: - return true; - case DSINK_Insert: - return inserterToJson(obj, json); - default: - break; - } - return false; -} - -static bool specificDataSinkFromJson(const cJSON* json, void* obj) { - SDataSink* dsink = (SDataSink*)obj; - switch (dsink->info.type) { - case DSINK_Dispatch: - return true; - case DSINK_Insert: - return inserterFromJson(json, obj); - default: - break; - } - return false; -} - -static const char* jkDataSinkName = "Name"; -static const char* jkDataSinkSchema = "Schema"; - -static bool dataSinkToJson(const void* obj, cJSON* json) { - const SDataSink* dsink = (const SDataSink*)obj; - bool res = cJSON_AddStringToObject(json, jkDataSinkName, dsink->info.name); - if (res) { - res = addObject(json, dsink->info.name, specificDataSinkToJson, dsink); - } - if (res) { - res = addObject(json, jkDataSinkSchema, dataBlockSchemaToJson, &dsink->schema); - } - return res; -} - -static bool dataSinkFromJson(const cJSON* json, void* obj) { - SDataSink* dsink = (SDataSink*)obj; - dsink->info.name = getString(json, jkDataSinkName); - dsink->info.type = dsinkNameToDsinkType(dsink->info.name); - bool res = fromObject(json, jkDataSinkSchema, dataBlockSchemaFromJson, &dsink->schema, true); - if (res) { - res = fromObject(json, dsink->info.name, specificDataSinkFromJson, dsink, true); - } - return res; -} - -static const char* jkIdQueryId = "QueryId"; -static const char* jkIdTemplateId = "TemplateId"; -static const char* jkIdSubplanId = "SubplanId"; - -static bool subplanIdToJson(const void* obj, cJSON* jId) { - const SSubplanId* id = (const SSubplanId*)obj; - - char ids[40] = {0}; - snprintf(ids, tListLen(ids), "%"PRIu64, id->queryId); - - bool res = cJSON_AddStringToObject(jId, jkIdQueryId, ids); - if (res) { - res = cJSON_AddNumberToObject(jId, jkIdTemplateId, id->templateId); - } - if (res) { - res = cJSON_AddNumberToObject(jId, jkIdSubplanId, id->subplanId); - } - return res; -} - -static bool subplanIdFromJson(const cJSON* json, void* obj) { - SSubplanId* id = (SSubplanId*)obj; - - id->queryId = getBigintFromString(json, jkIdQueryId); - id->templateId = getNumber(json, jkIdTemplateId); - id->subplanId = getNumber(json, jkIdSubplanId); - return true; -} - -static const char* jkSubplanId = "Id"; -static const char* jkSubplanNode = "Node"; -static const char* jkSubplanDataSink = "DataSink"; - -static cJSON* subplanToJson(const SSubplan* subplan) { - cJSON* jSubplan = cJSON_CreateObject(); - if (NULL == jSubplan) { - return NULL; - } - - // The 'type', 'level', 'execEpSet', 'pChildren' and 'pParents' fields do not need to be serialized. - bool res = addObject(jSubplan, jkSubplanId, subplanIdToJson, &subplan->id); - if (res) { - res = addObject(jSubplan, jkSubplanNode, phyNodeToJson, subplan->pNode); - } - if (res) { - res = addObject(jSubplan, jkSubplanDataSink, dataSinkToJson, subplan->pDataSink); - } - if (!res) { - cJSON_Delete(jSubplan); - return NULL; - } - - return jSubplan; -} - -static SSubplan* subplanFromJson(const cJSON* json) { - SSubplan* subplan = calloc(1, sizeof(SSubplan)); - if (NULL == subplan) { - return NULL; - } - - bool res = fromObject(json, jkSubplanId, subplanIdFromJson, &subplan->id, true); - - if (res) { - res = fromPnode(json, jkSubplanNode, phyNodeFromJson, (void**)&subplan->pNode); - } - - if (res) { - res = fromObjectWithAlloc(json, jkSubplanDataSink, dataSinkFromJson, (void**)&subplan->pDataSink, sizeof(SDataSink), false); - } - - if (!res) { - qDestroySubplan(subplan); - return NULL; - } - return subplan; -} - -int32_t subPlanToString(const SSubplan* subplan, char** str, int32_t* len) { - if (QUERY_TYPE_MODIFY == subplan->type) { - SDataInserter* insert = (SDataInserter*)(subplan->pDataSink); - *len = insert->size; - *str = insert->pData; - insert->pData = NULL; - return TSDB_CODE_SUCCESS; - } - - cJSON* json = subplanToJson(subplan); - if (NULL == json) { - terrno = TSDB_CODE_TSC_OUT_OF_MEMORY; - return TSDB_CODE_FAILED; - } - - *str = cJSON_Print(json); - cJSON_Delete(json); - - *len = strlen(*str) + 1; - return TSDB_CODE_SUCCESS; -} - -int32_t stringToSubplan(const char* str, SSubplan** subplan) { - cJSON* json = cJSON_Parse(str); - if (NULL == json) { - return TSDB_CODE_FAILED; - } - *subplan = subplanFromJson(json); - return (NULL == *subplan ? TSDB_CODE_FAILED : TSDB_CODE_SUCCESS); -} - -cJSON* qDagToJson(const SQueryDag* pDag) { - cJSON* pRoot = cJSON_CreateObject(); - if(pRoot == NULL) { - return NULL; - } - - cJSON_AddNumberToObject(pRoot, "Number", pDag->numOfSubplans); - cJSON_AddNumberToObject(pRoot, "QueryId", pDag->queryId); - - cJSON *pLevels = cJSON_CreateArray(); - if(pLevels == NULL) { - cJSON_Delete(pRoot); - return NULL; - } - - cJSON_AddItemToObject(pRoot, "Subplans", pLevels); - - size_t level = taosArrayGetSize(pDag->pSubplans); - for(size_t i = 0; i < level; i++) { - const SArray* pSubplans = (const SArray*)taosArrayGetP(pDag->pSubplans, i); - size_t num = taosArrayGetSize(pSubplans); - cJSON* plansOneLevel = cJSON_CreateArray(); - if(plansOneLevel == NULL) { - cJSON_Delete(pRoot); - return NULL; - } - - cJSON_AddItemToArray(pLevels, plansOneLevel); - for(size_t j = 0; j < num; j++) { - cJSON* pSubplan = subplanToJson((const SSubplan*)taosArrayGetP(pSubplans, j)); - if(pSubplan == NULL) { - cJSON_Delete(pRoot); - return NULL; - } - - cJSON_AddItemToArray(plansOneLevel, pSubplan); - } - } - return pRoot; -} - -char* qDagToString(const SQueryDag* pDag) { - cJSON* pRoot = qDagToJson(pDag); - return cJSON_Print(pRoot); -} - -SQueryDag* qJsonToDag(const cJSON* pRoot) { - SQueryDag* pDag = malloc(sizeof(SQueryDag)); - if(pDag == NULL) { - return NULL; - } - pDag->numOfSubplans = cJSON_GetNumberValue(cJSON_GetObjectItem(pRoot, "Number")); - pDag->queryId = cJSON_GetNumberValue(cJSON_GetObjectItem(pRoot, "QueryId")); - pDag->pSubplans = taosArrayInit(0, sizeof(SArray)); - if (pDag->pSubplans == NULL) { - free(pDag); - return NULL; - } - cJSON* pLevels = cJSON_GetObjectItem(pRoot, "Subplans"); - int level = cJSON_GetArraySize(pLevels); - for(int i = 0; i < level; i++) { - SArray* plansOneLevel = taosArrayInit(0, sizeof(void*)); - if(plansOneLevel == NULL) { - for(int j = 0; j < i; j++) { - taosArrayDestroy(taosArrayGetP(pDag->pSubplans, j)); - } - taosArrayDestroy(pDag->pSubplans); - free(pDag); - return NULL; - } - cJSON* pItem = cJSON_GetArrayItem(pLevels, i); - int sz = cJSON_GetArraySize(pItem); - for(int j = 0; j < sz; j++) { - cJSON* pSubplanJson = cJSON_GetArrayItem(pItem, j); - SSubplan* pSubplan = subplanFromJson(pSubplanJson); - taosArrayPush(plansOneLevel, &pSubplan); - } - taosArrayPush(pDag->pSubplans, plansOneLevel); - } - return pDag; -} - -SQueryDag* qStringToDag(const char* pStr) { - cJSON* pRoot = cJSON_Parse(pStr); - return qJsonToDag(pRoot); -} - -#endif diff --git a/source/libs/planner/src/planner.c b/source/libs/planner/src/planner.c index c2882928e0..d58f8bce15 100644 --- a/source/libs/planner/src/planner.c +++ b/source/libs/planner/src/planner.c @@ -15,8 +15,22 @@ #include "planner.h" -int32_t qCreateQueryPlan(SPlanContext* pCxt, SQueryPlan** pPlan) { +#include "plannerInt.h" +int32_t optimize(SPlanContext* pCxt, SLogicNode* pLogicNode) { + return TSDB_CODE_SUCCESS; +} + +int32_t qCreateQueryPlan(SPlanContext* pCxt, SQueryPlan** pPlan) { + SLogicNode* pLogicNode = NULL; + int32_t code = createLogicPlan(pCxt, &pLogicNode); + if (TSDB_CODE_SUCCESS == code) { + code = optimize(pCxt, pLogicNode); + } + if (TSDB_CODE_SUCCESS == code) { + code = buildPhysiPlan(pCxt, pLogicNode, pPlan); + } + return code; } void qSetSubplanExecutionNode(SSubplan* subplan, uint64_t templateId, SDownstreamSource* pSource) { diff --git a/source/libs/planner/src/plannerImpl.c b/source/libs/planner/src/plannerImpl.c deleted file mode 100644 index 8e2e898703..0000000000 --- a/source/libs/planner/src/plannerImpl.c +++ /dev/null @@ -1,868 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the GNU Affero General Public License, version 3 - * or later ("AGPL"), as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include "plannerImpl.h" - -#include "functionMgt.h" -#include "query.h" - -#define CHECK_ALLOC(p, res) \ - do { \ - if (NULL == (p)) { \ - pCxt->errCode = TSDB_CODE_OUT_OF_MEMORY; \ - return (res); \ - } \ - } while (0) - -#define CHECK_CODE(exec, res) \ - do { \ - int32_t code = (exec); \ - if (TSDB_CODE_SUCCESS != code) { \ - pCxt->errCode = code; \ - return (res); \ - } \ - } while (0) - -typedef struct SLogicPlanContext { - int32_t errCode; - int32_t planNodeId; -} SLogicPlanContext; - -static SLogicNode* createQueryLogicNode(SLogicPlanContext* pCxt, SNode* pStmt); -static SLogicNode* createLogicNodeByTable(SLogicPlanContext* pCxt, SSelectStmt* pSelect, SNode* pTable); - -typedef struct SRewriteExprCxt { - int32_t errCode; - SNodeList* pExprs; -} SRewriteExprCxt; - -static EDealRes doRewriteExpr(SNode** pNode, void* pContext) { - switch (nodeType(*pNode)) { - case QUERY_NODE_OPERATOR: - case QUERY_NODE_LOGIC_CONDITION: - case QUERY_NODE_FUNCTION: { - SRewriteExprCxt* pCxt = (SRewriteExprCxt*)pContext; - SNode* pExpr; - int32_t index = 0; - FOREACH(pExpr, pCxt->pExprs) { - if (QUERY_NODE_GROUPING_SET == nodeType(pExpr)) { - pExpr = nodesListGetNode(((SGroupingSetNode*)pExpr)->pParameterList, 0); - } - if (nodesEqualNode(pExpr, *pNode)) { - SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN); - CHECK_ALLOC(pCol, DEAL_RES_ERROR); - SExprNode* pToBeRewrittenExpr = (SExprNode*)(*pNode); - pCol->node.resType = pToBeRewrittenExpr->resType; - strcpy(pCol->node.aliasName, pToBeRewrittenExpr->aliasName); - strcpy(pCol->colName, ((SExprNode*)pExpr)->aliasName); - nodesDestroyNode(*pNode); - *pNode = (SNode*)pCol; - return DEAL_RES_IGNORE_CHILD; - } - ++index; - } - break; - } - default: - break; - } - - return DEAL_RES_CONTINUE; -} - -typedef struct SNameExprCxt { - int32_t planNodeId; - int32_t rewriteId; -} SNameExprCxt; - -static EDealRes doNameExpr(SNode* pNode, void* pContext) { - switch (nodeType(pNode)) { - case QUERY_NODE_OPERATOR: - case QUERY_NODE_LOGIC_CONDITION: - case QUERY_NODE_FUNCTION: { - SNameExprCxt* pCxt = (SNameExprCxt*)pContext; - sprintf(((SExprNode*)pNode)->aliasName, "#expr_%d_%d", pCxt->planNodeId, pCxt->rewriteId++); - return DEAL_RES_IGNORE_CHILD; - } - default: - break; - } - - return DEAL_RES_CONTINUE; -} - -static int32_t rewriteExpr(int32_t planNodeId, int32_t rewriteId, SNodeList* pExprs, SSelectStmt* pSelect, ESqlClause clause) { - SNameExprCxt nameCxt = { .planNodeId = planNodeId, .rewriteId = rewriteId }; - nodesWalkList(pExprs, doNameExpr, &nameCxt); - SRewriteExprCxt cxt = { .errCode = TSDB_CODE_SUCCESS, .pExprs = pExprs }; - nodesRewriteSelectStmt(pSelect, clause, doRewriteExpr, &cxt); - return cxt.errCode; -} - -static SLogicNode* pushLogicNode(SLogicPlanContext* pCxt, SLogicNode* pRoot, SLogicNode* pNode) { - if (TSDB_CODE_SUCCESS != pCxt->errCode) { - goto error; - } - - if (NULL == pRoot) { - return pNode; - } - - if (NULL == pNode) { - return pRoot; - } - - if (NULL == pNode->pChildren) { - pNode->pChildren = nodesMakeList(); - if (NULL == pNode->pChildren) { - goto error; - } - } - if (TSDB_CODE_SUCCESS != nodesListAppend(pNode->pChildren, (SNode*)pRoot)) { - goto error; - } - pRoot->pParent = pNode; - return pNode; -error: - nodesDestroyNode((SNode*)pNode); - return pRoot; -} - -static SLogicNode* createScanLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect, SRealTableNode* pRealTable) { - SScanLogicNode* pScan = (SScanLogicNode*)nodesMakeNode(QUERY_NODE_LOGIC_PLAN_SCAN); - CHECK_ALLOC(pScan, NULL); - pScan->node.id = pCxt->planNodeId++; - - pScan->pMeta = pRealTable->pMeta; - - // set columns to scan - SNodeList* pCols = NULL; - CHECK_CODE(nodesCollectColumns(pSelect, SQL_CLAUSE_FROM, pRealTable->table.tableAlias, &pCols), (SLogicNode*)pScan); - if (NULL != pCols) { - pScan->pScanCols = nodesCloneList(pCols); - CHECK_ALLOC(pScan->pScanCols, (SLogicNode*)pScan); - } - - // set output - if (NULL != pCols) { - pScan->node.pTargets = nodesCloneList(pCols); - CHECK_ALLOC(pScan->node.pTargets, (SLogicNode*)pScan); - } - - pScan->scanType = SCAN_TYPE_TABLE; - pScan->scanFlag = MAIN_SCAN; - pScan->scanRange = TSWINDOW_INITIALIZER; - - return (SLogicNode*)pScan; -} - -static SLogicNode* createSubqueryLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect, STempTableNode* pTable) { - SLogicNode* pRoot = createQueryLogicNode(pCxt, pTable->pSubquery); - CHECK_ALLOC(pRoot, NULL); - SNode* pNode; - FOREACH(pNode, pRoot->pTargets) { - strcpy(((SColumnNode*)pNode)->tableAlias, pTable->table.tableAlias); - } - return pRoot; -} - -static SLogicNode* createJoinLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect, SJoinTableNode* pJoinTable) { - SJoinLogicNode* pJoin = (SJoinLogicNode*)nodesMakeNode(QUERY_NODE_LOGIC_PLAN_JOIN); - CHECK_ALLOC(pJoin, NULL); - pJoin->node.id = pCxt->planNodeId++; - - pJoin->joinType = pJoinTable->joinType; - - // set left and right node - pJoin->node.pChildren = nodesMakeList(); - CHECK_ALLOC(pJoin->node.pChildren, (SLogicNode*)pJoin); - SLogicNode* pLeft = createLogicNodeByTable(pCxt, pSelect, pJoinTable->pLeft); - CHECK_ALLOC(pLeft, (SLogicNode*)pJoin); - CHECK_CODE(nodesListAppend(pJoin->node.pChildren, (SNode*)pLeft), (SLogicNode*)pJoin); - SLogicNode* pRight = createLogicNodeByTable(pCxt, pSelect, pJoinTable->pRight); - CHECK_ALLOC(pRight, (SLogicNode*)pJoin); - CHECK_CODE(nodesListAppend(pJoin->node.pChildren, (SNode*)pRight), (SLogicNode*)pJoin); - - // set on conditions - if (NULL != pJoinTable->pOnCond) { - pJoin->pOnConditions = nodesCloneNode(pJoinTable->pOnCond); - CHECK_ALLOC(pJoin->pOnConditions, (SLogicNode*)pJoin); - } - - // set the output - pJoin->node.pTargets = nodesCloneList(pLeft->pTargets); - CHECK_ALLOC(pJoin->node.pTargets, (SLogicNode*)pJoin); - SNodeList* pTargets = nodesCloneList(pRight->pTargets); - CHECK_ALLOC(pTargets, (SLogicNode*)pJoin); - nodesListAppendList(pJoin->node.pTargets, pTargets); - - return (SLogicNode*)pJoin; -} - -static SLogicNode* createLogicNodeByTable(SLogicPlanContext* pCxt, SSelectStmt* pSelect, SNode* pTable) { - switch (nodeType(pTable)) { - case QUERY_NODE_REAL_TABLE: - return createScanLogicNode(pCxt, pSelect, (SRealTableNode*)pTable); - case QUERY_NODE_TEMP_TABLE: - return createSubqueryLogicNode(pCxt, pSelect, (STempTableNode*)pTable); - case QUERY_NODE_JOIN_TABLE: - return createJoinLogicNode(pCxt, pSelect, (SJoinTableNode*)pTable); - default: - break; - } - return NULL; -} - -typedef struct SCreateColumnCxt { - int32_t errCode; - SNodeList* pList; -} SCreateColumnCxt; - -static EDealRes doCreateColumn(SNode* pNode, void* pContext) { - SCreateColumnCxt* pCxt = (SCreateColumnCxt*)pContext; - switch (nodeType(pNode)) { - case QUERY_NODE_COLUMN: { - SNode* pCol = nodesCloneNode(pNode); - CHECK_ALLOC(pCol, DEAL_RES_ERROR); - CHECK_CODE(nodesListAppend(pCxt->pList, pCol), DEAL_RES_ERROR); - return DEAL_RES_IGNORE_CHILD; - } - case QUERY_NODE_OPERATOR: - case QUERY_NODE_LOGIC_CONDITION: - case QUERY_NODE_FUNCTION: { - SExprNode* pExpr = (SExprNode*)pNode; - SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN); - CHECK_ALLOC(pCol, DEAL_RES_ERROR); - pCol->node.resType = pExpr->resType; - strcpy(pCol->colName, pExpr->aliasName); - CHECK_CODE(nodesListAppend(pCxt->pList, (SNode*)pCol), DEAL_RES_ERROR); - return DEAL_RES_IGNORE_CHILD; - } - default: - break; - } - - return DEAL_RES_CONTINUE; -} - -static SNodeList* createColumnByRewriteExps(SLogicPlanContext* pCxt, SNodeList* pExprs) { - SCreateColumnCxt cxt = { .errCode = TSDB_CODE_SUCCESS, .pList = nodesMakeList() }; - CHECK_ALLOC(cxt.pList, NULL); - - nodesWalkList(pExprs, doCreateColumn, &cxt); - if (TSDB_CODE_SUCCESS != cxt.errCode) { - nodesDestroyList(cxt.pList); - return NULL; - } - return cxt.pList; -} - -static SLogicNode* createAggLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect) { - SNodeList* pAggFuncs = NULL; - CHECK_CODE(nodesCollectFuncs(pSelect, fmIsAggFunc, &pAggFuncs), NULL); - if (NULL == pAggFuncs && NULL == pSelect->pGroupByList) { - return NULL; - } - - SAggLogicNode* pAgg = (SAggLogicNode*)nodesMakeNode(QUERY_NODE_LOGIC_PLAN_AGG); - CHECK_ALLOC(pAgg, NULL); - pAgg->node.id = pCxt->planNodeId++; - - // set grouyp keys, agg funcs and having conditions - if (NULL != pSelect->pGroupByList) { - pAgg->pGroupKeys = nodesCloneList(pSelect->pGroupByList); - CHECK_ALLOC(pAgg->pGroupKeys, (SLogicNode*)pAgg); - } - if (NULL != pAggFuncs) { - pAgg->pAggFuncs = nodesCloneList(pAggFuncs); - CHECK_ALLOC(pAgg->pAggFuncs, (SLogicNode*)pAgg); - } - - // rewrite the expression in subsequent clauses - CHECK_CODE(rewriteExpr(pAgg->node.id, 1, pAgg->pGroupKeys, pSelect, SQL_CLAUSE_GROUP_BY), (SLogicNode*)pAgg); - CHECK_CODE(rewriteExpr(pAgg->node.id, 1 + LIST_LENGTH(pAgg->pGroupKeys), pAgg->pAggFuncs, pSelect, SQL_CLAUSE_GROUP_BY), (SLogicNode*)pAgg); - - if (NULL != pSelect->pHaving) { - pAgg->node.pConditions = nodesCloneNode(pSelect->pHaving); - CHECK_ALLOC(pAgg->node.pConditions, (SLogicNode*)pAgg); - } - - // set the output - pAgg->node.pTargets = nodesMakeList(); - CHECK_ALLOC(pAgg->node.pTargets, (SLogicNode*)pAgg); - if (NULL != pAgg->pGroupKeys) { - SNodeList* pTargets = createColumnByRewriteExps(pCxt, pAgg->pGroupKeys); - CHECK_ALLOC(pAgg->node.pTargets, (SLogicNode*)pAgg); - nodesListAppendList(pAgg->node.pTargets, pTargets); - } - if (NULL != pAgg->pAggFuncs) { - SNodeList* pTargets = createColumnByRewriteExps(pCxt, pAgg->pAggFuncs); - CHECK_ALLOC(pTargets, (SLogicNode*)pAgg); - nodesListAppendList(pAgg->node.pTargets, pTargets); - } - - return (SLogicNode*)pAgg; -} - -static SNodeList* createColumnByProjections(SLogicPlanContext* pCxt, SNodeList* pExprs) { - SNodeList* pList = nodesMakeList(); - CHECK_ALLOC(pList, NULL); - SNode* pNode; - FOREACH(pNode, pExprs) { - SExprNode* pExpr = (SExprNode*)pNode; - SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN); - if (NULL == pCol) { - goto error; - } - pCol->node.resType = pExpr->resType; - strcpy(pCol->colName, pExpr->aliasName); - if (TSDB_CODE_SUCCESS != nodesListAppend(pList, (SNode*)pCol)) { - goto error; - } - } - return pList; -error: - nodesDestroyList(pList); - return NULL; -} - -static SLogicNode* createProjectLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect) { - SProjectLogicNode* pProject = (SProjectLogicNode*)nodesMakeNode(QUERY_NODE_LOGIC_PLAN_PROJECT); - CHECK_ALLOC(pProject, NULL); - pProject->node.id = pCxt->planNodeId++; - - pProject->pProjections = nodesCloneList(pSelect->pProjectionList); - - pProject->node.pTargets = createColumnByProjections(pCxt,pSelect->pProjectionList); - CHECK_ALLOC(pProject->node.pTargets, (SLogicNode*)pProject); - - return (SLogicNode*)pProject; -} - -static SLogicNode* createSelectLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect) { - SLogicNode* pRoot = createLogicNodeByTable(pCxt, pSelect, pSelect->pFromTable); - if (TSDB_CODE_SUCCESS == pCxt->errCode && NULL != pSelect->pWhere) { - pRoot->pConditions = nodesCloneNode(pSelect->pWhere); - CHECK_ALLOC(pRoot->pConditions, pRoot); - } - if (TSDB_CODE_SUCCESS == pCxt->errCode) { - pRoot = pushLogicNode(pCxt, pRoot, createAggLogicNode(pCxt, pSelect)); - } - if (TSDB_CODE_SUCCESS == pCxt->errCode) { - pRoot = pushLogicNode(pCxt, pRoot, createProjectLogicNode(pCxt, pSelect)); - } - return pRoot; -} - -static SLogicNode* createQueryLogicNode(SLogicPlanContext* pCxt, SNode* pStmt) { - switch (nodeType(pStmt)) { - case QUERY_NODE_SELECT_STMT: - return createSelectLogicNode(pCxt, (SSelectStmt*)pStmt); - default: - break; - } -} - -int32_t createLogicPlan(SNode* pNode, SLogicNode** pLogicNode) { - SLogicPlanContext cxt = { .errCode = TSDB_CODE_SUCCESS, .planNodeId = 1 }; - SLogicNode* pRoot = createQueryLogicNode(&cxt, pNode); - if (TSDB_CODE_SUCCESS != cxt.errCode) { - nodesDestroyNode((SNode*)pRoot); - return cxt.errCode; - } - *pLogicNode = pRoot; - return TSDB_CODE_SUCCESS; -} - -int32_t optimize(SLogicNode* pLogicNode) { - // todo - return TSDB_CODE_SUCCESS; -} - -typedef struct SSubLogicPlan { - SNode* pRoot; // SLogicNode - bool haveSuperTable; - bool haveSystemTable; -} SSubLogicPlan; - -int32_t splitLogicPlan(SSubLogicPlan* pLogicPlan) { - // todo - return TSDB_CODE_SUCCESS; -} - -typedef struct SSlotIndex { - int16_t dataBlockId; - int16_t slotId; -} SSlotIndex; - -typedef struct SPhysiPlanContext { - int32_t errCode; - int16_t nextDataBlockId; - SArray* pLocationHelper; -} SPhysiPlanContext; - -static int32_t getSlotKey(SNode* pNode, char* pKey) { - if (QUERY_NODE_COLUMN == nodeType(pNode)) { - SColumnNode* pCol = (SColumnNode*)pNode; - if ('\0' == pCol->tableAlias[0]) { - return sprintf(pKey, "%s", pCol->colName); - } - return sprintf(pKey, "%s.%s", pCol->tableAlias, pCol->colName); - } - return sprintf(pKey, "%s", ((SExprNode*)pNode)->aliasName); -} - -static SNode* createSlotDesc(SPhysiPlanContext* pCxt, const SNode* pNode, int16_t slotId) { - SSlotDescNode* pSlot = (SSlotDescNode*)nodesMakeNode(QUERY_NODE_SLOT_DESC); - CHECK_ALLOC(pSlot, NULL); - pSlot->slotId = slotId; - pSlot->dataType = ((SExprNode*)pNode)->resType; - pSlot->reserve = false; - pSlot->output = false; - return (SNode*)pSlot; -} - -static SNode* createTarget(SNode* pNode, int16_t dataBlockId, int16_t slotId) { - STargetNode* pTarget = (STargetNode*)nodesMakeNode(QUERY_NODE_TARGET); - if (NULL == pTarget) { - return NULL; - } - pTarget->dataBlockId = dataBlockId; - pTarget->slotId = slotId; - pTarget->pExpr = pNode; - return (SNode*)pTarget; -} - -static int32_t addDataBlockDesc(SPhysiPlanContext* pCxt, SNodeList* pList, SDataBlockDescNode* pDataBlockDesc) { - SHashObj* pHash = NULL; - if (NULL == pDataBlockDesc->pSlots) { - pDataBlockDesc->pSlots = nodesMakeList(); - CHECK_ALLOC(pDataBlockDesc->pSlots, TSDB_CODE_OUT_OF_MEMORY); - - pHash = taosHashInit(LIST_LENGTH(pList), taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK); - CHECK_ALLOC(pHash, TSDB_CODE_OUT_OF_MEMORY); - if (NULL == taosArrayInsert(pCxt->pLocationHelper, pDataBlockDesc->dataBlockId, &pHash)) { - taosHashCleanup(pHash); - return TSDB_CODE_OUT_OF_MEMORY; - } - } else { - pHash = taosArrayGetP(pCxt->pLocationHelper, pDataBlockDesc->dataBlockId); - } - - SNode* pNode = NULL; - int16_t slotId = taosHashGetSize(pHash); - FOREACH(pNode, pList) { - SNode* pSlot = createSlotDesc(pCxt, pNode, slotId); - CHECK_ALLOC(pSlot, TSDB_CODE_OUT_OF_MEMORY); - if (TSDB_CODE_SUCCESS != nodesListAppend(pDataBlockDesc->pSlots, (SNode*)pSlot)) { - nodesDestroyNode(pSlot); - return TSDB_CODE_OUT_OF_MEMORY; - } - - SSlotIndex index = { .dataBlockId = pDataBlockDesc->dataBlockId, .slotId = slotId }; - char name[TSDB_TABLE_NAME_LEN + TSDB_COL_NAME_LEN]; - int32_t len = getSlotKey(pNode, name); - CHECK_CODE(taosHashPut(pHash, name, len, &index, sizeof(SSlotIndex)), TSDB_CODE_OUT_OF_MEMORY); - - SNode* pTarget = createTarget(pNode, pDataBlockDesc->dataBlockId, slotId); - CHECK_ALLOC(pTarget, TSDB_CODE_OUT_OF_MEMORY); - REPLACE_NODE(pTarget); - - ++slotId; - } - return TSDB_CODE_SUCCESS; -} - -typedef struct SSetSlotIdCxt { - int32_t errCode; - SHashObj* pLeftHash; - SHashObj* pRightHash; -} SSetSlotIdCxt; - -static EDealRes doSetSlotId(SNode* pNode, void* pContext) { - if (QUERY_NODE_COLUMN == nodeType(pNode) && 0 != strcmp(((SColumnNode*)pNode)->colName, "*")) { - SSetSlotIdCxt* pCxt = (SSetSlotIdCxt*)pContext; - char name[TSDB_TABLE_NAME_LEN + TSDB_COL_NAME_LEN]; - int32_t len = getSlotKey(pNode, name); - SSlotIndex* pIndex = taosHashGet(pCxt->pLeftHash, name, len); - if (NULL == pIndex) { - pIndex = taosHashGet(pCxt->pRightHash, name, len); - } - // pIndex is definitely not NULL, otherwise it is a bug - ((SColumnNode*)pNode)->dataBlockId = pIndex->dataBlockId; - ((SColumnNode*)pNode)->slotId = pIndex->slotId; - CHECK_ALLOC(pNode, DEAL_RES_ERROR); - return DEAL_RES_IGNORE_CHILD; - } - return DEAL_RES_CONTINUE; -} - -static SNode* setNodeSlotId(SPhysiPlanContext* pCxt, int16_t leftDataBlockId, int16_t rightDataBlockId, SNode* pNode) { - SNode* pRes = nodesCloneNode(pNode); - CHECK_ALLOC(pRes, NULL); - SSetSlotIdCxt cxt = { .errCode = TSDB_CODE_SUCCESS, .pLeftHash = taosArrayGetP(pCxt->pLocationHelper, leftDataBlockId), - .pRightHash = (rightDataBlockId < 0 ? NULL : taosArrayGetP(pCxt->pLocationHelper, rightDataBlockId)) }; - nodesWalkNode(pRes, doSetSlotId, &cxt); - if (TSDB_CODE_SUCCESS != cxt.errCode) { - nodesDestroyNode(pRes); - return NULL; - } - return pRes; -} - -static SNodeList* setListSlotId(SPhysiPlanContext* pCxt, int16_t leftDataBlockId, int16_t rightDataBlockId, SNodeList* pList) { - SNodeList* pRes = nodesCloneList(pList); - CHECK_ALLOC(pRes, NULL); - SSetSlotIdCxt cxt = { .errCode = TSDB_CODE_SUCCESS, .pLeftHash = taosArrayGetP(pCxt->pLocationHelper, leftDataBlockId), - .pRightHash = (rightDataBlockId < 0 ? NULL : taosArrayGetP(pCxt->pLocationHelper, rightDataBlockId)) }; - nodesWalkList(pRes, doSetSlotId, &cxt); - if (TSDB_CODE_SUCCESS != cxt.errCode) { - nodesDestroyList(pRes); - return NULL; - } - return pRes; -} - -static SPhysiNode* makePhysiNode(SPhysiPlanContext* pCxt, ENodeType type) { - SPhysiNode* pPhysiNode = (SPhysiNode*)nodesMakeNode(type); - if (NULL == pPhysiNode) { - return NULL; - } - pPhysiNode->outputDataBlockDesc.dataBlockId = pCxt->nextDataBlockId++; - pPhysiNode->outputDataBlockDesc.type = QUERY_NODE_DATABLOCK_DESC; - return pPhysiNode; -} - -static int32_t setConditionsSlotId(SPhysiPlanContext* pCxt, const SLogicNode* pLogicNode, SPhysiNode* pPhysiNode) { - if (NULL != pLogicNode->pConditions) { - pPhysiNode->pConditions = setNodeSlotId(pCxt, pPhysiNode->outputDataBlockDesc.dataBlockId, -1, pLogicNode->pConditions); - CHECK_ALLOC(pPhysiNode->pConditions, TSDB_CODE_OUT_OF_MEMORY); - } - return TSDB_CODE_SUCCESS; -} - -static int32_t setSlotOutput(SPhysiPlanContext* pCxt, SNodeList* pTargets, SDataBlockDescNode* pDataBlockDesc) { - SHashObj* pHash = taosArrayGetP(pCxt->pLocationHelper, pDataBlockDesc->dataBlockId); - char name[TSDB_TABLE_NAME_LEN + TSDB_COL_NAME_LEN]; - SNode* pNode; - FOREACH(pNode, pTargets) { - int32_t len = getSlotKey(pNode, name); - SSlotIndex* pIndex = taosHashGet(pHash, name, len); - ((SSlotDescNode*)nodesListGetNode(pDataBlockDesc->pSlots, pIndex->slotId))->output = true; - } - - return TSDB_CODE_SUCCESS; -} - -static int32_t initScanPhysiNode(SPhysiPlanContext* pCxt, SScanLogicNode* pScanLogicNode, SScanPhysiNode* pScanPhysiNode) { - if (NULL != pScanLogicNode->pScanCols) { - pScanPhysiNode->pScanCols = nodesCloneList(pScanLogicNode->pScanCols); - CHECK_ALLOC(pScanPhysiNode->pScanCols, TSDB_CODE_OUT_OF_MEMORY); - } - // Data block describe also needs to be set without scanning column, such as SELECT COUNT(*) FROM t - CHECK_CODE(addDataBlockDesc(pCxt, pScanPhysiNode->pScanCols, &pScanPhysiNode->node.outputDataBlockDesc), TSDB_CODE_OUT_OF_MEMORY); - - CHECK_CODE(setConditionsSlotId(pCxt, (const SLogicNode*)pScanLogicNode, (SPhysiNode*)pScanPhysiNode), TSDB_CODE_OUT_OF_MEMORY); - - CHECK_CODE(setSlotOutput(pCxt, pScanLogicNode->node.pTargets, &pScanPhysiNode->node.outputDataBlockDesc), TSDB_CODE_OUT_OF_MEMORY); - - pScanPhysiNode->uid = pScanLogicNode->pMeta->uid; - pScanPhysiNode->tableType = pScanLogicNode->pMeta->tableType; - pScanPhysiNode->order = TSDB_ORDER_ASC; - pScanPhysiNode->count = 1; - pScanPhysiNode->reverse = 0; - - return TSDB_CODE_SUCCESS; -} - -static SPhysiNode* createTagScanPhysiNode(SPhysiPlanContext* pCxt, SScanLogicNode* pScanLogicNode) { - STagScanPhysiNode* pTagScan = (STagScanPhysiNode*)makePhysiNode(pCxt, QUERY_NODE_PHYSICAL_PLAN_TAG_SCAN); - CHECK_ALLOC(pTagScan, NULL); - CHECK_CODE(initScanPhysiNode(pCxt, pScanLogicNode, (SScanPhysiNode*)pTagScan), (SPhysiNode*)pTagScan); - return (SPhysiNode*)pTagScan; -} - -static SPhysiNode* createTableScanPhysiNode(SPhysiPlanContext* pCxt, SScanLogicNode* pScanLogicNode) { - STableScanPhysiNode* pTableScan = (STableScanPhysiNode*)makePhysiNode(pCxt, QUERY_NODE_PHYSICAL_PLAN_TABLE_SCAN); - CHECK_ALLOC(pTableScan, NULL); - CHECK_CODE(initScanPhysiNode(pCxt, pScanLogicNode, (SScanPhysiNode*)pTableScan), (SPhysiNode*)pTableScan); - pTableScan->scanFlag = pScanLogicNode->scanFlag; - pTableScan->scanRange = pScanLogicNode->scanRange; - return (SPhysiNode*)pTableScan; -} - -static SPhysiNode* createScanPhysiNode(SPhysiPlanContext* pCxt, SScanLogicNode* pScanLogicNode) { - switch (pScanLogicNode->scanType) { - case SCAN_TYPE_TAG: - return createTagScanPhysiNode(pCxt, pScanLogicNode); - case SCAN_TYPE_TABLE: - return createTableScanPhysiNode(pCxt, pScanLogicNode); - case SCAN_TYPE_STABLE: - case SCAN_TYPE_STREAM: - break; - default: - break; - } - return NULL; -} - -static SNodeList* createJoinOutputCols(SPhysiPlanContext* pCxt, SDataBlockDescNode* pLeftDesc, SDataBlockDescNode* pRightDesc) { - SNodeList* pCols = nodesMakeList(); - CHECK_ALLOC(pCols, NULL); - SNode* pNode; - FOREACH(pNode, pLeftDesc->pSlots) { - SSlotDescNode* pSlot = (SSlotDescNode*)pNode; - SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN); - if (NULL == pCol) { - goto error; - } - pCol->node.resType = pSlot->dataType; - pCol->dataBlockId = pLeftDesc->dataBlockId; - pCol->slotId = pSlot->slotId; - pCol->colId = -1; - if (TSDB_CODE_SUCCESS != nodesListAppend(pCols, (SNode*)pCol)) { - goto error; - } - } - FOREACH(pNode, pRightDesc->pSlots) { - SSlotDescNode* pSlot = (SSlotDescNode*)pNode; - SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN); - if (NULL == pCol) { - goto error; - } - pCol->node.resType = pSlot->dataType; - pCol->dataBlockId = pRightDesc->dataBlockId; - pCol->slotId = pSlot->slotId; - pCol->colId = -1; - if (TSDB_CODE_SUCCESS != nodesListAppend(pCols, (SNode*)pCol)) { - goto error; - } - } - return pCols; -error: - nodesDestroyList(pCols); - return NULL; -} - -static SPhysiNode* createJoinPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, SJoinLogicNode* pJoinLogicNode) { - SJoinPhysiNode* pJoin = (SJoinPhysiNode*)makePhysiNode(pCxt, QUERY_NODE_PHYSICAL_PLAN_JOIN); - CHECK_ALLOC(pJoin, NULL); - - SDataBlockDescNode* pLeftDesc = &((SPhysiNode*)nodesListGetNode(pChildren, 0))->outputDataBlockDesc; - SDataBlockDescNode* pRightDesc = &((SPhysiNode*)nodesListGetNode(pChildren, 1))->outputDataBlockDesc; - pJoin->pOnConditions = setNodeSlotId(pCxt, pLeftDesc->dataBlockId, pRightDesc->dataBlockId, pJoinLogicNode->pOnConditions); - CHECK_ALLOC(pJoin->pOnConditions, (SPhysiNode*)pJoin); - - pJoin->pTargets = createJoinOutputCols(pCxt, pLeftDesc, pRightDesc); - CHECK_ALLOC(pJoin->pTargets, (SPhysiNode*)pJoin); - CHECK_CODE(addDataBlockDesc(pCxt, pJoin->pTargets, &pJoin->node.outputDataBlockDesc), (SPhysiNode*)pJoin); - - CHECK_CODE(setConditionsSlotId(pCxt, (const SLogicNode*)pJoinLogicNode, (SPhysiNode*)pJoin), (SPhysiNode*)pJoin); - - CHECK_CODE(setSlotOutput(pCxt, pJoinLogicNode->node.pTargets, &pJoin->node.outputDataBlockDesc), (SPhysiNode*)pJoin); - - return (SPhysiNode*)pJoin; -} - -typedef struct SRewritePrecalcExprsCxt { - int32_t errCode; - int32_t planNodeId; - int32_t rewriteId; - SNodeList* pPrecalcExprs; -} SRewritePrecalcExprsCxt; - -static EDealRes collectAndRewrite(SRewritePrecalcExprsCxt* pCxt, SNode** pNode) { - SNode* pExpr = nodesCloneNode(*pNode); - CHECK_ALLOC(pExpr, DEAL_RES_ERROR); - if (nodesListAppend(pCxt->pPrecalcExprs, pExpr)) { - nodesDestroyNode(pExpr); - return DEAL_RES_ERROR; - } - SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN); - if (NULL == pCol) { - nodesDestroyNode(pExpr); - return DEAL_RES_ERROR; - } - SExprNode* pRewrittenExpr = (SExprNode*)pExpr; - pCol->node.resType = pRewrittenExpr->resType; - if ('\0' != pRewrittenExpr->aliasName[0]) { - strcpy(pCol->colName, pRewrittenExpr->aliasName); - } else { - snprintf(pRewrittenExpr->aliasName, sizeof(pRewrittenExpr->aliasName), "#expr_%d_%d", pCxt->planNodeId, pCxt->rewriteId); - strcpy(pCol->colName, pRewrittenExpr->aliasName); - } - nodesDestroyNode(*pNode); - *pNode = (SNode*)pCol; - return DEAL_RES_IGNORE_CHILD; -} - -static EDealRes doRewritePrecalcExprs(SNode** pNode, void* pContext) { - SRewritePrecalcExprsCxt* pCxt = (SRewritePrecalcExprsCxt*)pContext; - switch (nodeType(*pNode)) { - case QUERY_NODE_OPERATOR: - case QUERY_NODE_LOGIC_CONDITION: { - return collectAndRewrite(pContext, pNode); - } - case QUERY_NODE_FUNCTION: { - if (!fmIsAggFunc(((SFunctionNode*)(*pNode))->funcId)) { - return collectAndRewrite(pContext, pNode); - } - } - default: - break; - } - return DEAL_RES_CONTINUE; -} - -static int32_t rewritePrecalcExprs(SPhysiPlanContext* pCxt, SNodeList* pList, SNodeList** pPrecalcExprs, SNodeList** pRewrittenList) { - if (NULL == pList) { - return TSDB_CODE_SUCCESS; - } - - if (NULL == *pPrecalcExprs) { - *pPrecalcExprs = nodesMakeList(); - CHECK_ALLOC(*pPrecalcExprs, TSDB_CODE_OUT_OF_MEMORY); - } - if (NULL == *pRewrittenList) { - *pRewrittenList = nodesMakeList(); - CHECK_ALLOC(*pRewrittenList, TSDB_CODE_OUT_OF_MEMORY); - } - SNode* pNode = NULL; - FOREACH(pNode, pList) { - SNode* pNew = NULL; - if (QUERY_NODE_GROUPING_SET == nodeType(pNode)) { - pNew = nodesCloneNode(nodesListGetNode(((SGroupingSetNode*)pNode)->pParameterList, 0)); - } else { - pNew = nodesCloneNode(pNode); - } - CHECK_ALLOC(pNew, TSDB_CODE_OUT_OF_MEMORY); - CHECK_CODE(nodesListAppend(*pRewrittenList, pNew), TSDB_CODE_OUT_OF_MEMORY); - } - SRewritePrecalcExprsCxt cxt = { .errCode = TSDB_CODE_SUCCESS, .pPrecalcExprs = *pPrecalcExprs }; - nodesRewriteList(*pRewrittenList, doRewritePrecalcExprs, &cxt); - if (0 == LIST_LENGTH(cxt.pPrecalcExprs)) { - nodesDestroyList(cxt.pPrecalcExprs); - *pPrecalcExprs = NULL; - } - return cxt.errCode; -} - -static SPhysiNode* createAggPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, SAggLogicNode* pAggLogicNode) { - SAggPhysiNode* pAgg = (SAggPhysiNode*)makePhysiNode(pCxt, QUERY_NODE_PHYSICAL_PLAN_AGG); - CHECK_ALLOC(pAgg, NULL); - - SNodeList* pPrecalcExprs = NULL; - SNodeList* pGroupKeys = NULL; - SNodeList* pAggFuncs = NULL; - CHECK_CODE(rewritePrecalcExprs(pCxt, pAggLogicNode->pGroupKeys, &pPrecalcExprs, &pGroupKeys), (SPhysiNode*)pAgg); - CHECK_CODE(rewritePrecalcExprs(pCxt, pAggLogicNode->pAggFuncs, &pPrecalcExprs, &pAggFuncs), (SPhysiNode*)pAgg); - - SDataBlockDescNode* pChildTupe = &(((SPhysiNode*)nodesListGetNode(pChildren, 0))->outputDataBlockDesc); - // push down expression to outputDataBlockDesc of child node - if (NULL != pPrecalcExprs) { - pAgg->pExprs = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pPrecalcExprs); - CHECK_ALLOC(pAgg->pExprs, (SPhysiNode*)pAgg); - CHECK_CODE(addDataBlockDesc(pCxt, pAgg->pExprs, pChildTupe), (SPhysiNode*)pAgg); - } - - if (NULL != pGroupKeys) { - pAgg->pGroupKeys = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pGroupKeys); - CHECK_ALLOC(pAgg->pGroupKeys, (SPhysiNode*)pAgg); - CHECK_CODE(addDataBlockDesc(pCxt, pAgg->pGroupKeys, &pAgg->node.outputDataBlockDesc), (SPhysiNode*)pAgg); - } - - if (NULL != pAggFuncs) { - pAgg->pAggFuncs = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pAggFuncs); - CHECK_ALLOC(pAgg->pAggFuncs, (SPhysiNode*)pAgg); - CHECK_CODE(addDataBlockDesc(pCxt, pAgg->pAggFuncs, &pAgg->node.outputDataBlockDesc), (SPhysiNode*)pAgg); - } - - CHECK_CODE(setConditionsSlotId(pCxt, (const SLogicNode*)pAggLogicNode, (SPhysiNode*)pAgg), (SPhysiNode*)pAgg); - - CHECK_CODE(setSlotOutput(pCxt, pAggLogicNode->node.pTargets, &pAgg->node.outputDataBlockDesc), (SPhysiNode*)pAgg); - - return (SPhysiNode*)pAgg; -} - -static SPhysiNode* createProjectPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, SProjectLogicNode* pProjectLogicNode) { - SProjectPhysiNode* pProject = (SProjectPhysiNode*)makePhysiNode(pCxt, QUERY_NODE_PHYSICAL_PLAN_PROJECT); - CHECK_ALLOC(pProject, NULL); - - pProject->pProjections = setListSlotId(pCxt, ((SPhysiNode*)nodesListGetNode(pChildren, 0))->outputDataBlockDesc.dataBlockId, -1, pProjectLogicNode->pProjections); - CHECK_ALLOC(pProject->pProjections, (SPhysiNode*)pProject); - CHECK_CODE(addDataBlockDesc(pCxt, pProject->pProjections, &pProject->node.outputDataBlockDesc), (SPhysiNode*)pProject); - - CHECK_CODE(setConditionsSlotId(pCxt, (const SLogicNode*)pProjectLogicNode, (SPhysiNode*)pProject), (SPhysiNode*)pProject); - - return (SPhysiNode*)pProject; -} - -static SPhysiNode* createPhysiNode(SPhysiPlanContext* pCxt, SLogicNode* pLogicPlan) { - SNodeList* pChildren = nodesMakeList(); - CHECK_ALLOC(pChildren, NULL); - - SNode* pLogicChild; - FOREACH(pLogicChild, pLogicPlan->pChildren) { - SNode* pChildPhyNode = (SNode*)createPhysiNode(pCxt, (SLogicNode*)pLogicChild); - if (TSDB_CODE_SUCCESS != nodesListAppend(pChildren, pChildPhyNode)) { - pCxt->errCode = TSDB_CODE_OUT_OF_MEMORY; - nodesDestroyList(pChildren); - return NULL; - } - } - - SPhysiNode* pPhyNode = NULL; - switch (nodeType(pLogicPlan)) { - case QUERY_NODE_LOGIC_PLAN_SCAN: - pPhyNode = createScanPhysiNode(pCxt, (SScanLogicNode*)pLogicPlan); - break; - case QUERY_NODE_LOGIC_PLAN_JOIN: - pPhyNode = createJoinPhysiNode(pCxt, pChildren, (SJoinLogicNode*)pLogicPlan); - break; - case QUERY_NODE_LOGIC_PLAN_AGG: - pPhyNode = createAggPhysiNode(pCxt, pChildren, (SAggLogicNode*)pLogicPlan); - break; - case QUERY_NODE_LOGIC_PLAN_PROJECT: - pPhyNode = createProjectPhysiNode(pCxt, pChildren, (SProjectLogicNode*)pLogicPlan); - break; - default: - break; - } - - pPhyNode->pChildren = pChildren; - SNode* pChild; - FOREACH(pChild, pPhyNode->pChildren) { - ((SPhysiNode*)pChild)->pParent = pPhyNode; - } - - return pPhyNode; -} - -int32_t createPhysiPlan(SLogicNode* pLogicNode, SPhysiNode** pPhyNode) { - SPhysiPlanContext cxt = { .errCode = TSDB_CODE_SUCCESS, .nextDataBlockId = 0, .pLocationHelper = taosArrayInit(32, POINTER_BYTES) }; - if (NULL == cxt.pLocationHelper) { - return TSDB_CODE_OUT_OF_MEMORY; - } - *pPhyNode = createPhysiNode(&cxt, pLogicNode); - return cxt.errCode; -} - -int32_t buildPhysiPlan(SLogicNode* pLogicNode, SPhysiNode** pPhyNode) { - // split - // scale out - // maping - // create - return TSDB_CODE_SUCCESS; -} diff --git a/source/libs/planner/test/phyPlanTests.cpp b/source/libs/planner/test/phyPlanTests.cpp deleted file mode 100644 index b70b021057..0000000000 --- a/source/libs/planner/test/phyPlanTests.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the GNU Affero General Public License, version 3 - * or later ("AGPL"), as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -#if 0 -#include - -#include "plannerInt.h" -#include "mockCatalogService.h" - -using namespace std; -using namespace testing; - -void* myCalloc(size_t nmemb, size_t size) { - if (void* p = calloc(nmemb, size)) { - return p; - } - throw bad_alloc(); -} - -class PhyPlanTest : public Test { -protected: - void pushAgg(int32_t aggOp) { - unique_ptr agg((SQueryPlanNode*)myCalloc(1, sizeof(SQueryPlanNode))); - agg->info.type = aggOp; - agg->pExpr = taosArrayInit(TARRAY_MIN_SIZE, POINTER_BYTES); - unique_ptr expr((SExprInfo*)myCalloc(1, sizeof(SExprInfo))); - expr->base.resSchema.type = TSDB_DATA_TYPE_INT; - expr->base.resSchema.bytes = tDataTypes[TSDB_DATA_TYPE_INT].bytes; - expr->pExpr = (tExprNode*)myCalloc(1, sizeof(tExprNode)); - expr->pExpr->nodeType = TEXPR_FUNCTION_NODE; - strcpy(expr->pExpr->_function.functionName, "Count"); - SExprInfo* item = expr.release(); - taosArrayPush(agg->pExpr, &item); - pushNode(agg.release()); - } - - void pushScan(const string& db, const string& table, int32_t scanOp) { - shared_ptr meta = mockCatalogService->getTableMeta(db, table); - EXPECT_TRUE(meta); - unique_ptr scan((SQueryPlanNode*)myCalloc(1, sizeof(SQueryPlanNode))); - scan->info.type = scanOp; - scan->numOfCols = meta->schema->tableInfo.numOfColumns; - scan->pSchema = (SSchema*)myCalloc(1, sizeof(SSchema) * scan->numOfCols); - memcpy(scan->pSchema, meta->schema->schema, sizeof(SSchema) * scan->numOfCols); - //todo 'pExpr' 'numOfExpr' - scan->pExtInfo = createScanExtInfo(meta); - pushNode(scan.release()); - } - - int32_t run() { - SQueryDag* dag = nullptr; - uint64_t requestId = 20; - int32_t code = createDag(logicPlan_.get(), nullptr, &dag, NULL, requestId); - dag_.reset(dag); - return code; - } - - int32_t run(const string& db, const string& sql) { - SParseContext cxt; - buildParseContext(db, sql, &cxt); - SQueryNode* query; - int32_t code = qParseQuerySql(&cxt, &query); - if (TSDB_CODE_SUCCESS != code) { - cout << "error no:" << code << ", msg:" << cxt.pMsg << endl; - return code; - } - SQueryDag* dag = nullptr; - uint64_t requestId = 20; - SSchema *schema = NULL; - int32_t numOfOutput = 0; - - code = qCreateQueryDag(query, &dag, &schema, &numOfOutput, nullptr, requestId); - dag_.reset(dag); - return code; - } - - void explain() { - size_t level = taosArrayGetSize(dag_->pSubplans); - for (size_t i = 0; i < level; ++i) { - std::cout << "level " << i << ":" << std::endl; - const SArray* subplans = (const SArray*)taosArrayGetP(dag_->pSubplans, i); - size_t num = taosArrayGetSize(subplans); - for (size_t j = 0; j < num; ++j) { - std::cout << "no " << j << ":" << std::endl; - int32_t len = 0; - char* str = nullptr; - ASSERT_EQ(TSDB_CODE_SUCCESS, qSubPlanToString((const SSubplan*)taosArrayGetP(subplans, j), &str, &len)); - std::cout << "len:" << len << std::endl; - std::cout << str << std::endl; - free(str); - } - } - } - - SQueryDag* result() { - return dag_.get(); - } - -private: - void pushNode(SQueryPlanNode* node) { - if (logicPlan_) { - node->pChildren = taosArrayInit(TARRAY_MIN_SIZE, POINTER_BYTES); - SQueryPlanNode* child = logicPlan_.release(); - taosArrayPush(node->pChildren, &child); - } - logicPlan_.reset(node); - } - - void copySchemaMeta(STableMeta** dst, const STableMeta* src) { - int32_t size = sizeof(STableMeta) + sizeof(SSchema) * (src->tableInfo.numOfTags + src->tableInfo.numOfColumns); - *dst = (STableMeta*)myCalloc(1, size); - memcpy(*dst, src, size); - } - - void copyStorageMeta(SVgroupsInfo** dst, const std::vector& src) { - *dst = (SVgroupsInfo*)myCalloc(1, sizeof(SVgroupsInfo) + sizeof(SVgroupInfo) * src.size()); - (*dst)->numOfVgroups = src.size(); - for (int32_t i = 0; i < src.size(); ++i) { - (*dst)->vgroups[i] = src[i]; - } - } - - SQueryTableInfo* createScanExtInfo(shared_ptr& meta) { - SQueryTableInfo* info = (SQueryTableInfo*)myCalloc(1, sizeof(SQueryTableInfo)); - info->pMeta = (STableMetaInfo*)myCalloc(1, sizeof(STableMetaInfo)); - copySchemaMeta(&info->pMeta->pTableMeta, meta->schema.get()); - copyStorageMeta(&info->pMeta->vgroupList, meta->vgs); - return info; - } - - void buildParseContext(const string& db, const string& sql, SParseContext* pCxt) { - static string _db; - static string _sql; - static const int32_t _msgMaxLen = 4096; - static char _msg[_msgMaxLen]; - - _db = db; - _sql = sql; - memset(_msg, 0, _msgMaxLen); - - pCxt->acctId = 1; - pCxt->db = _db.c_str(); - pCxt->requestId = 1; - pCxt->pSql = _sql.c_str(); - pCxt->sqlLen = _sql.length(); - pCxt->pMsg = _msg; - pCxt->msgLen = _msgMaxLen; - } - - shared_ptr meta_; - unique_ptr logicPlan_; - unique_ptr dag_; -}; - -// select * from table -TEST_F(PhyPlanTest, tableScanTest) { - pushScan("test", "t1", QNODE_TABLESCAN); - ASSERT_EQ(run(), TSDB_CODE_SUCCESS); - explain(); - SQueryDag* dag = result(); - // todo check -} - -TEST_F(PhyPlanTest, serializeTest) { - pushScan("test", "t1", QNODE_TABLESCAN); - ASSERT_EQ(run(), TSDB_CODE_SUCCESS); - SQueryDag* dag = result(); - cout << qDagToString(dag) << endl; -} - -// select * from supertable -TEST_F(PhyPlanTest, superTableScanTest) { - pushScan("test", "st1", QNODE_TABLESCAN); - ASSERT_EQ(run(), TSDB_CODE_SUCCESS); - explain(); - SQueryDag* dag = result(); - // todo check -} - -// select count(*) from table -TEST_F(PhyPlanTest, simpleAggTest) { - pushScan("test", "t1", QNODE_TABLESCAN); - pushAgg(QNODE_AGGREGATE); - ASSERT_EQ(run(), TSDB_CODE_SUCCESS); - explain(); - SQueryDag* dag = result(); - // todo check -} - -// insert into t values(...) -TEST_F(PhyPlanTest, insertTest) { - ASSERT_EQ(run("test", "insert into t1 values (now, 1, \"beijing\")"), TSDB_CODE_SUCCESS); - explain(); - SQueryDag* dag = result(); - // todo check -} -#endif \ No newline at end of file diff --git a/source/libs/planner/test/newPlannerTest.cpp b/source/libs/planner/test/plannerTest.cpp similarity index 96% rename from source/libs/planner/test/newPlannerTest.cpp rename to source/libs/planner/test/plannerTest.cpp index 3f7f0ca868..737acaf799 100644 --- a/source/libs/planner/test/newPlannerTest.cpp +++ b/source/libs/planner/test/plannerTest.cpp @@ -17,8 +17,8 @@ #include -#include "plannerImpl.h" #include "parser.h" +#include "plannerInt.h" using namespace std; using namespace testing; @@ -56,7 +56,8 @@ protected: const string syntaxTreeStr = toString(query_->pRoot, false); SLogicNode* pLogicPlan = nullptr; - code = createLogicPlan(query_->pRoot, &pLogicPlan); + SPlanContext cxt = { .queryId = 1, .pAstRoot = query_->pRoot }; + code = createLogicPlan(&cxt, &pLogicPlan); if (code != TSDB_CODE_SUCCESS) { cout << "sql:[" << cxt_.pSql << "] logic plan code:" << code << ", strerror:" << tstrerror(code) << endl; return false; diff --git a/source/libs/parser/inc/astCreateContext.h b/source/libs/planner/test/plannerTestMain.cpp similarity index 57% rename from source/libs/parser/inc/astCreateContext.h rename to source/libs/planner/test/plannerTestMain.cpp index a0bac9ea7b..36a46ab99e 100644 --- a/source/libs/parser/inc/astCreateContext.h +++ b/source/libs/planner/test/plannerTestMain.cpp @@ -13,28 +13,29 @@ * along with this program. If not, see . */ -#ifndef _TD_AST_CREATER_H_ -#define _TD_AST_CREATER_H_ +#include -#ifdef __cplusplus -extern "C" { -#endif +#include -#include "nodes.h" -#include "parser.h" +#include "mockCatalog.h" -typedef struct SAstCreateContext { - SParseContext* pQueryCxt; - bool notSupport; - bool valid; - SNode* pRootNode; -} SAstCreateContext; +class PlannerEnv : public testing::Environment { +public: + virtual void SetUp() { + initMetaDataEnv(); + generateMetaData(); + } -int32_t createAstCreateContext(SParseContext* pQueryCxt, SAstCreateContext* pCxt); -int32_t destroyAstCreateContext(SAstCreateContext* pCxt); + virtual void TearDown() { + destroyMetaDataEnv(); + } -#ifdef __cplusplus + PlannerEnv() {} + virtual ~PlannerEnv() {} +}; + +int main(int argc, char* argv[]) { + testing::AddGlobalTestEnvironment(new PlannerEnv()); + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } -#endif - -#endif /*_TD_AST_CREATER_H_*/ diff --git a/source/libs/planner/test/plannerTests.cpp b/source/libs/planner/test/plannerTests.cpp deleted file mode 100644 index 466618da26..0000000000 --- a/source/libs/planner/test/plannerTests.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the GNU Affero General Public License, version 3 - * or later ("AGPL"), as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include -#include - -#include "os.h" - -#include "taos.h" -#include "parser.h" -#include "mockCatalog.h" - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wwrite-strings" -#pragma GCC diagnostic ignored "-Wunused-function" -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wsign-compare" - -class PlannerEnv : public testing::Environment { -public: - virtual void SetUp() { - initMetaDataEnv(); - generateMetaData(); - } - - virtual void TearDown() { - destroyMetaDataEnv(); - } - - PlannerEnv() {} - virtual ~PlannerEnv() {} -}; - -int main(int argc, char* argv[]) { - testing::AddGlobalTestEnvironment(new PlannerEnv()); - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} - -TEST(testCase, planner_test) { - char msg[128] = {0}; - const char* sql = "select top(a*b / 99, 20) from `t.1abc` interval(10s, 1s)"; - - // SQueryStmtInfo* pQueryInfo = nullptr; -// int32_t code = qParseQuerySql(sql, strlen(sql), &pQueryInfo, 0, msg, sizeof(msg)); -// ASSERT_EQ(code, 0); - -// SSqlNode* pNode = (SSqlNode*)taosArrayGetP(((SArray*)info1.list), 0); -// int32_t code = evaluateSqlNode(pNode, TSDB_TIME_PRECISION_NANO, &buf); -// ASSERT_EQ(code, 0); -// -// SMetaReq req = {0}; -// int32_t ret = qParserExtractRequestedMetaInfo(&info1, &req, msg, 128); -// ASSERT_EQ(ret, 0); -// ASSERT_EQ(taosArrayGetSize(req.pTableName), 1); -// -// SQueryStmtInfo* pQueryInfo = createQueryInfo(); -// setTableMetaInfo(pQueryInfo, &req); -// -// SSqlNode* pSqlNode = (SSqlNode*)taosArrayGetP(info1.list, 0); -// ret = validateSqlNode(pSqlNode, pQueryInfo, &buf); -// ASSERT_EQ(ret, 0); -// -// SArray* pExprList = pQueryInfo->exprList; -// ASSERT_EQ(taosArrayGetSize(pExprList), 2); -// -// SExprInfo* p1 = (SExprInfo*)taosArrayGetP(pExprList, 1); -// ASSERT_EQ(p1->base.uid, 110); -// ASSERT_EQ(p1->base.numOfParams, 1); -// ASSERT_EQ(p1->base.resSchema.type, TSDB_DATA_TYPE_DOUBLE); -// ASSERT_STRCASEEQ(p1->base.resSchema.name, "top(a*b / 99, 20)"); -// ASSERT_EQ(p1->base.colInfo.flag, TSDB_COL_NORMAL); -// ASSERT_STRCASEEQ(p1->base.token, "top(a*b / 99, 20)"); -// ASSERT_EQ(p1->base.interBytes, 16); -// -// ASSERT_EQ(p1->pExpr->nodeType, TEXPR_UNARYEXPR_NODE); -// ASSERT_EQ(p1->pExpr->_node.functionId, FUNCTION_TOP); -// ASSERT_TRUE(p1->pExpr->_node.pRight == NULL); -// -// tExprNode* pParam = p1->pExpr->_node.pLeft; -// -// ASSERT_EQ(pParam->nodeType, TEXPR_BINARYEXPR_NODE); -// ASSERT_EQ(pParam->_node.optr, TSDB_BINARY_OP_DIVIDE); -// ASSERT_EQ(pParam->_node.pLeft->nodeType, TEXPR_BINARYEXPR_NODE); -// ASSERT_EQ(pParam->_node.pRight->nodeType, TEXPR_VALUE_NODE); -// -// ASSERT_EQ(taosArrayGetSize(pQueryInfo->colList), 3); -// ASSERT_EQ(pQueryInfo->fieldsInfo.numOfOutput, 2); -// -// destroyQueryInfo(pQueryInfo); -// qParserCleanupMetaRequestInfo(&req); -// destroySqlInfo(&info1); -} - -#pragma GCC diagnostic pop \ No newline at end of file