enh: support nest partition by clause
This commit is contained in:
parent
7ea23a33bc
commit
eb7cd25e2e
|
@ -321,6 +321,8 @@ void nodesListInsertList(SNodeList* pTarget, SListCell* pPos, SNodeList* p
|
||||||
SNode* nodesListGetNode(SNodeList* pList, int32_t index);
|
SNode* nodesListGetNode(SNodeList* pList, int32_t index);
|
||||||
SListCell* nodesListGetCell(SNodeList* pList, int32_t index);
|
SListCell* nodesListGetCell(SNodeList* pList, int32_t index);
|
||||||
void nodesDestroyList(SNodeList* pList);
|
void nodesDestroyList(SNodeList* pList);
|
||||||
|
bool nodesListMatch(const SNodeList* pList, const SNodeList* pSubList);
|
||||||
|
|
||||||
// Only clear the linked list structure, without releasing the elements inside
|
// Only clear the linked list structure, without releasing the elements inside
|
||||||
void nodesClearList(SNodeList* pList);
|
void nodesClearList(SNodeList* pList);
|
||||||
|
|
||||||
|
@ -339,6 +341,7 @@ void nodesRewriteExprPostOrder(SNode** pNode, FNodeRewriter rewriter, void* pCon
|
||||||
void nodesRewriteExprsPostOrder(SNodeList* pList, FNodeRewriter rewriter, void* pContext);
|
void nodesRewriteExprsPostOrder(SNodeList* pList, FNodeRewriter rewriter, void* pContext);
|
||||||
|
|
||||||
bool nodesEqualNode(const SNode* a, const SNode* b);
|
bool nodesEqualNode(const SNode* a, const SNode* b);
|
||||||
|
bool nodesMatchNode(const SNode* pSub, const SNode* pNode);
|
||||||
|
|
||||||
SNode* nodesCloneNode(const SNode* pNode);
|
SNode* nodesCloneNode(const SNode* pNode);
|
||||||
SNodeList* nodesCloneList(const SNodeList* pList);
|
SNodeList* nodesCloneList(const SNodeList* pList);
|
||||||
|
|
|
@ -0,0 +1,180 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
|
@ -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) {
|
static bool isPrimaryKeyImpl(SNode* pExpr) {
|
||||||
if (QUERY_NODE_COLUMN == nodeType(pExpr)) {
|
if (QUERY_NODE_COLUMN == nodeType(pExpr)) {
|
||||||
return (PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pExpr)->colId);
|
return (PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pExpr)->colId);
|
||||||
|
|
Loading…
Reference in New Issue