TD-13338 SELECT statement translate code
This commit is contained in:
parent
655b7ec562
commit
a5e9d8f548
|
@ -31,16 +31,7 @@ extern "C" {
|
||||||
for (SListCell* cell = (NULL != (list) ? (list)->pHead : NULL); (NULL != cell ? (node = cell->pNode, true) : (node = NULL, false)); cell = cell->pNext)
|
for (SListCell* cell = (NULL != (list) ? (list)->pHead : NULL); (NULL != cell ? (node = cell->pNode, true) : (node = NULL, false)); cell = cell->pNext)
|
||||||
|
|
||||||
// only be use in FOREACH
|
// only be use in FOREACH
|
||||||
#define ERASE_NODE(list) \
|
#define ERASE_NODE(list) cell = nodesListErase(list, cell);
|
||||||
if (NULL == cell->pPrev) { \
|
|
||||||
(list)->pHead = cell->pNext; \
|
|
||||||
} else { \
|
|
||||||
cell->pPrev->pNext = cell->pNext; \
|
|
||||||
cell->pNext->pPrev = cell->pPrev; \
|
|
||||||
} \
|
|
||||||
SListCell* tmp = cell; \
|
|
||||||
cell = cell->pNext; \
|
|
||||||
tfree(tmp);
|
|
||||||
|
|
||||||
#define REPLACE_NODE(newNode) cell->pNode = (SNode*)(newNode)
|
#define REPLACE_NODE(newNode) cell->pNode = (SNode*)(newNode)
|
||||||
|
|
||||||
|
@ -343,18 +334,22 @@ void nodesDestroyNode(SNode* pNode);
|
||||||
|
|
||||||
SNodeList* nodesMakeList();
|
SNodeList* nodesMakeList();
|
||||||
SNodeList* nodesListAppend(SNodeList* pList, SNode* pNode);
|
SNodeList* nodesListAppend(SNodeList* pList, SNode* pNode);
|
||||||
|
SListCell* nodesListErase(SNodeList* pList, SListCell* pCell);
|
||||||
SNode* nodesListGetNode(SNodeList* pList, int32_t index);
|
SNode* nodesListGetNode(SNodeList* pList, int32_t index);
|
||||||
void nodesDestroyList(SNodeList* pList);
|
void nodesDestroyList(SNodeList* pList);
|
||||||
|
|
||||||
typedef bool (*FQueryNodeWalker)(SNode* pNode, void* pContext);
|
typedef enum EDealRes {
|
||||||
|
DEAL_RES_CONTINUE = 1,
|
||||||
|
DEAL_RES_IGNORE_CHILD,
|
||||||
|
DEAL_RES_ERROR,
|
||||||
|
} EDealRes;
|
||||||
|
typedef EDealRes (*FQueryNodeWalker)(SNode* pNode, void* pContext);
|
||||||
|
|
||||||
void nodesWalkNode(SNode* pNode, FQueryNodeWalker walker, void* pContext);
|
void nodesWalkNode(SNode* pNode, FQueryNodeWalker walker, void* pContext);
|
||||||
void nodesWalkList(SNodeList* pList, FQueryNodeWalker walker, void* pContext);
|
void nodesWalkList(SNodeList* pList, FQueryNodeWalker walker, void* pContext);
|
||||||
void nodesWalkNodePostOrder(SNode* pNode, FQueryNodeWalker walker, void* pContext);
|
void nodesWalkNodePostOrder(SNode* pNode, FQueryNodeWalker walker, void* pContext);
|
||||||
void nodesWalkListPostOrder(SNodeList* pList, FQueryNodeWalker walker, void* pContext);
|
void nodesWalkListPostOrder(SNodeList* pList, FQueryNodeWalker walker, void* pContext);
|
||||||
|
|
||||||
bool nodesWalkStmt(SNode* pNode, FQueryNodeWalker walker, void* pContext);
|
|
||||||
|
|
||||||
bool nodesEqualNode(const SNode* a, const SNode* b);
|
bool nodesEqualNode(const SNode* a, const SNode* b);
|
||||||
|
|
||||||
void nodesCloneNode(const SNode* pNode);
|
void nodesCloneNode(const SNode* pNode);
|
||||||
|
@ -362,6 +357,8 @@ void nodesCloneNode(const SNode* pNode);
|
||||||
int32_t nodesNodeToString(const SNode* pNode, char** pStr, int32_t* pLen);
|
int32_t nodesNodeToString(const SNode* pNode, char** pStr, int32_t* pLen);
|
||||||
int32_t nodesStringToNode(const char* pStr, SNode** pNode);
|
int32_t nodesStringToNode(const char* pStr, SNode** pNode);
|
||||||
|
|
||||||
|
bool nodesIsExprNode(const SNode* pNode);
|
||||||
|
|
||||||
bool nodesIsArithmeticOp(const SOperatorNode* pOp);
|
bool nodesIsArithmeticOp(const SOperatorNode* pOp);
|
||||||
bool nodesIsComparisonOp(const SOperatorNode* pOp);
|
bool nodesIsComparisonOp(const SOperatorNode* pOp);
|
||||||
bool nodesIsJsonOp(const SOperatorNode* pOp);
|
bool nodesIsJsonOp(const SOperatorNode* pOp);
|
||||||
|
|
|
@ -453,6 +453,7 @@ int32_t* taosGetErrno();
|
||||||
#define TSDB_CODE_PAR_FUNTION_PARA_TYPE TAOS_DEF_ERROR_CODE(0, 0x2607) //Inconsistent datatypes
|
#define TSDB_CODE_PAR_FUNTION_PARA_TYPE TAOS_DEF_ERROR_CODE(0, 0x2607) //Inconsistent datatypes
|
||||||
#define TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION TAOS_DEF_ERROR_CODE(0, 0x2608) //There mustn't be aggregation
|
#define TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION TAOS_DEF_ERROR_CODE(0, 0x2608) //There mustn't be aggregation
|
||||||
#define TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT TAOS_DEF_ERROR_CODE(0, 0x2609) //ORDER BY item must be the number of a SELECT-list expression
|
#define TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT TAOS_DEF_ERROR_CODE(0, 0x2609) //ORDER BY item must be the number of a SELECT-list expression
|
||||||
|
#define TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION TAOS_DEF_ERROR_CODE(0, 0x260A) //Not a GROUP BY expression
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@ SNode* createSessionWindowNode(SAstCreateContext* pCxt, SNode* pCol, const SToke
|
||||||
SNode* createStateWindowNode(SAstCreateContext* pCxt, SNode* pCol);
|
SNode* createStateWindowNode(SAstCreateContext* pCxt, SNode* pCol);
|
||||||
SNode* createIntervalWindowNode(SAstCreateContext* pCxt, SNode* pInterval, SNode* pOffset, SNode* pSliding, SNode* pFill);
|
SNode* createIntervalWindowNode(SAstCreateContext* pCxt, SNode* pInterval, SNode* pOffset, SNode* pSliding, SNode* pFill);
|
||||||
SNode* createFillNode(SAstCreateContext* pCxt, EFillMode mode, SNode* pValues);
|
SNode* createFillNode(SAstCreateContext* pCxt, EFillMode mode, SNode* pValues);
|
||||||
|
SNode* createGroupingSetNode(SAstCreateContext* pCxt, SNode* pNode);
|
||||||
|
|
||||||
SNode* addWhereClause(SAstCreateContext* pCxt, SNode* pStmt, SNode* pWhere);
|
SNode* addWhereClause(SAstCreateContext* pCxt, SNode* pStmt, SNode* pWhere);
|
||||||
SNode* addPartitionByClause(SAstCreateContext* pCxt, SNode* pStmt, SNodeList* pPartitionByList);
|
SNode* addPartitionByClause(SAstCreateContext* pCxt, SNode* pStmt, SNodeList* pPartitionByList);
|
||||||
|
|
|
@ -238,6 +238,7 @@ joined_table(A) ::=
|
||||||
|
|
||||||
%type join_type { EJoinType }
|
%type join_type { EJoinType }
|
||||||
%destructor join_type { PARSER_DESTRUCTOR_TRACE; }
|
%destructor join_type { PARSER_DESTRUCTOR_TRACE; }
|
||||||
|
join_type(A) ::= . { PARSER_TRACE; A = JOIN_TYPE_INNER; }
|
||||||
join_type(A) ::= INNER. { PARSER_TRACE; A = JOIN_TYPE_INNER; }
|
join_type(A) ::= INNER. { PARSER_TRACE; A = JOIN_TYPE_INNER; }
|
||||||
|
|
||||||
/************************************************ query_specification *************************************************/
|
/************************************************ query_specification *************************************************/
|
||||||
|
@ -315,7 +316,12 @@ fill_mode(A) ::= NEXT.
|
||||||
%type group_by_clause_opt { SNodeList* }
|
%type group_by_clause_opt { SNodeList* }
|
||||||
%destructor group_by_clause_opt { PARSER_DESTRUCTOR_TRACE; nodesDestroyList($$); }
|
%destructor group_by_clause_opt { PARSER_DESTRUCTOR_TRACE; nodesDestroyList($$); }
|
||||||
group_by_clause_opt(A) ::= . { PARSER_TRACE; A = NULL; }
|
group_by_clause_opt(A) ::= . { PARSER_TRACE; A = NULL; }
|
||||||
group_by_clause_opt(A) ::= GROUP BY expression_list(B). { PARSER_TRACE; A = B; }
|
group_by_clause_opt(A) ::= GROUP BY group_by_list(B). { PARSER_TRACE; A = B; }
|
||||||
|
|
||||||
|
%type group_by_list { SNodeList* }
|
||||||
|
%destructor group_by_list { PARSER_DESTRUCTOR_TRACE; nodesDestroyList($$); }
|
||||||
|
group_by_list(A) ::= expression(B). { PARSER_TRACE; A = createNodeList(pCxt, createGroupingSetNode(pCxt, releaseRawExprNode(pCxt, B))); }
|
||||||
|
group_by_list(A) ::= group_by_list(B) NK_COMMA expression(C). { PARSER_TRACE; A = addNodeToList(pCxt, B, createGroupingSetNode(pCxt, releaseRawExprNode(pCxt, C))); }
|
||||||
|
|
||||||
having_clause_opt(A) ::= . { PARSER_TRACE; A = NULL; }
|
having_clause_opt(A) ::= . { PARSER_TRACE; A = NULL; }
|
||||||
having_clause_opt(A) ::= HAVING search_condition(B). { PARSER_TRACE; A = B; }
|
having_clause_opt(A) ::= HAVING search_condition(B). { PARSER_TRACE; A = B; }
|
||||||
|
|
|
@ -242,6 +242,9 @@ SNode* createOrderByExprNode(SAstCreateContext* pCxt, SNode* pExpr, EOrder order
|
||||||
CHECK_OUT_OF_MEM(orderByExpr);
|
CHECK_OUT_OF_MEM(orderByExpr);
|
||||||
orderByExpr->pExpr = pExpr;
|
orderByExpr->pExpr = pExpr;
|
||||||
orderByExpr->order = order;
|
orderByExpr->order = order;
|
||||||
|
if (NULL_ORDER_DEFAULT == nullOrder) {
|
||||||
|
nullOrder = (ORDER_ASC == order ? NULL_ORDER_FIRST : NULL_ORDER_LAST);
|
||||||
|
}
|
||||||
orderByExpr->nullOrder = nullOrder;
|
orderByExpr->nullOrder = nullOrder;
|
||||||
return (SNode*)orderByExpr;
|
return (SNode*)orderByExpr;
|
||||||
}
|
}
|
||||||
|
@ -279,6 +282,15 @@ SNode* createFillNode(SAstCreateContext* pCxt, EFillMode mode, SNode* pValues) {
|
||||||
return (SNode*)fill;
|
return (SNode*)fill;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SNode* createGroupingSetNode(SAstCreateContext* pCxt, SNode* pNode) {
|
||||||
|
SGroupingSetNode* groupingSet = (SGroupingSetNode*)nodesMakeNode(QUERY_NODE_GROUPING_SET);
|
||||||
|
CHECK_OUT_OF_MEM(groupingSet);
|
||||||
|
groupingSet->groupingSetType = GP_TYPE_NORMAL;
|
||||||
|
groupingSet->pParameterList = nodesMakeList();
|
||||||
|
nodesListAppend(groupingSet->pParameterList, pNode);
|
||||||
|
return (SNode*)groupingSet;
|
||||||
|
}
|
||||||
|
|
||||||
SNode* setProjectionAlias(SAstCreateContext* pCxt, SNode* pNode, const SToken* pAlias) {
|
SNode* setProjectionAlias(SAstCreateContext* pCxt, SNode* pNode, const SToken* pAlias) {
|
||||||
strncpy(((SExprNode*)pNode)->aliasName, pAlias->z, pAlias->n);
|
strncpy(((SExprNode*)pNode)->aliasName, pAlias->z, pAlias->n);
|
||||||
return pNode;
|
return pNode;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -116,10 +116,6 @@ static uint32_t toNewTokenId(uint32_t tokenId) {
|
||||||
return NEW_TK_FROM;
|
return NEW_TK_FROM;
|
||||||
case TK_JOIN:
|
case TK_JOIN:
|
||||||
return NEW_TK_JOIN;
|
return NEW_TK_JOIN;
|
||||||
// case TK_ON:
|
|
||||||
// return NEW_TK_ON;
|
|
||||||
// case TK_INNER:
|
|
||||||
// return NEW_TK_INNER;
|
|
||||||
// case TK_PARTITION:
|
// case TK_PARTITION:
|
||||||
// return NEW_TK_PARTITION;
|
// return NEW_TK_PARTITION;
|
||||||
case TK_SESSION:
|
case TK_SESSION:
|
||||||
|
@ -163,6 +159,8 @@ static uint32_t toNewTokenId(uint32_t tokenId) {
|
||||||
case TK_OFFSET:
|
case TK_OFFSET:
|
||||||
return NEW_TK_OFFSET;
|
return NEW_TK_OFFSET;
|
||||||
case TK_SPACE:
|
case TK_SPACE:
|
||||||
|
case NEW_TK_ON:
|
||||||
|
case NEW_TK_INNER:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!tokenId = %d\n", tokenId);
|
printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!tokenId = %d\n", tokenId);
|
||||||
|
@ -248,6 +246,10 @@ typedef enum ESqlClause {
|
||||||
} ESqlClause;
|
} ESqlClause;
|
||||||
|
|
||||||
static bool afterGroupBy(ESqlClause clause) {
|
static bool afterGroupBy(ESqlClause clause) {
|
||||||
|
return clause > SQL_CLAUSE_GROUP_BY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool beforeHaving(ESqlClause clause) {
|
||||||
return clause < SQL_CLAUSE_HAVING;
|
return clause < SQL_CLAUSE_HAVING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,7 +261,7 @@ typedef struct STranslateContext {
|
||||||
SArray* pNsLevel; // element is SArray*, the element of this subarray is STableNode*
|
SArray* pNsLevel; // element is SArray*, the element of this subarray is STableNode*
|
||||||
int32_t currLevel;
|
int32_t currLevel;
|
||||||
ESqlClause currClause;
|
ESqlClause currClause;
|
||||||
void* pExt;
|
SSelectStmt* pCurrStmt;
|
||||||
} STranslateContext;
|
} STranslateContext;
|
||||||
|
|
||||||
static int32_t translateSubquery(STranslateContext* pCxt, SNode* pNode);
|
static int32_t translateSubquery(STranslateContext* pCxt, SNode* pNode);
|
||||||
|
@ -284,6 +286,8 @@ static char* getSyntaxErrFormat(int32_t errCode) {
|
||||||
return "There mustn't be aggregation";
|
return "There mustn't be aggregation";
|
||||||
case TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT:
|
case TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT:
|
||||||
return "ORDER BY item must be the number of a SELECT-list expression";
|
return "ORDER BY item must be the number of a SELECT-list expression";
|
||||||
|
case TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION:
|
||||||
|
return "Not a GROUP BY expression";
|
||||||
default:
|
default:
|
||||||
return "Unknown error";
|
return "Unknown error";
|
||||||
}
|
}
|
||||||
|
@ -415,7 +419,7 @@ static bool findAndSetColumn(SColumnNode* pCol, const STableNode* pTable) {
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool translateColumnWithPrefix(STranslateContext* pCxt, SColumnNode* pCol) {
|
static EDealRes translateColumnWithPrefix(STranslateContext* pCxt, SColumnNode* pCol) {
|
||||||
SArray* pTables = taosArrayGetP(pCxt->pNsLevel, pCxt->currLevel);
|
SArray* pTables = taosArrayGetP(pCxt->pNsLevel, pCxt->currLevel);
|
||||||
size_t nums = taosArrayGetSize(pTables);
|
size_t nums = taosArrayGetSize(pTables);
|
||||||
for (size_t i = 0; i < nums; ++i) {
|
for (size_t i = 0; i < nums; ++i) {
|
||||||
|
@ -425,13 +429,13 @@ static bool translateColumnWithPrefix(STranslateContext* pCxt, SColumnNode* pCol
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_INVALID_COLUMN, pCol->colName);
|
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_INVALID_COLUMN, pCol->colName);
|
||||||
return false;
|
return DEAL_RES_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return DEAL_RES_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool translateColumnWithoutPrefix(STranslateContext* pCxt, SColumnNode* pCol) {
|
static EDealRes translateColumnWithoutPrefix(STranslateContext* pCxt, SColumnNode* pCol) {
|
||||||
SArray* pTables = taosArrayGetP(pCxt->pNsLevel, pCxt->currLevel);
|
SArray* pTables = taosArrayGetP(pCxt->pNsLevel, pCxt->currLevel);
|
||||||
size_t nums = taosArrayGetSize(pTables);
|
size_t nums = taosArrayGetSize(pTables);
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
@ -440,20 +444,20 @@ static bool translateColumnWithoutPrefix(STranslateContext* pCxt, SColumnNode* p
|
||||||
if (findAndSetColumn(pCol, pTable)) {
|
if (findAndSetColumn(pCol, pTable)) {
|
||||||
if (found) {
|
if (found) {
|
||||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_AMBIGUOUS_COLUMN, pCol->colName);
|
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_AMBIGUOUS_COLUMN, pCol->colName);
|
||||||
return false;
|
return DEAL_RES_ERROR;
|
||||||
}
|
}
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_INVALID_COLUMN, pCol->colName);
|
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_INVALID_COLUMN, pCol->colName);
|
||||||
return false;
|
return DEAL_RES_ERROR;
|
||||||
}
|
}
|
||||||
return true;
|
return DEAL_RES_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool translateColumnUseAlias(STranslateContext* pCxt, SColumnNode* pCol) {
|
static bool translateColumnUseAlias(STranslateContext* pCxt, SColumnNode* pCol) {
|
||||||
SNodeList* pProjectionList = pCxt->pExt;
|
SNodeList* pProjectionList = pCxt->pCurrStmt->pProjectionList;
|
||||||
SNode* pNode;
|
SNode* pNode;
|
||||||
FOREACH(pNode, pProjectionList) {
|
FOREACH(pNode, pProjectionList) {
|
||||||
SExprNode* pExpr = (SExprNode*)pNode;
|
SExprNode* pExpr = (SExprNode*)pNode;
|
||||||
|
@ -465,10 +469,10 @@ static bool translateColumnUseAlias(STranslateContext* pCxt, SColumnNode* pCol)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool translateColumn(STranslateContext* pCxt, SColumnNode* pCol) {
|
static EDealRes translateColumn(STranslateContext* pCxt, SColumnNode* pCol) {
|
||||||
// count(*)/first(*)/last(*)
|
// count(*)/first(*)/last(*)
|
||||||
if (0 == strcmp(pCol->colName, "*")) {
|
if (0 == strcmp(pCol->colName, "*")) {
|
||||||
return true;
|
return DEAL_RES_CONTINUE;
|
||||||
}
|
}
|
||||||
if ('\0' != pCol->tableAlias[0]) {
|
if ('\0' != pCol->tableAlias[0]) {
|
||||||
return translateColumnWithPrefix(pCxt, pCol);
|
return translateColumnWithPrefix(pCxt, pCol);
|
||||||
|
@ -477,7 +481,7 @@ static bool translateColumn(STranslateContext* pCxt, SColumnNode* pCol) {
|
||||||
if (SQL_CLAUSE_ORDER_BY == pCxt->currClause) {
|
if (SQL_CLAUSE_ORDER_BY == pCxt->currClause) {
|
||||||
found = translateColumnUseAlias(pCxt, pCol);
|
found = translateColumnUseAlias(pCxt, pCol);
|
||||||
}
|
}
|
||||||
return found ? true : translateColumnWithoutPrefix(pCxt, pCol);
|
return found ? DEAL_RES_CONTINUE : translateColumnWithoutPrefix(pCxt, pCol);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t trimStringCopy(const char* src, int32_t len, char* dst) {
|
static int32_t trimStringCopy(const char* src, int32_t len, char* dst) {
|
||||||
|
@ -500,12 +504,12 @@ static int32_t trimStringCopy(const char* src, int32_t len, char* dst) {
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool translateValue(STranslateContext* pCxt, SValueNode* pVal) {
|
static EDealRes translateValue(STranslateContext* pCxt, SValueNode* pVal) {
|
||||||
if (pVal->isDuration) {
|
if (pVal->isDuration) {
|
||||||
char unit = 0;
|
char unit = 0;
|
||||||
if (parseAbsoluteDuration(pVal->literal, strlen(pVal->literal), &pVal->datum.i, &unit, pVal->node.resType.precision) != TSDB_CODE_SUCCESS) {
|
if (parseAbsoluteDuration(pVal->literal, strlen(pVal->literal), &pVal->datum.i, &unit, pVal->node.resType.precision) != TSDB_CODE_SUCCESS) {
|
||||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, pVal->literal);
|
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, pVal->literal);
|
||||||
return false;
|
return DEAL_RES_ERROR;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (pVal->node.resType.type) {
|
switch (pVal->node.resType.type) {
|
||||||
|
@ -552,7 +556,7 @@ static bool translateValue(STranslateContext* pCxt, SValueNode* pVal) {
|
||||||
if (taosParseTime(tmp, &pVal->datum.u, len, pVal->node.resType.precision, tsDaylight) != TSDB_CODE_SUCCESS) {
|
if (taosParseTime(tmp, &pVal->datum.u, len, pVal->node.resType.precision, tsDaylight) != TSDB_CODE_SUCCESS) {
|
||||||
tfree(tmp);
|
tfree(tmp);
|
||||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, pVal->literal);
|
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, pVal->literal);
|
||||||
return false;
|
return DEAL_RES_ERROR;
|
||||||
}
|
}
|
||||||
tfree(tmp);
|
tfree(tmp);
|
||||||
break;
|
break;
|
||||||
|
@ -565,55 +569,56 @@ static bool translateValue(STranslateContext* pCxt, SValueNode* pVal) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return DEAL_RES_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool translateOperator(STranslateContext* pCxt, SOperatorNode* pOp) {
|
static EDealRes translateOperator(STranslateContext* pCxt, SOperatorNode* pOp) {
|
||||||
SDataType ldt = ((SExprNode*)(pOp->pLeft))->resType;
|
SDataType ldt = ((SExprNode*)(pOp->pLeft))->resType;
|
||||||
SDataType rdt = ((SExprNode*)(pOp->pRight))->resType;
|
SDataType rdt = ((SExprNode*)(pOp->pRight))->resType;
|
||||||
if (nodesIsArithmeticOp(pOp)) {
|
if (nodesIsArithmeticOp(pOp)) {
|
||||||
if (TSDB_DATA_TYPE_JSON == ldt.type || TSDB_DATA_TYPE_BLOB == ldt.type ||
|
if (TSDB_DATA_TYPE_JSON == ldt.type || TSDB_DATA_TYPE_BLOB == ldt.type ||
|
||||||
TSDB_DATA_TYPE_JSON == rdt.type || TSDB_DATA_TYPE_BLOB == rdt.type) {
|
TSDB_DATA_TYPE_JSON == rdt.type || TSDB_DATA_TYPE_BLOB == rdt.type) {
|
||||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, ((SExprNode*)(pOp->pRight))->aliasName);
|
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, ((SExprNode*)(pOp->pRight))->aliasName);
|
||||||
return false;
|
return DEAL_RES_ERROR;
|
||||||
}
|
}
|
||||||
pOp->node.resType.type = TSDB_DATA_TYPE_DOUBLE;
|
pOp->node.resType.type = TSDB_DATA_TYPE_DOUBLE;
|
||||||
pOp->node.resType.bytes = tDataTypes[TSDB_DATA_TYPE_DOUBLE].bytes;
|
pOp->node.resType.bytes = tDataTypes[TSDB_DATA_TYPE_DOUBLE].bytes;
|
||||||
return true;
|
|
||||||
} else if (nodesIsComparisonOp(pOp)) {
|
} else if (nodesIsComparisonOp(pOp)) {
|
||||||
if (TSDB_DATA_TYPE_JSON == ldt.type || TSDB_DATA_TYPE_BLOB == ldt.type ||
|
if (TSDB_DATA_TYPE_JSON == ldt.type || TSDB_DATA_TYPE_BLOB == ldt.type ||
|
||||||
TSDB_DATA_TYPE_JSON == rdt.type || TSDB_DATA_TYPE_BLOB == rdt.type) {
|
TSDB_DATA_TYPE_JSON == rdt.type || TSDB_DATA_TYPE_BLOB == rdt.type) {
|
||||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, ((SExprNode*)(pOp->pRight))->aliasName);
|
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, ((SExprNode*)(pOp->pRight))->aliasName);
|
||||||
return false;
|
return DEAL_RES_ERROR;
|
||||||
}
|
}
|
||||||
pOp->node.resType.type = TSDB_DATA_TYPE_BOOL;
|
pOp->node.resType.type = TSDB_DATA_TYPE_BOOL;
|
||||||
pOp->node.resType.bytes = tDataTypes[TSDB_DATA_TYPE_BOOL].bytes;
|
pOp->node.resType.bytes = tDataTypes[TSDB_DATA_TYPE_BOOL].bytes;
|
||||||
return true;
|
|
||||||
} else {
|
} else {
|
||||||
// todo json operator
|
// todo json operator
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return true;
|
return DEAL_RES_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool translateFunction(STranslateContext* pCxt, SFunctionNode* pFunc) {
|
static EDealRes translateFunction(STranslateContext* pCxt, SFunctionNode* pFunc) {
|
||||||
if (TSDB_CODE_SUCCESS != fmGetFuncInfo(pCxt->fmgt, pFunc->functionName, &pFunc->funcId, &pFunc->funcType)) {
|
if (TSDB_CODE_SUCCESS != fmGetFuncInfo(pCxt->fmgt, pFunc->functionName, &pFunc->funcId, &pFunc->funcType)) {
|
||||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_INVALID_FUNTION, pFunc->functionName);
|
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_INVALID_FUNTION, pFunc->functionName);
|
||||||
return false;
|
return DEAL_RES_ERROR;
|
||||||
}
|
}
|
||||||
int32_t code = fmGetFuncResultType(pFunc);
|
int32_t code = fmGetFuncResultType(pFunc);
|
||||||
if (TSDB_CODE_SUCCESS != code) {
|
if (TSDB_CODE_SUCCESS != code) {
|
||||||
generateSyntaxErrMsg(pCxt, code, pFunc->functionName);
|
generateSyntaxErrMsg(pCxt, code, pFunc->functionName);
|
||||||
return false;
|
return DEAL_RES_ERROR;
|
||||||
}
|
}
|
||||||
if (fmIsAggFunc(pFunc->funcId) && afterGroupBy(pCxt->currClause)) {
|
if (fmIsAggFunc(pFunc->funcId) && beforeHaving(pCxt->currClause)) {
|
||||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION);
|
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION);
|
||||||
return false;
|
return DEAL_RES_ERROR;
|
||||||
}
|
}
|
||||||
return true;
|
return DEAL_RES_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool doTranslateExpr(SNode* pNode, void* pContext) {
|
static EDealRes translateExprSubquery(STranslateContext* pCxt, SNode* pNode) {
|
||||||
|
return (TSDB_CODE_SUCCESS == translateSubquery(pCxt, pNode) ? DEAL_RES_CONTINUE : DEAL_RES_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static EDealRes doTranslateExpr(SNode* pNode, void* pContext) {
|
||||||
STranslateContext* pCxt = (STranslateContext*)pContext;
|
STranslateContext* pCxt = (STranslateContext*)pContext;
|
||||||
switch (nodeType(pNode)) {
|
switch (nodeType(pNode)) {
|
||||||
case QUERY_NODE_COLUMN:
|
case QUERY_NODE_COLUMN:
|
||||||
|
@ -625,11 +630,11 @@ static bool doTranslateExpr(SNode* pNode, void* pContext) {
|
||||||
case QUERY_NODE_FUNCTION:
|
case QUERY_NODE_FUNCTION:
|
||||||
return translateFunction(pCxt, (SFunctionNode*)pNode);
|
return translateFunction(pCxt, (SFunctionNode*)pNode);
|
||||||
case QUERY_NODE_TEMP_TABLE:
|
case QUERY_NODE_TEMP_TABLE:
|
||||||
return translateSubquery(pCxt, ((STempTableNode*)pNode)->pSubquery);
|
return translateExprSubquery(pCxt, ((STempTableNode*)pNode)->pSubquery);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return true;
|
return DEAL_RES_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t translateExpr(STranslateContext* pCxt, SNode* pNode) {
|
static int32_t translateExpr(STranslateContext* pCxt, SNode* pNode) {
|
||||||
|
@ -642,6 +647,41 @@ static int32_t translateExprList(STranslateContext* pCxt, SNodeList* pList) {
|
||||||
return pCxt->errCode;
|
return pCxt->errCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isAliasColumn(SColumnNode* pCol) {
|
||||||
|
return ('\0' == pCol->tableAlias[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static EDealRes doCheckkExprForGroupBy(SNode* pNode, void* pContext) {
|
||||||
|
STranslateContext* pCxt = (STranslateContext*)pContext;
|
||||||
|
if (!nodesIsExprNode(pNode) || (QUERY_NODE_COLUMN == nodeType(pNode) && isAliasColumn((SColumnNode*)pNode))) {
|
||||||
|
return DEAL_RES_CONTINUE;
|
||||||
|
}
|
||||||
|
if (QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsAggFunc(((SFunctionNode*)pNode)->funcId)) {
|
||||||
|
return DEAL_RES_IGNORE_CHILD;
|
||||||
|
}
|
||||||
|
SNode* pGroupNode;
|
||||||
|
FOREACH(pGroupNode, pCxt->pCurrStmt->pGroupByList) {
|
||||||
|
if (nodesEqualNode(nodesListGetNode(((SGroupingSetNode*)pGroupNode)->pParameterList, 0), pNode)) {
|
||||||
|
return DEAL_RES_IGNORE_CHILD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (QUERY_NODE_COLUMN == nodeType(pNode)) {
|
||||||
|
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION);
|
||||||
|
return DEAL_RES_ERROR;
|
||||||
|
}
|
||||||
|
return DEAL_RES_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t checkExprForGroupBy(STranslateContext* pCxt, SNode* pNode) {
|
||||||
|
nodesWalkNode(pNode, doCheckkExprForGroupBy, pCxt);
|
||||||
|
return pCxt->errCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t checkExprListForGroupBy(STranslateContext* pCxt, SNodeList* pList) {
|
||||||
|
nodesWalkList(pList, doCheckkExprForGroupBy, pCxt);
|
||||||
|
return pCxt->errCode;
|
||||||
|
}
|
||||||
|
|
||||||
static int32_t translateTable(STranslateContext* pCxt, SNode* pTable) {
|
static int32_t translateTable(STranslateContext* pCxt, SNode* pTable) {
|
||||||
int32_t code = TSDB_CODE_SUCCESS;
|
int32_t code = TSDB_CODE_SUCCESS;
|
||||||
switch (nodeType(pTable)) {
|
switch (nodeType(pTable)) {
|
||||||
|
@ -732,12 +772,13 @@ static bool translateOrderByPosition(STranslateContext* pCxt, SNodeList* pProjec
|
||||||
*pOther = false;
|
*pOther = false;
|
||||||
SNode* pNode;
|
SNode* pNode;
|
||||||
FOREACH(pNode, pOrderByList) {
|
FOREACH(pNode, pOrderByList) {
|
||||||
if (QUERY_NODE_VALUE == nodeType(pNode)) {
|
SNode* pExpr = ((SOrderByExprNode*)pNode)->pExpr;
|
||||||
SValueNode* pVal = (SValueNode*)pNode;
|
if (QUERY_NODE_VALUE == nodeType(pExpr)) {
|
||||||
if (translateValue(pCxt, pVal)) {
|
SValueNode* pVal = (SValueNode*)pExpr;
|
||||||
|
if (!translateValue(pCxt, pVal)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int32_t pos = getPositionValue((SValueNode*)pNode);
|
int32_t pos = getPositionValue((SValueNode*)pExpr);
|
||||||
if (pos < 0) {
|
if (pos < 0) {
|
||||||
ERASE_NODE(pOrderByList);
|
ERASE_NODE(pOrderByList);
|
||||||
nodesDestroyNode(pNode);
|
nodesDestroyNode(pNode);
|
||||||
|
@ -747,9 +788,9 @@ static bool translateOrderByPosition(STranslateContext* pCxt, SNodeList* pProjec
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN);
|
SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN);
|
||||||
setColumnInfoByExpr(NULL, (SExprNode*)nodesListGetNode(pProjectionList, pos), pCol);
|
setColumnInfoByExpr(NULL, (SExprNode*)nodesListGetNode(pProjectionList, pos - 1), pCol);
|
||||||
REPLACE_NODE(pCol);
|
((SOrderByExprNode*)pNode)->pExpr = (SNode*)pCol;
|
||||||
nodesDestroyNode(pNode);
|
nodesDestroyNode(pExpr);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
*pOther = true;
|
*pOther = true;
|
||||||
|
@ -758,17 +799,20 @@ static bool translateOrderByPosition(STranslateContext* pCxt, SNodeList* pProjec
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t translateOrderBy(STranslateContext* pCxt, SNodeList* pProjectionList, SNodeList* pOrderByList) {
|
static int32_t translateOrderBy(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||||
bool other;
|
bool other;
|
||||||
if (!translateOrderByPosition(pCxt, pProjectionList, pOrderByList, &other)) {
|
if (!translateOrderByPosition(pCxt, pSelect->pProjectionList, pSelect->pOrderByList, &other)) {
|
||||||
return pCxt->errCode;
|
return pCxt->errCode;
|
||||||
}
|
}
|
||||||
if (!other) {
|
if (!other) {
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
pCxt->currClause = SQL_CLAUSE_ORDER_BY;
|
pCxt->currClause = SQL_CLAUSE_ORDER_BY;
|
||||||
pCxt->pExt = pProjectionList;
|
int32_t code = translateExprList(pCxt, pSelect->pOrderByList);
|
||||||
return translateExprList(pCxt, pOrderByList);
|
if (TSDB_CODE_SUCCESS == code && NULL != pSelect->pGroupByList) {
|
||||||
|
code = checkExprListForGroupBy(pCxt, pSelect->pOrderByList);
|
||||||
|
}
|
||||||
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t translateSelectList(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
static int32_t translateSelectList(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||||
|
@ -778,12 +822,22 @@ static int32_t translateSelectList(STranslateContext* pCxt, SSelectStmt* pSelect
|
||||||
pCxt->currClause = SQL_CLAUSE_SELECT;
|
pCxt->currClause = SQL_CLAUSE_SELECT;
|
||||||
code = translateExprList(pCxt, pSelect->pProjectionList);
|
code = translateExprList(pCxt, pSelect->pProjectionList);
|
||||||
}
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code && NULL != pSelect->pGroupByList) {
|
||||||
|
code = checkExprListForGroupBy(pCxt, pSelect->pProjectionList);
|
||||||
|
}
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t translateHaving(STranslateContext* pCxt, SNode* pHaving) {
|
static int32_t translateHaving(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||||
|
if (NULL == pSelect->pGroupByList && NULL != pSelect->pHaving) {
|
||||||
|
return generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION);
|
||||||
|
}
|
||||||
pCxt->currClause = SQL_CLAUSE_HAVING;
|
pCxt->currClause = SQL_CLAUSE_HAVING;
|
||||||
return translateExpr(pCxt, pHaving);
|
int32_t code = translateExpr(pCxt, pSelect->pHaving);
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = checkExprForGroupBy(pCxt, pSelect->pHaving);
|
||||||
|
}
|
||||||
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t translateGroupBy(STranslateContext* pCxt, SNodeList* pGroupByList) {
|
static int32_t translateGroupBy(STranslateContext* pCxt, SNodeList* pGroupByList) {
|
||||||
|
@ -818,8 +872,8 @@ static int32_t translateFrom(STranslateContext* pCxt, SNode* pTable) {
|
||||||
// } SSelectStmt;
|
// } SSelectStmt;
|
||||||
|
|
||||||
static int32_t translateSelect(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
static int32_t translateSelect(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||||
int32_t code = TSDB_CODE_SUCCESS;
|
pCxt->pCurrStmt = pSelect;
|
||||||
code = translateFrom(pCxt, pSelect->pFromTable);
|
int32_t code = translateFrom(pCxt, pSelect->pFromTable);
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = translateWhere(pCxt, pSelect->pWhere);
|
code = translateWhere(pCxt, pSelect->pWhere);
|
||||||
}
|
}
|
||||||
|
@ -833,15 +887,14 @@ static int32_t translateSelect(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||||
code = translateGroupBy(pCxt, pSelect->pGroupByList);
|
code = translateGroupBy(pCxt, pSelect->pGroupByList);
|
||||||
}
|
}
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = translateHaving(pCxt, pSelect->pHaving);
|
code = translateHaving(pCxt, pSelect);
|
||||||
}
|
}
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = translateSelectList(pCxt, pSelect);
|
code = translateSelectList(pCxt, pSelect);
|
||||||
}
|
}
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = translateOrderBy(pCxt, pSelect->pProjectionList, pSelect->pOrderByList);
|
code = translateOrderBy(pCxt, pSelect);
|
||||||
}
|
}
|
||||||
// printf("%s:%d code = %d\n", __FUNCTION__, __LINE__, code);
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -860,11 +913,11 @@ static int32_t translateQuery(STranslateContext* pCxt, SNode* pNode) {
|
||||||
static int32_t translateSubquery(STranslateContext* pCxt, SNode* pNode) {
|
static int32_t translateSubquery(STranslateContext* pCxt, SNode* pNode) {
|
||||||
++(pCxt->currLevel);
|
++(pCxt->currLevel);
|
||||||
ESqlClause currClause = pCxt->currClause;
|
ESqlClause currClause = pCxt->currClause;
|
||||||
void* pExt = pCxt->pExt;
|
SSelectStmt* pCurrStmt = pCxt->pCurrStmt;
|
||||||
int32_t code = translateQuery(pCxt, pNode);
|
int32_t code = translateQuery(pCxt, pNode);
|
||||||
--(pCxt->currLevel);
|
--(pCxt->currLevel);
|
||||||
pCxt->currClause = currClause;
|
pCxt->currClause = currClause;
|
||||||
pCxt->pExt = pExt;
|
pCxt->pCurrStmt = pCurrStmt;
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -227,7 +227,9 @@ static SKeyword keywordTable[] = {
|
||||||
{"OUTPUTTYPE", TK_OUTPUTTYPE},
|
{"OUTPUTTYPE", TK_OUTPUTTYPE},
|
||||||
{"AGGREGATE", TK_AGGREGATE},
|
{"AGGREGATE", TK_AGGREGATE},
|
||||||
{"BUFSIZE", TK_BUFSIZE},
|
{"BUFSIZE", TK_BUFSIZE},
|
||||||
{"PORT", TK_PORT},
|
{"PORT", TK_PORT},
|
||||||
|
{"INNER", NEW_TK_INNER},
|
||||||
|
{"ON", NEW_TK_ON},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char isIdChar[] = {
|
static const char isIdChar[] = {
|
||||||
|
|
|
@ -53,8 +53,8 @@ protected:
|
||||||
code = doTranslate(&cxt_, &query_);
|
code = doTranslate(&cxt_, &query_);
|
||||||
// cout << "doTranslate return " << code << endl;
|
// cout << "doTranslate return " << code << endl;
|
||||||
if (code != TSDB_CODE_SUCCESS) {
|
if (code != TSDB_CODE_SUCCESS) {
|
||||||
cout << "sql:[" << cxt_.pSql << "] code:" << tstrerror(code) << ", msg:" << errMagBuf_ << endl;
|
cout << "sql:[" << cxt_.pSql << "] code:" << code << ", " << translateCode << ", msg:" << errMagBuf_ << endl;
|
||||||
return (TSDB_CODE_SUCCESS != translateCode);
|
return (code == translateCode);
|
||||||
}
|
}
|
||||||
if (NULL != query_.pRoot && QUERY_NODE_SELECT_STMT == nodeType(query_.pRoot)) {
|
if (NULL != query_.pRoot && QUERY_NODE_SELECT_STMT == nodeType(query_.pRoot)) {
|
||||||
cout << "input sql : [" << cxt_.pSql << "]" << endl;
|
cout << "input sql : [" << cxt_.pSql << "]" << endl;
|
||||||
|
@ -71,6 +71,24 @@ protected:
|
||||||
private:
|
private:
|
||||||
static const int max_err_len = 1024;
|
static const int max_err_len = 1024;
|
||||||
|
|
||||||
|
void exprNodeToStr(const SNode* node, string& str, bool isProject) {
|
||||||
|
switch (nodeType(node)) {
|
||||||
|
case QUERY_NODE_COLUMN:
|
||||||
|
case QUERY_NODE_VALUE:
|
||||||
|
case QUERY_NODE_OPERATOR:
|
||||||
|
case QUERY_NODE_FUNCTION: {
|
||||||
|
SExprNode* pExpr = (SExprNode*)node;
|
||||||
|
str.append(" [" + dataTypeToStr(pExpr->resType) + "]");
|
||||||
|
if (isProject) {
|
||||||
|
str.append(" AS " + string(pExpr->aliasName));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
string dataTypeToStr(const SDataType& dt) {
|
string dataTypeToStr(const SDataType& dt) {
|
||||||
switch (dt.type) {
|
switch (dt.type) {
|
||||||
case TSDB_DATA_TYPE_NULL:
|
case TSDB_DATA_TYPE_NULL:
|
||||||
|
@ -119,7 +137,7 @@ private:
|
||||||
return "Unknown Data Type " + to_string(dt.type);
|
return "Unknown Data Type " + to_string(dt.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void valueNodeToStr(const SValueNode* pVal, string& str, bool isProject) {
|
void valueNodeToStr(const SValueNode* pVal, string& str) {
|
||||||
switch (pVal->node.resType.type) {
|
switch (pVal->node.resType.type) {
|
||||||
case TSDB_DATA_TYPE_NULL:
|
case TSDB_DATA_TYPE_NULL:
|
||||||
str.append("null");
|
str.append("null");
|
||||||
|
@ -160,10 +178,41 @@ private:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
str.append(" [" + dataTypeToStr(pVal->node.resType) + "]");
|
}
|
||||||
if (isProject) {
|
|
||||||
str.append(" AS " + string(pVal->node.aliasName));
|
void columnNodeToStr(const SColumnNode* pCol, string& str) {
|
||||||
|
if ('\0' != pCol->dbName[0]) {
|
||||||
|
str.append(pCol->dbName);
|
||||||
|
str.append(".");
|
||||||
}
|
}
|
||||||
|
if ('\0' != pCol->tableAlias[0]) {
|
||||||
|
str.append(pCol->tableAlias);
|
||||||
|
str.append(".");
|
||||||
|
}
|
||||||
|
str.append(pCol->colName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operatorToStr(const SOperatorNode* pOp, string& str) {
|
||||||
|
nodeToStr(pOp->pLeft, str, false);
|
||||||
|
str.append(opTypeToStr(pOp->opType));
|
||||||
|
nodeToStr(pOp->pRight, str, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void functionToStr(const SFunctionNode* pFunc, string& str) {
|
||||||
|
str.append(pFunc->functionName);
|
||||||
|
str.append("(");
|
||||||
|
nodeListToStr(pFunc->pParameterList, "", str, false, ", ");
|
||||||
|
str.append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
void groupingSetToStr(SGroupingSetNode* pGroup, string& str) {
|
||||||
|
nodeToStr(nodesListGetNode(pGroup->pParameterList, 0), str, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void orderByExprToStr(SOrderByExprNode* pOrderBy, string& str) {
|
||||||
|
nodeToStr(pOrderBy->pExpr, str, false);
|
||||||
|
str.append((ORDER_ASC == pOrderBy->order ? " ASC" : " DESC"));
|
||||||
|
str.append((NULL_ORDER_FIRST == pOrderBy->nullOrder ? " NULLS FIRST" : " NULLS LAST"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void nodeToStr(const SNode* node, string& str, bool isProject) {
|
void nodeToStr(const SNode* node, string& str, bool isProject) {
|
||||||
|
@ -173,48 +222,41 @@ private:
|
||||||
|
|
||||||
switch (nodeType(node)) {
|
switch (nodeType(node)) {
|
||||||
case QUERY_NODE_COLUMN: {
|
case QUERY_NODE_COLUMN: {
|
||||||
SColumnNode* pCol = (SColumnNode*)node;
|
columnNodeToStr((SColumnNode*)node, str);
|
||||||
if ('\0' != pCol->dbName[0]) {
|
|
||||||
str.append(pCol->dbName);
|
|
||||||
str.append(".");
|
|
||||||
}
|
|
||||||
if ('\0' != pCol->tableAlias[0]) {
|
|
||||||
str.append(pCol->tableAlias);
|
|
||||||
str.append(".");
|
|
||||||
}
|
|
||||||
str.append(pCol->colName);
|
|
||||||
str.append(" [" + dataTypeToStr(pCol->node.resType) + "]");
|
|
||||||
if (isProject) {
|
|
||||||
str.append(" AS " + string(pCol->node.aliasName));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case QUERY_NODE_VALUE: {
|
case QUERY_NODE_VALUE: {
|
||||||
valueNodeToStr((SValueNode*)node, str, isProject);
|
valueNodeToStr((SValueNode*)node, str);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case QUERY_NODE_OPERATOR: {
|
case QUERY_NODE_OPERATOR: {
|
||||||
SOperatorNode* pOp = (SOperatorNode*)node;
|
operatorToStr((SOperatorNode*)node, str);
|
||||||
nodeToStr(pOp->pLeft, str, false);
|
break;
|
||||||
str.append(opTypeToStr(pOp->opType));
|
}
|
||||||
nodeToStr(pOp->pRight, str, false);
|
case QUERY_NODE_FUNCTION: {
|
||||||
str.append(" [" + dataTypeToStr(pOp->node.resType) + "]");
|
functionToStr((SFunctionNode*)node, str);
|
||||||
if (isProject) {
|
break;
|
||||||
str.append(" AS " + string(pOp->node.aliasName));
|
}
|
||||||
}
|
case QUERY_NODE_GROUPING_SET: {
|
||||||
|
groupingSetToStr((SGroupingSetNode*)node, str);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QUERY_NODE_ORDER_BY_EXPR: {
|
||||||
|
orderByExprToStr((SOrderByExprNode*)node, str);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
exprNodeToStr(node, str, isProject);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nodeListToStr(const SNodeList* nodelist, const string& prefix, string& str, bool isProject = false) {
|
void nodeListToStr(const SNodeList* nodelist, const string& prefix, string& str, bool isProject = false, const string& sep = string("\n")) {
|
||||||
SNode* node = nullptr;
|
SNode* node = nullptr;
|
||||||
FOREACH(node, nodelist) {
|
FOREACH(node, nodelist) {
|
||||||
str.append(prefix);
|
str.append(prefix);
|
||||||
nodeToStr(node, str, isProject);
|
nodeToStr(node, str, isProject);
|
||||||
str.append("\n");
|
str.append(sep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,8 +307,20 @@ private:
|
||||||
}
|
}
|
||||||
str.append("\n");
|
str.append("\n");
|
||||||
nodeListToStr(select->pProjectionList, prefix + "\t", str, true);
|
nodeListToStr(select->pProjectionList, prefix + "\t", str, true);
|
||||||
str.append("\n" + prefix + "FROM\n");
|
str.append(prefix + "FROM\n");
|
||||||
tableToStr(select->pFromTable, prefix + "\t", str);
|
tableToStr(select->pFromTable, prefix + "\t", str);
|
||||||
|
if (nullptr != select->pWhere) {
|
||||||
|
str.append("\n" + prefix + "WHERE\n\t");
|
||||||
|
nodeToStr(select->pWhere, str, false);
|
||||||
|
}
|
||||||
|
if (nullptr != select->pGroupByList) {
|
||||||
|
str.append("\n" + prefix + "GROUP BY\n");
|
||||||
|
nodeListToStr(select->pGroupByList, prefix + "\t", str, true);
|
||||||
|
}
|
||||||
|
if (nullptr != select->pOrderByList) {
|
||||||
|
str.append(prefix + "ORDER BY\n");
|
||||||
|
nodeListToStr(select->pOrderByList, prefix + "\t", str, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void selectToSql(const SNode* node, string& sql) {
|
void selectToSql(const SNode* node, string& sql) {
|
||||||
|
@ -332,15 +386,23 @@ private:
|
||||||
case OP_TYPE_SUB:
|
case OP_TYPE_SUB:
|
||||||
return " - ";
|
return " - ";
|
||||||
case OP_TYPE_MULTI:
|
case OP_TYPE_MULTI:
|
||||||
|
return " * ";
|
||||||
case OP_TYPE_DIV:
|
case OP_TYPE_DIV:
|
||||||
|
return " / ";
|
||||||
case OP_TYPE_MOD:
|
case OP_TYPE_MOD:
|
||||||
|
return " % ";
|
||||||
case OP_TYPE_GREATER_THAN:
|
case OP_TYPE_GREATER_THAN:
|
||||||
|
return " > ";
|
||||||
case OP_TYPE_GREATER_EQUAL:
|
case OP_TYPE_GREATER_EQUAL:
|
||||||
|
return " >= ";
|
||||||
case OP_TYPE_LOWER_THAN:
|
case OP_TYPE_LOWER_THAN:
|
||||||
|
return " < ";
|
||||||
case OP_TYPE_LOWER_EQUAL:
|
case OP_TYPE_LOWER_EQUAL:
|
||||||
|
return " <= ";
|
||||||
case OP_TYPE_EQUAL:
|
case OP_TYPE_EQUAL:
|
||||||
return " = ";
|
return " = ";
|
||||||
case OP_TYPE_NOT_EQUAL:
|
case OP_TYPE_NOT_EQUAL:
|
||||||
|
return " != ";
|
||||||
case OP_TYPE_IN:
|
case OP_TYPE_IN:
|
||||||
case OP_TYPE_NOT_IN:
|
case OP_TYPE_NOT_IN:
|
||||||
case OP_TYPE_LIKE:
|
case OP_TYPE_LIKE:
|
||||||
|
@ -454,6 +516,23 @@ TEST_F(NewParserTest, selectExpression) {
|
||||||
TEST_F(NewParserTest, selectClause) {
|
TEST_F(NewParserTest, selectClause) {
|
||||||
setDatabase("root", "test");
|
setDatabase("root", "test");
|
||||||
|
|
||||||
|
// GROUP BY clause
|
||||||
|
bind("SELECT count(*), c2 cnt FROM t1 WHERE c1 > 0");
|
||||||
|
ASSERT_TRUE(run());
|
||||||
|
|
||||||
|
bind("SELECT count(*), c2 cnt FROM t1 WHERE c1 > 0 GROUP BY c2");
|
||||||
|
ASSERT_TRUE(run());
|
||||||
|
|
||||||
|
bind("SELECT count(*) cnt FROM t1 WHERE c1 > 0 GROUP BY c2 HAVING count(c1) > 10");
|
||||||
|
ASSERT_TRUE(run());
|
||||||
|
|
||||||
|
bind("SELECT count(*), c1, c2 + 10, c1 + c2 cnt FROM t1 WHERE c1 > 0 GROUP BY c2, c1");
|
||||||
|
ASSERT_TRUE(run());
|
||||||
|
|
||||||
|
bind("SELECT count(*), c1 + 10, c2 cnt FROM t1 WHERE c1 > 0 GROUP BY c1 + 10, c2");
|
||||||
|
ASSERT_TRUE(run());
|
||||||
|
|
||||||
|
// ORDER BY clause
|
||||||
bind("SELECT count(*) cnt FROM t1 WHERE c1 > 0 GROUP BY c2 ORDER BY cnt");
|
bind("SELECT count(*) cnt FROM t1 WHERE c1 > 0 GROUP BY c2 ORDER BY cnt");
|
||||||
ASSERT_TRUE(run());
|
ASSERT_TRUE(run());
|
||||||
|
|
||||||
|
@ -480,15 +559,65 @@ TEST_F(NewParserTest, selectSyntaxError) {
|
||||||
TEST_F(NewParserTest, selectSemanticError) {
|
TEST_F(NewParserTest, selectSemanticError) {
|
||||||
setDatabase("root", "test");
|
setDatabase("root", "test");
|
||||||
|
|
||||||
bind("SELECT * FROM t10");
|
// TSDB_CODE_PAR_INVALID_COLUMN
|
||||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_FAILED));
|
|
||||||
|
|
||||||
bind("SELECT c1, c3 FROM t1");
|
bind("SELECT c1, c3 FROM t1");
|
||||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_FAILED));
|
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_INVALID_COLUMN));
|
||||||
|
|
||||||
|
bind("SELECT t1.c1, t1.c3 FROM t1");
|
||||||
|
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_INVALID_COLUMN));
|
||||||
|
|
||||||
|
// TSDB_CODE_PAR_TABLE_NOT_EXIST
|
||||||
|
bind("SELECT * FROM t10");
|
||||||
|
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_TABLE_NOT_EXIST));
|
||||||
|
|
||||||
|
bind("SELECT * FROM test.t10");
|
||||||
|
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_TABLE_NOT_EXIST));
|
||||||
|
|
||||||
|
// TSDB_CODE_PAR_AMBIGUOUS_COLUMN
|
||||||
bind("SELECT c2 FROM t1 tt1, t1 tt2 WHERE tt1.c1 = tt2.c1");
|
bind("SELECT c2 FROM t1 tt1, t1 tt2 WHERE tt1.c1 = tt2.c1");
|
||||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_FAILED));
|
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_AMBIGUOUS_COLUMN));
|
||||||
|
|
||||||
|
// TSDB_CODE_PAR_WRONG_VALUE_TYPE
|
||||||
|
bind("SELECT 10n FROM t1");
|
||||||
|
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_WRONG_VALUE_TYPE));
|
||||||
|
|
||||||
|
bind("SELECT TIMESTAMP '2010' FROM t1");
|
||||||
|
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_WRONG_VALUE_TYPE));
|
||||||
|
|
||||||
|
// TSDB_CODE_PAR_INVALID_FUNTION
|
||||||
|
bind("SELECT cnt(*) FROM t1");
|
||||||
|
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_INVALID_FUNTION));
|
||||||
|
|
||||||
|
// TSDB_CODE_PAR_FUNTION_PARA_NUM
|
||||||
|
// TSDB_CODE_PAR_FUNTION_PARA_TYPE
|
||||||
|
|
||||||
|
// TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION
|
||||||
|
bind("SELECT c2 FROM t1 tt1 JOIN t1 tt2 ON count(*) > 0");
|
||||||
|
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION));
|
||||||
|
|
||||||
bind("SELECT c2 FROM t1 where count(*) > 0");
|
bind("SELECT c2 FROM t1 where count(*) > 0");
|
||||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_FAILED));
|
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION));
|
||||||
|
|
||||||
|
bind("SELECT c2 FROM t1 GROUP BY count(*)");
|
||||||
|
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION));
|
||||||
|
|
||||||
|
// TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT
|
||||||
|
bind("SELECT c2 FROM t1 ORDER BY 0");
|
||||||
|
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT));
|
||||||
|
|
||||||
|
bind("SELECT c2 FROM t1 ORDER BY 2");
|
||||||
|
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT));
|
||||||
|
|
||||||
|
//TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION
|
||||||
|
bind("SELECT count(*) cnt FROM t1 HAVING c1 > 0");
|
||||||
|
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION));
|
||||||
|
|
||||||
|
bind("SELECT count(*) cnt FROM t1 GROUP BY c2 HAVING c1 > 0");
|
||||||
|
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION));
|
||||||
|
|
||||||
|
bind("SELECT count(*), c1 cnt FROM t1 GROUP BY c2 HAVING c2 > 0");
|
||||||
|
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION));
|
||||||
|
|
||||||
|
bind("SELECT count(*) cnt FROM t1 GROUP BY c2 HAVING c2 > 0 ORDER BY c1");
|
||||||
|
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION));
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,18 +20,22 @@ typedef enum ETraversalOrder {
|
||||||
TRAVERSAL_POSTORDER
|
TRAVERSAL_POSTORDER
|
||||||
} ETraversalOrder;
|
} ETraversalOrder;
|
||||||
|
|
||||||
static bool walkList(SNodeList* pNodeList, ETraversalOrder order, FQueryNodeWalker walker, void* pContext);
|
static EDealRes walkList(SNodeList* pNodeList, ETraversalOrder order, FQueryNodeWalker walker, void* pContext);
|
||||||
|
|
||||||
static bool walkNode(SNode* pNode, ETraversalOrder order, FQueryNodeWalker walker, void* pContext) {
|
static EDealRes walkNode(SNode* pNode, ETraversalOrder order, FQueryNodeWalker walker, void* pContext) {
|
||||||
if (NULL == pNode) {
|
if (NULL == pNode) {
|
||||||
return true;
|
return DEAL_RES_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TRAVERSAL_PREORDER == order && !walker(pNode, pContext)) {
|
EDealRes res = DEAL_RES_CONTINUE;
|
||||||
return false;
|
|
||||||
|
if (TRAVERSAL_PREORDER == order) {
|
||||||
|
res = walker(pNode, pContext);
|
||||||
|
if (DEAL_RES_CONTINUE != res) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool res = true;
|
|
||||||
switch (nodeType(pNode)) {
|
switch (nodeType(pNode)) {
|
||||||
case QUERY_NODE_COLUMN:
|
case QUERY_NODE_COLUMN:
|
||||||
case QUERY_NODE_VALUE:
|
case QUERY_NODE_VALUE:
|
||||||
|
@ -41,7 +45,7 @@ static bool walkNode(SNode* pNode, ETraversalOrder order, FQueryNodeWalker walke
|
||||||
case QUERY_NODE_OPERATOR: {
|
case QUERY_NODE_OPERATOR: {
|
||||||
SOperatorNode* pOpNode = (SOperatorNode*)pNode;
|
SOperatorNode* pOpNode = (SOperatorNode*)pNode;
|
||||||
res = walkNode(pOpNode->pLeft, order, walker, pContext);
|
res = walkNode(pOpNode->pLeft, order, walker, pContext);
|
||||||
if (res) {
|
if (DEAL_RES_ERROR != res) {
|
||||||
res = walkNode(pOpNode->pRight, order, walker, pContext);
|
res = walkNode(pOpNode->pRight, order, walker, pContext);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -61,10 +65,10 @@ static bool walkNode(SNode* pNode, ETraversalOrder order, FQueryNodeWalker walke
|
||||||
case QUERY_NODE_JOIN_TABLE: {
|
case QUERY_NODE_JOIN_TABLE: {
|
||||||
SJoinTableNode* pJoinTableNode = (SJoinTableNode*)pNode;
|
SJoinTableNode* pJoinTableNode = (SJoinTableNode*)pNode;
|
||||||
res = walkNode(pJoinTableNode->pLeft, order, walker, pContext);
|
res = walkNode(pJoinTableNode->pLeft, order, walker, pContext);
|
||||||
if (res) {
|
if (DEAL_RES_ERROR != res) {
|
||||||
res = walkNode(pJoinTableNode->pRight, order, walker, pContext);
|
res = walkNode(pJoinTableNode->pRight, order, walker, pContext);
|
||||||
}
|
}
|
||||||
if (res) {
|
if (DEAL_RES_ERROR != res) {
|
||||||
res = walkNode(pJoinTableNode->pOnCond, order, walker, pContext);
|
res = walkNode(pJoinTableNode->pOnCond, order, walker, pContext);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -84,13 +88,13 @@ static bool walkNode(SNode* pNode, ETraversalOrder order, FQueryNodeWalker walke
|
||||||
case QUERY_NODE_INTERVAL_WINDOW: {
|
case QUERY_NODE_INTERVAL_WINDOW: {
|
||||||
SIntervalWindowNode* pInterval = (SIntervalWindowNode*)pNode;
|
SIntervalWindowNode* pInterval = (SIntervalWindowNode*)pNode;
|
||||||
res = walkNode(pInterval->pInterval, order, walker, pContext);
|
res = walkNode(pInterval->pInterval, order, walker, pContext);
|
||||||
if (res) {
|
if (DEAL_RES_ERROR != res) {
|
||||||
res = walkNode(pInterval->pOffset, order, walker, pContext);
|
res = walkNode(pInterval->pOffset, order, walker, pContext);
|
||||||
}
|
}
|
||||||
if (res) {
|
if (DEAL_RES_ERROR != res) {
|
||||||
res = walkNode(pInterval->pSliding, order, walker, pContext);
|
res = walkNode(pInterval->pSliding, order, walker, pContext);
|
||||||
}
|
}
|
||||||
if (res) {
|
if (DEAL_RES_ERROR != res) {
|
||||||
res = walkNode(pInterval->pFill, order, walker, pContext);
|
res = walkNode(pInterval->pFill, order, walker, pContext);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -108,21 +112,21 @@ static bool walkNode(SNode* pNode, ETraversalOrder order, FQueryNodeWalker walke
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res && TRAVERSAL_POSTORDER == order) {
|
if (DEAL_RES_ERROR != res && TRAVERSAL_POSTORDER == order) {
|
||||||
res = walker(pNode, pContext);
|
res = walker(pNode, pContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool walkList(SNodeList* pNodeList, ETraversalOrder order, FQueryNodeWalker walker, void* pContext) {
|
static EDealRes walkList(SNodeList* pNodeList, ETraversalOrder order, FQueryNodeWalker walker, void* pContext) {
|
||||||
SNode* node;
|
SNode* node;
|
||||||
FOREACH(node, pNodeList) {
|
FOREACH(node, pNodeList) {
|
||||||
if (!walkNode(node, order, walker, pContext)) {
|
if (DEAL_RES_ERROR == walkNode(node, order, walker, pContext)) {
|
||||||
return false;
|
return DEAL_RES_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return DEAL_RES_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nodesWalkNode(SNode* pNode, FQueryNodeWalker walker, void* pContext) {
|
void nodesWalkNode(SNode* pNode, FQueryNodeWalker walker, void* pContext) {
|
||||||
|
@ -140,7 +144,3 @@ void nodesWalkNodePostOrder(SNode* pNode, FQueryNodeWalker walker, void* pContex
|
||||||
void nodesWalkListPostOrder(SNodeList* pList, FQueryNodeWalker walker, void* pContext) {
|
void nodesWalkListPostOrder(SNodeList* pList, FQueryNodeWalker walker, void* pContext) {
|
||||||
(void)walkList(pList, TRAVERSAL_POSTORDER, walker, pContext);
|
(void)walkList(pList, TRAVERSAL_POSTORDER, walker, pContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nodesWalkStmt(SNode* pNode, FQueryNodeWalker walker, void* pContext) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -76,7 +76,7 @@ SNode* nodesMakeNode(ENodeType type) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool destroyNode(SNode* pNode, void* pContext) {
|
static EDealRes destroyNode(SNode* pNode, void* pContext) {
|
||||||
switch (nodeType(pNode)) {
|
switch (nodeType(pNode)) {
|
||||||
case QUERY_NODE_VALUE:
|
case QUERY_NODE_VALUE:
|
||||||
tfree(((SValueNode*)pNode)->literal);
|
tfree(((SValueNode*)pNode)->literal);
|
||||||
|
@ -85,6 +85,7 @@ static bool destroyNode(SNode* pNode, void* pContext) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tfree(pNode);
|
tfree(pNode);
|
||||||
|
return DEAL_RES_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nodesDestroyNode(SNode* pNode) {
|
void nodesDestroyNode(SNode* pNode) {
|
||||||
|
@ -116,9 +117,23 @@ SNodeList* nodesListAppend(SNodeList* pList, SNode* pNode) {
|
||||||
pList->pTail->pNext = p;
|
pList->pTail->pNext = p;
|
||||||
}
|
}
|
||||||
pList->pTail = p;
|
pList->pTail = p;
|
||||||
|
++(pList->length);
|
||||||
return pList;
|
return pList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SListCell* nodesListErase(SNodeList* pList, SListCell* pCell) {
|
||||||
|
if (NULL == pCell->pPrev) {
|
||||||
|
pList->pHead = pCell->pNext;
|
||||||
|
} else {
|
||||||
|
pCell->pPrev->pNext = pCell->pNext;
|
||||||
|
pCell->pNext->pPrev = pCell->pPrev;
|
||||||
|
}
|
||||||
|
SListCell* pNext = pCell->pNext;
|
||||||
|
tfree(pCell);
|
||||||
|
--(pList->length);
|
||||||
|
return pNext;
|
||||||
|
}
|
||||||
|
|
||||||
SNode* nodesListGetNode(SNodeList* pList, int32_t index) {
|
SNode* nodesListGetNode(SNodeList* pList, int32_t index) {
|
||||||
SNode* node;
|
SNode* node;
|
||||||
FOREACH(node, pList) {
|
FOREACH(node, pList) {
|
||||||
|
@ -137,6 +152,11 @@ void nodesDestroyList(SNodeList* pList) {
|
||||||
tfree(pList);
|
tfree(pList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool nodesIsExprNode(const SNode* pNode) {
|
||||||
|
ENodeType type = nodeType(pNode);
|
||||||
|
return (QUERY_NODE_COLUMN == type || QUERY_NODE_VALUE == type || QUERY_NODE_OPERATOR == type || QUERY_NODE_FUNCTION == type);
|
||||||
|
}
|
||||||
|
|
||||||
bool nodesIsArithmeticOp(const SOperatorNode* pOp) {
|
bool nodesIsArithmeticOp(const SOperatorNode* pOp) {
|
||||||
switch (pOp->opType) {
|
switch (pOp->opType) {
|
||||||
case OP_TYPE_ADD:
|
case OP_TYPE_ADD:
|
||||||
|
|
Loading…
Reference in New Issue