diff --git a/include/libs/nodes/nodes.h b/include/libs/nodes/nodes.h index 3556a8ac95..320a89030b 100644 --- a/include/libs/nodes/nodes.h +++ b/include/libs/nodes/nodes.h @@ -321,6 +321,8 @@ void nodesListInsertList(SNodeList* pTarget, SListCell* pPos, SNodeList* p SNode* nodesListGetNode(SNodeList* pList, int32_t index); SListCell* nodesListGetCell(SNodeList* pList, int32_t index); void nodesDestroyList(SNodeList* pList); +bool nodesListMatch(const SNodeList* pList, const SNodeList* pSubList); + // Only clear the linked list structure, without releasing the elements inside void nodesClearList(SNodeList* pList); @@ -339,6 +341,7 @@ void nodesRewriteExprPostOrder(SNode** pNode, FNodeRewriter rewriter, void* pCon void nodesRewriteExprsPostOrder(SNodeList* pList, FNodeRewriter rewriter, void* pContext); bool nodesEqualNode(const SNode* a, const SNode* b); +bool nodesMatchNode(const SNode* pSub, const SNode* pNode); SNode* nodesCloneNode(const SNode* pNode); SNodeList* nodesCloneList(const SNodeList* pList); diff --git a/source/libs/nodes/src/nodesMatchFuncs.c b/source/libs/nodes/src/nodesMatchFuncs.c new file mode 100755 index 0000000000..a91fdcdfac --- /dev/null +++ b/source/libs/nodes/src/nodesMatchFuncs.c @@ -0,0 +1,180 @@ +/* + * 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 "querynodes.h" + +#define MATCH_SCALAR_FIELD(fldname) \ + do { \ + if (p->fldname != pSub->fldname) return false; \ + } while (0) + +#define MATCH_STRING(a, b) (((a) != NULL && (b) != NULL) ? (strcmp((a), (b)) == 0) : (a) == (b)) + +#define MATCH_VARDATA(a, b) \ + (((a) != NULL && (b) != NULL) \ + ? (varDataLen((a)) == varDataLen((b)) && memcmp(varDataVal((a)), varDataVal((b)), varDataLen((a))) == 0) \ + : (a) == (b)) + +#define MATCH_STRING_FIELD(fldname) \ + do { \ + if (!MATCH_STRING(p->fldname, pSub->fldname)) return false; \ + } while (0) + +#define MATCH_VARDATA_FIELD(fldname) \ + do { \ + if (!MATCH_VARDATA(p->fldname, pSub->fldname)) return false; \ + } while (0) + +#define MATCH_OBJECT_FIELD(fldname, matchFunc) \ + do { \ + if (!matchFunc(p->fldname, pSub->fldname)) return false; \ + } while (0) + +#define MATCH_NODE_FIELD(fldname) \ + do { \ + if (!nodesMatchNode(pSub->fldname, p->fldname)) return false; \ + } while (0) + +#define MATCH_NODE_LIST_FIELD(fldname) \ + do { \ + if (!nodesListMatch(p->fldname, pSub->fldname)) return false; \ + } while (0) + + +bool nodesListMatchExists(const SNodeList* pList, const SNode* pTarget) { + if (NULL == pList || NULL == pTarget) { + return false; + } + SNode* node = NULL; + bool exists = false; + FOREACH(node, pList) { + if (nodesMatchNode(node, pTarget)) { + exists = true; + break; + } + } + + return exists; +} + +bool nodesListMatch(const SNodeList* pList, const SNodeList* pSubList) { + if (pList == pSubList) { + return true; + } + + if (NULL == pList || NULL == pSubList) { + return false; + } + + if (pList->length != pSubList->length) { + return false; + } + + SNode* node = NULL; + bool match = false; + FOREACH(node, pList) { + if (!nodesListMatchExists(pSubList, node)) { + break; + } + } + return match; +} + +static bool columnNodeMatch(const SColumnNode* pSub, const SColumnNode* p) { + MATCH_STRING_FIELD(dbName); + if (0 == strcmp(p->colName, pSub->node.aliasName)) { + return true; + } + return false; +} + +static bool valueNodeMatch(const SValueNode* pSub, const SValueNode* p) { + return nodesEqualNode((SNode*)pSub, (SNode*)p); +} + +static bool operatorNodeMatch(const SOperatorNode* pSub, const SOperatorNode* p) { + MATCH_SCALAR_FIELD(opType); + MATCH_NODE_FIELD(pLeft); + MATCH_NODE_FIELD(pRight); + return true; +} + +static bool logicConditionNodeMatch(const SLogicConditionNode* pSub, const SLogicConditionNode* p) { + MATCH_SCALAR_FIELD(condType); + MATCH_NODE_LIST_FIELD(pParameterList); + return true; +} + +static bool functionNodeMatch(const SFunctionNode* pSub, const SFunctionNode* p) { + MATCH_SCALAR_FIELD(funcId); + MATCH_STRING_FIELD(functionName); + MATCH_NODE_LIST_FIELD(pParameterList); + return true; +} + +static bool whenThenNodeMatch(const SWhenThenNode* pSub, const SWhenThenNode* p) { + MATCH_NODE_FIELD(pWhen); + MATCH_NODE_FIELD(pThen); + return true; +} + +static bool caseWhenNodeMatch(const SCaseWhenNode* pSub, const SCaseWhenNode* p) { + MATCH_NODE_FIELD(pCase); + MATCH_NODE_FIELD(pElse); + MATCH_NODE_LIST_FIELD(pWhenThenList); + return true; +} + +bool nodesMatchNode(const SNode* pSub, const SNode* p) { + if (pSub == p) { + return true; + } + + if (NULL == pSub || NULL == p) { + return false; + } + + if (nodeType(pSub) != nodeType(p)) { + return false; + } + + switch (nodeType(p)) { + case QUERY_NODE_COLUMN: + return columnNodeMatch((const SColumnNode*)pSub, (const SColumnNode*)p); + case QUERY_NODE_VALUE: + return valueNodeMatch((const SValueNode*)pSub, (const SValueNode*)p); + case QUERY_NODE_OPERATOR: + return operatorNodeMatch((const SOperatorNode*)pSub, (const SOperatorNode*)p); + case QUERY_NODE_LOGIC_CONDITION: + return logicConditionNodeMatch((const SLogicConditionNode*)pSub, (const SLogicConditionNode*)p); + case QUERY_NODE_FUNCTION: + return functionNodeMatch((const SFunctionNode*)pSub, (const SFunctionNode*)p); + case QUERY_NODE_WHEN_THEN: + return whenThenNodeMatch((const SWhenThenNode*)pSub, (const SWhenThenNode*)p); + case QUERY_NODE_CASE_WHEN: + return caseWhenNodeMatch((const SCaseWhenNode*)pSub, (const SCaseWhenNode*)p); + case QUERY_NODE_REAL_TABLE: + case QUERY_NODE_TEMP_TABLE: + case QUERY_NODE_JOIN_TABLE: + case QUERY_NODE_GROUPING_SET: + case QUERY_NODE_ORDER_BY_EXPR: + case QUERY_NODE_LIMIT: + return false; + default: + break; + } + + return false; +} diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index 7692629a9f..9bf94308e1 100644 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -760,6 +760,21 @@ static bool isGlobalTimeLineQuery(SNode* pStmt) { } } +static bool isTimeLineAlignedQuery(SNode* pStmt) { + SSelectStmt *pSelect = (SSelectStmt *)pStmt; + SSelectStmt *pSub = (SSelectStmt *)((STempTableNode*)pSelect->pFromTable)->pSubquery; + if (isGlobalTimeLineQuery((SNode*)pSub)) { + return true; + } + if (!isTimeLineQuery((SNode*)pSub)) { + return false; + } + if (nodesListMatch(pSelect->pPartitionByList, pSub->pPartitionByList)) { + return true; + } + return false; +} + static bool isPrimaryKeyImpl(SNode* pExpr) { if (QUERY_NODE_COLUMN == nodeType(pExpr)) { return (PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pExpr)->colId);