TD-13338 SELECT statement translate code
This commit is contained in:
parent
570ef3d3b2
commit
57c2bdc57a
|
@ -78,6 +78,11 @@ typedef struct SNodeList {
|
|||
SListCell* pTail;
|
||||
} SNodeList;
|
||||
|
||||
typedef struct SNameStr {
|
||||
int32_t len;
|
||||
char* pName;
|
||||
} SNameStr;
|
||||
|
||||
typedef struct SDataType {
|
||||
uint8_t type;
|
||||
uint8_t precision;
|
||||
|
@ -89,6 +94,7 @@ typedef struct SExprNode {
|
|||
ENodeType nodeType;
|
||||
SDataType resType;
|
||||
char aliasName[TSDB_COL_NAME_LEN];
|
||||
SNodeList* pAssociationList;
|
||||
} SExprNode;
|
||||
|
||||
typedef enum EColumnType {
|
||||
|
@ -102,7 +108,9 @@ typedef struct SColumnNode {
|
|||
EColumnType colType; // column or tag
|
||||
char dbName[TSDB_DB_NAME_LEN];
|
||||
char tableName[TSDB_TABLE_NAME_LEN];
|
||||
char tableAlias[TSDB_TABLE_NAME_LEN];
|
||||
char colName[TSDB_COL_NAME_LEN];
|
||||
SNode* pProjectRef;
|
||||
} SColumnNode;
|
||||
|
||||
typedef struct SValueNode {
|
||||
|
@ -176,13 +184,16 @@ typedef struct SFunctionNode {
|
|||
|
||||
typedef struct STableNode {
|
||||
ENodeType type;
|
||||
char dbName[TSDB_DB_NAME_LEN];
|
||||
char tableName[TSDB_TABLE_NAME_LEN];
|
||||
char tableAliasName[TSDB_COL_NAME_LEN];
|
||||
char tableAlias[TSDB_TABLE_NAME_LEN];
|
||||
} STableNode;
|
||||
|
||||
struct STableMeta;
|
||||
|
||||
typedef struct SRealTableNode {
|
||||
STableNode table; // QUERY_NODE_REAL_TABLE
|
||||
char dbName[TSDB_DB_NAME_LEN];
|
||||
struct STableMeta* pMeta;
|
||||
} SRealTableNode;
|
||||
|
||||
typedef struct STempTableNode {
|
||||
|
@ -273,7 +284,6 @@ typedef struct SFillNode {
|
|||
typedef struct SSelectStmt {
|
||||
ENodeType type; // QUERY_NODE_SELECT_STMT
|
||||
bool isDistinct;
|
||||
bool isStar;
|
||||
SNodeList* pProjectionList; // SNode
|
||||
SNode* pFromTable;
|
||||
SNode* pWhere;
|
||||
|
@ -295,6 +305,8 @@ typedef struct SSetOperator {
|
|||
ESetOperatorType opType;
|
||||
SNode* pLeft;
|
||||
SNode* pRight;
|
||||
SNodeList* pOrderByList; // SOrderByExprNode
|
||||
SNode* pLimit;
|
||||
} SSetOperator;
|
||||
|
||||
SNode* nodesMakeNode(ENodeType type);
|
||||
|
@ -306,8 +318,10 @@ void nodesDestroyList(SNodeList* pList);
|
|||
|
||||
typedef bool (*FQueryNodeWalker)(SNode* pNode, void* pContext);
|
||||
|
||||
bool nodesWalkNode(SNode* pNode, FQueryNodeWalker walker, void* pContext);
|
||||
bool nodesWalkList(SNodeList* pList, FQueryNodeWalker walker, void* pContext);
|
||||
void nodesWalkNode(SNode* pNode, FQueryNodeWalker walker, void* pContext);
|
||||
void nodesWalkList(SNodeList* pList, FQueryNodeWalker walker, void* pContext);
|
||||
void nodesWalkNodePostOrder(SNode* pNode, FQueryNodeWalker walker, void* pContext);
|
||||
void nodesWalkListPostOrder(SNodeList* pList, FQueryNodeWalker walker, void* pContext);
|
||||
|
||||
bool nodesWalkStmt(SNode* pNode, FQueryNodeWalker walker, void* pContext);
|
||||
|
||||
|
|
|
@ -440,7 +440,10 @@ int32_t* taosGetErrno();
|
|||
#define TSDB_CODE_SCH_STATUS_ERROR TAOS_DEF_ERROR_CODE(0, 0x2501) //scheduler status error
|
||||
#define TSDB_CODE_SCH_INTERNAL_ERROR TAOS_DEF_ERROR_CODE(0, 0x2502) //scheduler internal error
|
||||
|
||||
|
||||
//parser
|
||||
#define TSDB_CODE_PARSER_INVALID_COLUMN TAOS_DEF_ERROR_CODE(0, 0x2601) //invalid column name
|
||||
#define TSDB_CODE_PARSER_TABLE_NOT_EXIST TAOS_DEF_ERROR_CODE(0, 0x2602) //table not exist
|
||||
#define TSDB_CODE_PARSER_AMBIGUOUS_COLUMN TAOS_DEF_ERROR_CODE(0, 0x2603) //ambiguous column
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -150,7 +150,7 @@ SNode* createRealTableNode(SAstCreateContext* pCxt, const SToken* pDbName, const
|
|||
SRealTableNode* realTable = (SRealTableNode*)nodesMakeNode(QUERY_NODE_REAL_TABLE);
|
||||
CHECK_OUT_OF_MEM(realTable);
|
||||
if (NULL != pDbName) {
|
||||
strncpy(realTable->dbName, pDbName->z, pDbName->n);
|
||||
strncpy(realTable->table.dbName, pDbName->z, pDbName->n);
|
||||
}
|
||||
strncpy(realTable->table.tableName, pTableName->z, pTableName->n);
|
||||
return (SNode*)realTable;
|
||||
|
@ -288,9 +288,6 @@ SNode* createSelectStmt(SAstCreateContext* pCxt, bool isDistinct, SNodeList* pPr
|
|||
SSelectStmt* select = (SSelectStmt*)nodesMakeNode(QUERY_NODE_SELECT_STMT);
|
||||
CHECK_OUT_OF_MEM(select);
|
||||
select->isDistinct = isDistinct;
|
||||
if (NULL == pProjectionList) {
|
||||
select->isStar = true;
|
||||
}
|
||||
select->pProjectionList = pProjectionList;
|
||||
select->pFromTable = pTable;
|
||||
return (SNode*)select;
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
// int32_t doTranslate() {
|
||||
|
||||
// }
|
|
@ -15,8 +15,9 @@
|
|||
|
||||
#include "parserImpl.h"
|
||||
|
||||
#include "ttoken.h"
|
||||
#include "astCreateContext.h"
|
||||
#include "parserInt.h"
|
||||
#include "ttoken.h"
|
||||
|
||||
typedef void* (*FMalloc)(size_t);
|
||||
typedef void (*FFree)(void*);
|
||||
|
@ -25,7 +26,7 @@ extern void* NewParseAlloc(FMalloc);
|
|||
extern void NewParse(void*, int, SToken, void*);
|
||||
extern void NewParseFree(void*, FFree);
|
||||
|
||||
uint32_t toNewTokenId(uint32_t tokenId) {
|
||||
static uint32_t toNewTokenId(uint32_t tokenId) {
|
||||
switch (tokenId) {
|
||||
case TK_UNION:
|
||||
return NEW_TK_UNION;
|
||||
|
@ -73,7 +74,7 @@ uint32_t toNewTokenId(uint32_t tokenId) {
|
|||
return tokenId;
|
||||
}
|
||||
|
||||
uint32_t getToken(const char* z, uint32_t* tokenId) {
|
||||
static uint32_t getToken(const char* z, uint32_t* tokenId) {
|
||||
uint32_t n = tGetToken(z, tokenId);
|
||||
*tokenId = toNewTokenId(*tokenId);
|
||||
return n;
|
||||
|
@ -137,3 +138,289 @@ abort_parse:
|
|||
pQuery->pRoot = cxt.pRootNode;
|
||||
return cxt.valid ? TSDB_CODE_SUCCESS : TSDB_CODE_FAILED;
|
||||
}
|
||||
|
||||
// typedef struct SNamespace {
|
||||
// int16_t level; // todo for correlated subquery
|
||||
// char dbName[TSDB_DB_NAME_LEN];
|
||||
// char tableAlias[TSDB_TABLE_NAME_LEN];
|
||||
// SHashObj* pColHash; // key is colname, value is index of STableMeta.schema
|
||||
// STableMeta* pMeta;
|
||||
// } SNamespace;
|
||||
|
||||
typedef struct STranslateContext {
|
||||
SParseContext* pParseCxt;
|
||||
int32_t errCode;
|
||||
SMsgBuf msgBuf;
|
||||
SArray* pNsLevel; // element is SArray*, the element of this subarray is STableNode*
|
||||
int32_t currLevel;
|
||||
} STranslateContext;
|
||||
|
||||
static int32_t translateSubquery(STranslateContext* pCxt, SNode* pNode);
|
||||
|
||||
static char* getSyntaxErrFormat(int32_t errCode) {
|
||||
switch (errCode) {
|
||||
case TSDB_CODE_PARSER_INVALID_COLUMN:
|
||||
return "Invalid column name : %s";
|
||||
case TSDB_CODE_PARSER_TABLE_NOT_EXIST:
|
||||
return "Table does not exist : %s";
|
||||
case TSDB_CODE_PARSER_AMBIGUOUS_COLUMN:
|
||||
return "Column ambiguously defined : %s";
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t generateSyntaxErrMsg(STranslateContext* pCxt, int32_t errCode, const char* additionalInfo) {
|
||||
snprintf(pCxt->msgBuf.buf, pCxt->msgBuf.len, getSyntaxErrFormat(errCode), additionalInfo);
|
||||
pCxt->errCode = errCode;
|
||||
return errCode;
|
||||
}
|
||||
|
||||
static int32_t addNamespace(STranslateContext* pCxt, void* pTable) {
|
||||
SArray* pTables = NULL;
|
||||
if (taosArrayGetSize(pCxt->pNsLevel) > pCxt->currLevel) {
|
||||
pTables = taosArrayGetP(pCxt->pNsLevel, pCxt->currLevel);
|
||||
} else {
|
||||
pTables = taosArrayInit(TARRAY_MIN_SIZE, POINTER_BYTES);
|
||||
}
|
||||
taosArrayPush(pTables, &pTable);
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static SName* toName(const SRealTableNode* pRealTable, SName* pName) {
|
||||
strncpy(pName->dbname, pRealTable->table.dbName, strlen(pRealTable->table.dbName));
|
||||
strncpy(pName->dbname, pRealTable->table.tableName, strlen(pRealTable->table.tableName));
|
||||
return pName;
|
||||
}
|
||||
|
||||
static bool belongTable(const char* currentDb, const SColumnNode* pCol, const STableNode* pTable) {
|
||||
int cmp = 0;
|
||||
if ('\0' != pCol->dbName[0]) {
|
||||
cmp = strcmp(pCol->dbName, pTable->dbName);
|
||||
} else {
|
||||
cmp = strcmp(currentDb, pTable->dbName);
|
||||
}
|
||||
if (0 == cmp) {
|
||||
cmp = strcmp(pCol->tableAlias, pTable->tableAlias);
|
||||
}
|
||||
return (0 == cmp);
|
||||
}
|
||||
|
||||
static SNodeList* getProjectList(SNode* pNode) {
|
||||
if (QUERY_NODE_SELECT_STMT == nodeType(pNode)) {
|
||||
return ((SSelectStmt*)pNode)->pProjectionList;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int32_t createColumnNodeByTable(const STableNode* pTable, SNodeList* pList) {
|
||||
if (QUERY_NODE_REAL_TABLE == nodeType(pTable)) {
|
||||
const STableMeta* pMeta = ((SRealTableNode*)pTable)->pMeta;
|
||||
int32_t nums = pMeta->tableInfo.numOfTags + pMeta->tableInfo.numOfColumns;
|
||||
for (int32_t i = 0; i < nums; ++i) {
|
||||
SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN);
|
||||
pCol->colId = pMeta->schema[i].colId;
|
||||
pCol->colType = pMeta->schema[i].type;
|
||||
pCol->node.resType.bytes = pMeta->schema[i].bytes;
|
||||
nodesListAppend(pList, (SNode*)pCol);
|
||||
}
|
||||
} else {
|
||||
SNodeList* pProjectList = getProjectList(((STempTableNode*)pTable)->pSubquery);
|
||||
SNode* pNode;
|
||||
FOREACH(pNode, pProjectList) {
|
||||
SExprNode* pExpr = (SExprNode*)pNode;
|
||||
SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN);
|
||||
pCol->pProjectRef = (SNode*)pExpr;
|
||||
pExpr->pAssociationList = nodesListAppend(pExpr->pAssociationList, (SNode*)pCol);
|
||||
pCol->node.resType = pExpr->resType;
|
||||
nodesListAppend(pList, (SNode*)pCol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool findAndSetColumn(SColumnNode* pCol, const STableNode* pTable) {
|
||||
bool found = false;
|
||||
if (QUERY_NODE_REAL_TABLE == nodeType(pTable)) {
|
||||
const STableMeta* pMeta = ((SRealTableNode*)pTable)->pMeta;
|
||||
int32_t nums = pMeta->tableInfo.numOfTags + pMeta->tableInfo.numOfColumns;
|
||||
for (int32_t i = 0; i < nums; ++i) {
|
||||
if (0 == strcmp(pCol->colName, pMeta->schema[i].name)) {
|
||||
pCol->colId = pMeta->schema[i].colId;
|
||||
pCol->colType = pMeta->schema[i].type;
|
||||
pCol->node.resType.bytes = pMeta->schema[i].bytes;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SNodeList* pProjectList = getProjectList(((STempTableNode*)pTable)->pSubquery);
|
||||
SNode* pNode;
|
||||
FOREACH(pNode, pProjectList) {
|
||||
SExprNode* pExpr = (SExprNode*)pNode;
|
||||
if (0 == strcmp(pCol->colName, pExpr->aliasName)) {
|
||||
pCol->pProjectRef = (SNode*)pExpr;
|
||||
pExpr->pAssociationList = nodesListAppend(pExpr->pAssociationList, (SNode*)pCol);
|
||||
pCol->node.resType = pExpr->resType;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
static bool doTranslateExpr(SNode* pNode, void* pContext) {
|
||||
STranslateContext* pCxt = (STranslateContext*)pContext;
|
||||
switch (nodeType(pNode)) {
|
||||
case QUERY_NODE_COLUMN: {
|
||||
SColumnNode* pCol = (SColumnNode*)pNode;
|
||||
SArray* pTables = taosArrayGetP(pCxt->pNsLevel, pCxt->currLevel);
|
||||
size_t nums = taosArrayGetSize(pTables);
|
||||
bool hasTableAlias = ('\0' != pCol->tableAlias[0]);
|
||||
bool found = false;
|
||||
for (size_t i = 0; i < nums; ++i) {
|
||||
STableNode* pTable = taosArrayGetP(pTables, i);
|
||||
if (hasTableAlias) {
|
||||
if (belongTable(pCxt->pParseCxt->db, pCol, pTable)) {
|
||||
if (findAndSetColumn(pCol, pTable)) {
|
||||
break;
|
||||
}
|
||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PARSER_INVALID_COLUMN, pCol->colName);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (findAndSetColumn(pCol, pTable)) {
|
||||
if (found) {
|
||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PARSER_AMBIGUOUS_COLUMN, pCol->colName);
|
||||
return false;
|
||||
}
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QUERY_NODE_VALUE:
|
||||
break; // todo check literal format
|
||||
case QUERY_NODE_OPERATOR: {
|
||||
|
||||
break;
|
||||
}
|
||||
case QUERY_NODE_FUNCTION:
|
||||
break; // todo
|
||||
case QUERY_NODE_TEMP_TABLE:
|
||||
return translateSubquery(pCxt, ((STempTableNode*)pNode)->pSubquery);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int32_t translateExpr(STranslateContext* pCxt, SNode* pNode) {
|
||||
nodesWalkNodePostOrder(pNode, doTranslateExpr, pCxt);
|
||||
return pCxt->errCode;
|
||||
}
|
||||
|
||||
static int32_t translateExprList(STranslateContext* pCxt, SNodeList* pList) {
|
||||
nodesWalkListPostOrder(pList, doTranslateExpr, pCxt);
|
||||
return pCxt->errCode;
|
||||
}
|
||||
|
||||
static int32_t translateTable(STranslateContext* pCxt, SNode* pTable) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
switch (nodeType(pTable)) {
|
||||
case QUERY_NODE_REAL_TABLE: {
|
||||
SRealTableNode* pRealTable = (SRealTableNode*)pTable;
|
||||
if ('\0' == pRealTable->table.dbName[0]) {
|
||||
strcpy(pRealTable->table.dbName, pCxt->pParseCxt->db);
|
||||
}
|
||||
if ('\0' == pRealTable->table.tableAlias[0]) {
|
||||
strcpy(pRealTable->table.tableAlias, pRealTable->table.tableName);
|
||||
}
|
||||
SName name;
|
||||
code = catalogGetTableMeta(
|
||||
pCxt->pParseCxt->pCatalog, pCxt->pParseCxt->pTransporter, &(pCxt->pParseCxt->mgmtEpSet), toName(pRealTable, &name), &(pRealTable->pMeta));
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
return generateSyntaxErrMsg(pCxt, TSDB_CODE_PARSER_TABLE_NOT_EXIST, pRealTable->table.tableName);
|
||||
}
|
||||
code = addNamespace(pCxt, pRealTable);
|
||||
break;
|
||||
}
|
||||
case QUERY_NODE_TEMP_TABLE: {
|
||||
STempTableNode* pTempTable = (STempTableNode*)pTable;
|
||||
code = translateSubquery(pCxt, pTempTable->pSubquery);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = addNamespace(pCxt, pTempTable);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QUERY_NODE_JOIN_TABLE: {
|
||||
SJoinTableNode* pJoinTable = (SJoinTableNode*)pTable;
|
||||
code = translateTable(pCxt, pJoinTable->pLeft);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = translateTable(pCxt, pJoinTable->pRight);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = translateExpr(pCxt, pJoinTable->pOnCond);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t translateStar(STranslateContext* pCxt, SSelectStmt* pSelect, bool* pIsSelectStar) {
|
||||
if (NULL == pSelect->pProjectionList) { // select * ...
|
||||
SArray* pTables = taosArrayGetP(pCxt->pNsLevel, pCxt->currLevel);
|
||||
size_t nums = taosArrayGetSize(pTables);
|
||||
for (size_t i = 0; i < nums; ++i) {
|
||||
STableNode* pTable = taosArrayGetP(pTables, i);
|
||||
createColumnNodeByTable(pTable, pSelect->pProjectionList);
|
||||
}
|
||||
*pIsSelectStar = true;
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t translateSelect(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
code = translateTable(pCxt, pSelect->pFromTable);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = translateExpr(pCxt, pSelect->pWhere);
|
||||
}
|
||||
bool isSelectStar = false;
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = translateStar(pCxt, pSelect, &isSelectStar);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code && !isSelectStar) {
|
||||
code = translateExprList(pCxt, pSelect->pProjectionList);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t translateQuery(STranslateContext* pCxt, SNode* pNode) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
switch (nodeType(pNode)) {
|
||||
case QUERY_NODE_SELECT_STMT:
|
||||
code = translateSelect(pCxt, (SSelectStmt*)pNode);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t translateSubquery(STranslateContext* pCxt, SNode* pNode) {
|
||||
++(pCxt->currLevel);
|
||||
int32_t code = translateQuery(pCxt, pNode);
|
||||
--(pCxt->currLevel);
|
||||
return code;
|
||||
}
|
||||
|
||||
int32_t doTranslate(SParseContext* pParseCxt, SQuery* pQuery) {
|
||||
STranslateContext cxt = { .pParseCxt = pParseCxt, .pNsLevel = taosArrayInit(TARRAY_MIN_SIZE, POINTER_BYTES), .currLevel = 0 };
|
||||
return translateQuery(&cxt, pQuery->pRoot);
|
||||
}
|
||||
|
|
|
@ -71,8 +71,8 @@ private:
|
|||
switch (nodeType(node)) {
|
||||
case QUERY_NODE_REAL_TABLE: {
|
||||
SRealTableNode* realTable = (SRealTableNode*)table;
|
||||
if ('\0' != realTable->dbName[0]) {
|
||||
sql.append(realTable->dbName);
|
||||
if ('\0' != realTable->table.dbName[0]) {
|
||||
sql.append(realTable->table.dbName);
|
||||
sql.append(".");
|
||||
}
|
||||
sql.append(realTable->table.tableName);
|
||||
|
|
|
@ -15,68 +15,101 @@
|
|||
|
||||
#include "nodes.h"
|
||||
|
||||
typedef bool (*FQueryNodeWalker)(SNode* pNode, void* pContext);
|
||||
typedef enum ETraversalOrder {
|
||||
TRAVERSAL_PREORDER = 1,
|
||||
TRAVERSAL_POSTORDER
|
||||
} ETraversalOrder;
|
||||
|
||||
bool nodesWalkNodeList(SNodeList* pNodeList, FQueryNodeWalker walker, void* pContext) {
|
||||
static bool walkList(SNodeList* pNodeList, ETraversalOrder order, FQueryNodeWalker walker, void* pContext);
|
||||
|
||||
static bool walkNode(SNode* pNode, ETraversalOrder order, FQueryNodeWalker walker, void* pContext) {
|
||||
if (NULL == pNode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TRAVERSAL_PREORDER == order && !walker(pNode, pContext)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool res = true;
|
||||
switch (nodeType(pNode)) {
|
||||
case QUERY_NODE_COLUMN:
|
||||
case QUERY_NODE_VALUE:
|
||||
case QUERY_NODE_LIMIT:
|
||||
// these node types with no subnodes
|
||||
break;
|
||||
case QUERY_NODE_OPERATOR: {
|
||||
SOperatorNode* pOpNode = (SOperatorNode*)pNode;
|
||||
res = walkNode(pOpNode->pLeft, order, walker, pContext);
|
||||
if (res) {
|
||||
res = walkNode(pOpNode->pRight, order, walker, pContext);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QUERY_NODE_LOGIC_CONDITION:
|
||||
res = walkList(((SLogicConditionNode*)pNode)->pParameterList, order, walker, pContext);
|
||||
break;
|
||||
case QUERY_NODE_IS_NULL_CONDITION:
|
||||
res = walkNode(((SIsNullCondNode*)pNode)->pExpr, order, walker, pContext);
|
||||
break;
|
||||
case QUERY_NODE_FUNCTION:
|
||||
res = walkList(((SFunctionNode*)pNode)->pParameterList, order, walker, pContext);
|
||||
break;
|
||||
case QUERY_NODE_REAL_TABLE:
|
||||
case QUERY_NODE_TEMP_TABLE:
|
||||
break; // todo
|
||||
case QUERY_NODE_JOIN_TABLE: {
|
||||
SJoinTableNode* pJoinTableNode = (SJoinTableNode*)pNode;
|
||||
res = walkNode(pJoinTableNode->pLeft, order, walker, pContext);
|
||||
if (res) {
|
||||
res = walkNode(pJoinTableNode->pRight, order, walker, pContext);
|
||||
}
|
||||
if (res) {
|
||||
res = walkNode(pJoinTableNode->pOnCond, order, walker, pContext);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QUERY_NODE_GROUPING_SET:
|
||||
res = walkList(((SGroupingSetNode*)pNode)->pParameterList, order, walker, pContext);
|
||||
break;
|
||||
case QUERY_NODE_ORDER_BY_EXPR:
|
||||
res = walkNode(((SOrderByExprNode*)pNode)->pExpr, order, walker, pContext);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (res && TRAVERSAL_POSTORDER == order) {
|
||||
res = walker(pNode, pContext);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool walkList(SNodeList* pNodeList, ETraversalOrder order, FQueryNodeWalker walker, void* pContext) {
|
||||
SNode* node;
|
||||
FOREACH(node, pNodeList) {
|
||||
if (!nodesWalkNode(node, walker, pContext)) {
|
||||
if (!walkNode(node, order, walker, pContext)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nodesWalkNode(SNode* pNode, FQueryNodeWalker walker, void* pContext) {
|
||||
if (NULL == pNode) {
|
||||
return true;
|
||||
}
|
||||
void nodesWalkNode(SNode* pNode, FQueryNodeWalker walker, void* pContext) {
|
||||
(void)walkNode(pNode, TRAVERSAL_PREORDER, walker, pContext);
|
||||
}
|
||||
|
||||
if (!walker(pNode, pContext)) {
|
||||
return false;
|
||||
}
|
||||
void nodesWalkList(SNodeList* pNodeList, FQueryNodeWalker walker, void* pContext) {
|
||||
(void)walkList(pNodeList, TRAVERSAL_PREORDER, walker, pContext);
|
||||
}
|
||||
|
||||
switch (nodeType(pNode)) {
|
||||
case QUERY_NODE_COLUMN:
|
||||
case QUERY_NODE_VALUE:
|
||||
case QUERY_NODE_LIMIT:
|
||||
// these node types with no subnodes
|
||||
return true;
|
||||
case QUERY_NODE_OPERATOR: {
|
||||
SOperatorNode* pOpNode = (SOperatorNode*)pNode;
|
||||
if (!nodesWalkNode(pOpNode->pLeft, walker, pContext)) {
|
||||
return false;
|
||||
}
|
||||
return nodesWalkNode(pOpNode->pRight, walker, pContext);
|
||||
}
|
||||
case QUERY_NODE_LOGIC_CONDITION:
|
||||
return nodesWalkNodeList(((SLogicConditionNode*)pNode)->pParameterList, walker, pContext);
|
||||
case QUERY_NODE_IS_NULL_CONDITION:
|
||||
return nodesWalkNode(((SIsNullCondNode*)pNode)->pExpr, walker, pContext);
|
||||
case QUERY_NODE_FUNCTION:
|
||||
return nodesWalkNodeList(((SFunctionNode*)pNode)->pParameterList, walker, pContext);
|
||||
case QUERY_NODE_REAL_TABLE:
|
||||
case QUERY_NODE_TEMP_TABLE:
|
||||
return true; // todo
|
||||
case QUERY_NODE_JOIN_TABLE: {
|
||||
SJoinTableNode* pJoinTableNode = (SJoinTableNode*)pNode;
|
||||
if (!nodesWalkNode(pJoinTableNode->pLeft, walker, pContext)) {
|
||||
return false;
|
||||
}
|
||||
if (!nodesWalkNode(pJoinTableNode->pRight, walker, pContext)) {
|
||||
return false;
|
||||
}
|
||||
return nodesWalkNode(pJoinTableNode->pOnCond, walker, pContext);
|
||||
}
|
||||
case QUERY_NODE_GROUPING_SET:
|
||||
return nodesWalkNodeList(((SGroupingSetNode*)pNode)->pParameterList, walker, pContext);
|
||||
case QUERY_NODE_ORDER_BY_EXPR:
|
||||
return nodesWalkNode(((SOrderByExprNode*)pNode)->pExpr, walker, pContext);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
void nodesWalkNodePostOrder(SNode* pNode, FQueryNodeWalker walker, void* pContext) {
|
||||
(void)walkNode(pNode, TRAVERSAL_POSTORDER, walker, pContext);
|
||||
}
|
||||
|
||||
return false;
|
||||
void nodesWalkListPostOrder(SNodeList* pList, FQueryNodeWalker walker, void* pContext) {
|
||||
(void)walkList(pList, TRAVERSAL_PREORDER, walker, pContext);
|
||||
}
|
||||
|
||||
bool nodesWalkStmt(SNode* pNode, FQueryNodeWalker walker, void* pContext) {
|
||||
|
|
Loading…
Reference in New Issue