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)
|
||||
|
||||
// only be use in FOREACH
|
||||
#define ERASE_NODE(list) \
|
||||
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 ERASE_NODE(list) cell = nodesListErase(list, cell);
|
||||
|
||||
#define REPLACE_NODE(newNode) cell->pNode = (SNode*)(newNode)
|
||||
|
||||
|
@ -343,18 +334,22 @@ void nodesDestroyNode(SNode* pNode);
|
|||
|
||||
SNodeList* nodesMakeList();
|
||||
SNodeList* nodesListAppend(SNodeList* pList, SNode* pNode);
|
||||
SListCell* nodesListErase(SNodeList* pList, SListCell* pCell);
|
||||
SNode* nodesListGetNode(SNodeList* pList, int32_t index);
|
||||
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 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);
|
||||
|
||||
bool nodesEqualNode(const SNode* a, const SNode* b);
|
||||
|
||||
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 nodesStringToNode(const char* pStr, SNode** pNode);
|
||||
|
||||
bool nodesIsExprNode(const SNode* pNode);
|
||||
|
||||
bool nodesIsArithmeticOp(const SOperatorNode* pOp);
|
||||
bool nodesIsComparisonOp(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_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_GROUPBY_LACK_EXPRESSION TAOS_DEF_ERROR_CODE(0, 0x260A) //Not a GROUP BY expression
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ SNode* createSessionWindowNode(SAstCreateContext* pCxt, SNode* pCol, const SToke
|
|||
SNode* createStateWindowNode(SAstCreateContext* pCxt, SNode* pCol);
|
||||
SNode* createIntervalWindowNode(SAstCreateContext* pCxt, SNode* pInterval, SNode* pOffset, SNode* pSliding, SNode* pFill);
|
||||
SNode* createFillNode(SAstCreateContext* pCxt, EFillMode mode, SNode* pValues);
|
||||
SNode* createGroupingSetNode(SAstCreateContext* pCxt, SNode* pNode);
|
||||
|
||||
SNode* addWhereClause(SAstCreateContext* pCxt, SNode* pStmt, SNode* pWhere);
|
||||
SNode* addPartitionByClause(SAstCreateContext* pCxt, SNode* pStmt, SNodeList* pPartitionByList);
|
||||
|
|
|
@ -238,6 +238,7 @@ joined_table(A) ::=
|
|||
|
||||
%type join_type { EJoinType }
|
||||
%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; }
|
||||
|
||||
/************************************************ query_specification *************************************************/
|
||||
|
@ -315,7 +316,12 @@ fill_mode(A) ::= NEXT.
|
|||
%type group_by_clause_opt { SNodeList* }
|
||||
%destructor group_by_clause_opt { PARSER_DESTRUCTOR_TRACE; nodesDestroyList($$); }
|
||||
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) ::= 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);
|
||||
orderByExpr->pExpr = pExpr;
|
||||
orderByExpr->order = order;
|
||||
if (NULL_ORDER_DEFAULT == nullOrder) {
|
||||
nullOrder = (ORDER_ASC == order ? NULL_ORDER_FIRST : NULL_ORDER_LAST);
|
||||
}
|
||||
orderByExpr->nullOrder = nullOrder;
|
||||
return (SNode*)orderByExpr;
|
||||
}
|
||||
|
@ -279,6 +282,15 @@ SNode* createFillNode(SAstCreateContext* pCxt, EFillMode mode, SNode* pValues) {
|
|||
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) {
|
||||
strncpy(((SExprNode*)pNode)->aliasName, pAlias->z, pAlias->n);
|
||||
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;
|
||||
case TK_JOIN:
|
||||
return NEW_TK_JOIN;
|
||||
// case TK_ON:
|
||||
// return NEW_TK_ON;
|
||||
// case TK_INNER:
|
||||
// return NEW_TK_INNER;
|
||||
// case TK_PARTITION:
|
||||
// return NEW_TK_PARTITION;
|
||||
case TK_SESSION:
|
||||
|
@ -163,6 +159,8 @@ static uint32_t toNewTokenId(uint32_t tokenId) {
|
|||
case TK_OFFSET:
|
||||
return NEW_TK_OFFSET;
|
||||
case TK_SPACE:
|
||||
case NEW_TK_ON:
|
||||
case NEW_TK_INNER:
|
||||
break;
|
||||
default:
|
||||
printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!tokenId = %d\n", tokenId);
|
||||
|
@ -248,6 +246,10 @@ typedef enum ESqlClause {
|
|||
} ESqlClause;
|
||||
|
||||
static bool afterGroupBy(ESqlClause clause) {
|
||||
return clause > SQL_CLAUSE_GROUP_BY;
|
||||
}
|
||||
|
||||
static bool beforeHaving(ESqlClause clause) {
|
||||
return clause < SQL_CLAUSE_HAVING;
|
||||
}
|
||||
|
||||
|
@ -259,7 +261,7 @@ typedef struct STranslateContext {
|
|||
SArray* pNsLevel; // element is SArray*, the element of this subarray is STableNode*
|
||||
int32_t currLevel;
|
||||
ESqlClause currClause;
|
||||
void* pExt;
|
||||
SSelectStmt* pCurrStmt;
|
||||
} STranslateContext;
|
||||
|
||||
static int32_t translateSubquery(STranslateContext* pCxt, SNode* pNode);
|
||||
|
@ -284,6 +286,8 @@ static char* getSyntaxErrFormat(int32_t errCode) {
|
|||
return "There mustn't be aggregation";
|
||||
case TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT:
|
||||
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:
|
||||
return "Unknown error";
|
||||
}
|
||||
|
@ -415,7 +419,7 @@ static bool findAndSetColumn(SColumnNode* pCol, const STableNode* pTable) {
|
|||
return found;
|
||||
}
|
||||
|
||||
static bool translateColumnWithPrefix(STranslateContext* pCxt, SColumnNode* pCol) {
|
||||
static EDealRes translateColumnWithPrefix(STranslateContext* pCxt, SColumnNode* pCol) {
|
||||
SArray* pTables = taosArrayGetP(pCxt->pNsLevel, pCxt->currLevel);
|
||||
size_t nums = taosArrayGetSize(pTables);
|
||||
for (size_t i = 0; i < nums; ++i) {
|
||||
|
@ -425,13 +429,13 @@ static bool translateColumnWithPrefix(STranslateContext* pCxt, SColumnNode* pCol
|
|||
break;
|
||||
}
|
||||
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);
|
||||
size_t nums = taosArrayGetSize(pTables);
|
||||
bool found = false;
|
||||
|
@ -440,20 +444,20 @@ static bool translateColumnWithoutPrefix(STranslateContext* pCxt, SColumnNode* p
|
|||
if (findAndSetColumn(pCol, pTable)) {
|
||||
if (found) {
|
||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_AMBIGUOUS_COLUMN, pCol->colName);
|
||||
return false;
|
||||
return DEAL_RES_ERROR;
|
||||
}
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
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) {
|
||||
SNodeList* pProjectionList = pCxt->pExt;
|
||||
SNodeList* pProjectionList = pCxt->pCurrStmt->pProjectionList;
|
||||
SNode* pNode;
|
||||
FOREACH(pNode, pProjectionList) {
|
||||
SExprNode* pExpr = (SExprNode*)pNode;
|
||||
|
@ -465,10 +469,10 @@ static bool translateColumnUseAlias(STranslateContext* pCxt, SColumnNode* pCol)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool translateColumn(STranslateContext* pCxt, SColumnNode* pCol) {
|
||||
static EDealRes translateColumn(STranslateContext* pCxt, SColumnNode* pCol) {
|
||||
// count(*)/first(*)/last(*)
|
||||
if (0 == strcmp(pCol->colName, "*")) {
|
||||
return true;
|
||||
return DEAL_RES_CONTINUE;
|
||||
}
|
||||
if ('\0' != pCol->tableAlias[0]) {
|
||||
return translateColumnWithPrefix(pCxt, pCol);
|
||||
|
@ -477,7 +481,7 @@ static bool translateColumn(STranslateContext* pCxt, SColumnNode* pCol) {
|
|||
if (SQL_CLAUSE_ORDER_BY == pCxt->currClause) {
|
||||
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) {
|
||||
|
@ -500,12 +504,12 @@ static int32_t trimStringCopy(const char* src, int32_t len, char* dst) {
|
|||
return j;
|
||||
}
|
||||
|
||||
static bool translateValue(STranslateContext* pCxt, SValueNode* pVal) {
|
||||
static EDealRes translateValue(STranslateContext* pCxt, SValueNode* pVal) {
|
||||
if (pVal->isDuration) {
|
||||
char unit = 0;
|
||||
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);
|
||||
return false;
|
||||
return DEAL_RES_ERROR;
|
||||
}
|
||||
} else {
|
||||
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) {
|
||||
tfree(tmp);
|
||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, pVal->literal);
|
||||
return false;
|
||||
return DEAL_RES_ERROR;
|
||||
}
|
||||
tfree(tmp);
|
||||
break;
|
||||
|
@ -565,55 +569,56 @@ static bool translateValue(STranslateContext* pCxt, SValueNode* pVal) {
|
|||
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 rdt = ((SExprNode*)(pOp->pRight))->resType;
|
||||
if (nodesIsArithmeticOp(pOp)) {
|
||||
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) {
|
||||
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.bytes = tDataTypes[TSDB_DATA_TYPE_DOUBLE].bytes;
|
||||
return true;
|
||||
} else if (nodesIsComparisonOp(pOp)) {
|
||||
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) {
|
||||
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.bytes = tDataTypes[TSDB_DATA_TYPE_BOOL].bytes;
|
||||
return true;
|
||||
} else {
|
||||
// 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)) {
|
||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_INVALID_FUNTION, pFunc->functionName);
|
||||
return false;
|
||||
return DEAL_RES_ERROR;
|
||||
}
|
||||
int32_t code = fmGetFuncResultType(pFunc);
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
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);
|
||||
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;
|
||||
switch (nodeType(pNode)) {
|
||||
case QUERY_NODE_COLUMN:
|
||||
|
@ -625,11 +630,11 @@ static bool doTranslateExpr(SNode* pNode, void* pContext) {
|
|||
case QUERY_NODE_FUNCTION:
|
||||
return translateFunction(pCxt, (SFunctionNode*)pNode);
|
||||
case QUERY_NODE_TEMP_TABLE:
|
||||
return translateSubquery(pCxt, ((STempTableNode*)pNode)->pSubquery);
|
||||
return translateExprSubquery(pCxt, ((STempTableNode*)pNode)->pSubquery);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
return DEAL_RES_CONTINUE;
|
||||
}
|
||||
|
||||
static int32_t translateExpr(STranslateContext* pCxt, SNode* pNode) {
|
||||
|
@ -642,6 +647,41 @@ static int32_t translateExprList(STranslateContext* pCxt, SNodeList* pList) {
|
|||
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) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
switch (nodeType(pTable)) {
|
||||
|
@ -732,12 +772,13 @@ static bool translateOrderByPosition(STranslateContext* pCxt, SNodeList* pProjec
|
|||
*pOther = false;
|
||||
SNode* pNode;
|
||||
FOREACH(pNode, pOrderByList) {
|
||||
if (QUERY_NODE_VALUE == nodeType(pNode)) {
|
||||
SValueNode* pVal = (SValueNode*)pNode;
|
||||
if (translateValue(pCxt, pVal)) {
|
||||
SNode* pExpr = ((SOrderByExprNode*)pNode)->pExpr;
|
||||
if (QUERY_NODE_VALUE == nodeType(pExpr)) {
|
||||
SValueNode* pVal = (SValueNode*)pExpr;
|
||||
if (!translateValue(pCxt, pVal)) {
|
||||
return false;
|
||||
}
|
||||
int32_t pos = getPositionValue((SValueNode*)pNode);
|
||||
int32_t pos = getPositionValue((SValueNode*)pExpr);
|
||||
if (pos < 0) {
|
||||
ERASE_NODE(pOrderByList);
|
||||
nodesDestroyNode(pNode);
|
||||
|
@ -747,9 +788,9 @@ static bool translateOrderByPosition(STranslateContext* pCxt, SNodeList* pProjec
|
|||
return false;
|
||||
} else {
|
||||
SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN);
|
||||
setColumnInfoByExpr(NULL, (SExprNode*)nodesListGetNode(pProjectionList, pos), pCol);
|
||||
REPLACE_NODE(pCol);
|
||||
nodesDestroyNode(pNode);
|
||||
setColumnInfoByExpr(NULL, (SExprNode*)nodesListGetNode(pProjectionList, pos - 1), pCol);
|
||||
((SOrderByExprNode*)pNode)->pExpr = (SNode*)pCol;
|
||||
nodesDestroyNode(pExpr);
|
||||
}
|
||||
} else {
|
||||
*pOther = true;
|
||||
|
@ -758,17 +799,20 @@ static bool translateOrderByPosition(STranslateContext* pCxt, SNodeList* pProjec
|
|||
return true;
|
||||
}
|
||||
|
||||
static int32_t translateOrderBy(STranslateContext* pCxt, SNodeList* pProjectionList, SNodeList* pOrderByList) {
|
||||
static int32_t translateOrderBy(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||
bool other;
|
||||
if (!translateOrderByPosition(pCxt, pProjectionList, pOrderByList, &other)) {
|
||||
if (!translateOrderByPosition(pCxt, pSelect->pProjectionList, pSelect->pOrderByList, &other)) {
|
||||
return pCxt->errCode;
|
||||
}
|
||||
if (!other) {
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
pCxt->currClause = SQL_CLAUSE_ORDER_BY;
|
||||
pCxt->pExt = pProjectionList;
|
||||
return translateExprList(pCxt, pOrderByList);
|
||||
int32_t code = translateExprList(pCxt, pSelect->pOrderByList);
|
||||
if (TSDB_CODE_SUCCESS == code && NULL != pSelect->pGroupByList) {
|
||||
code = checkExprListForGroupBy(pCxt, pSelect->pOrderByList);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
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;
|
||||
code = translateExprList(pCxt, pSelect->pProjectionList);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code && NULL != pSelect->pGroupByList) {
|
||||
code = checkExprListForGroupBy(pCxt, pSelect->pProjectionList);
|
||||
}
|
||||
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;
|
||||
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) {
|
||||
|
@ -818,8 +872,8 @@ static int32_t translateFrom(STranslateContext* pCxt, SNode* pTable) {
|
|||
// } SSelectStmt;
|
||||
|
||||
static int32_t translateSelect(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
code = translateFrom(pCxt, pSelect->pFromTable);
|
||||
pCxt->pCurrStmt = pSelect;
|
||||
int32_t code = translateFrom(pCxt, pSelect->pFromTable);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = translateWhere(pCxt, pSelect->pWhere);
|
||||
}
|
||||
|
@ -833,15 +887,14 @@ static int32_t translateSelect(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
|||
code = translateGroupBy(pCxt, pSelect->pGroupByList);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = translateHaving(pCxt, pSelect->pHaving);
|
||||
code = translateHaving(pCxt, pSelect);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = translateSelectList(pCxt, pSelect);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -860,11 +913,11 @@ static int32_t translateQuery(STranslateContext* pCxt, SNode* pNode) {
|
|||
static int32_t translateSubquery(STranslateContext* pCxt, SNode* pNode) {
|
||||
++(pCxt->currLevel);
|
||||
ESqlClause currClause = pCxt->currClause;
|
||||
void* pExt = pCxt->pExt;
|
||||
SSelectStmt* pCurrStmt = pCxt->pCurrStmt;
|
||||
int32_t code = translateQuery(pCxt, pNode);
|
||||
--(pCxt->currLevel);
|
||||
pCxt->currClause = currClause;
|
||||
pCxt->pExt = pExt;
|
||||
pCxt->pCurrStmt = pCurrStmt;
|
||||
return code;
|
||||
}
|
||||
|
||||
|
|
|
@ -228,6 +228,8 @@ static SKeyword keywordTable[] = {
|
|||
{"AGGREGATE", TK_AGGREGATE},
|
||||
{"BUFSIZE", TK_BUFSIZE},
|
||||
{"PORT", TK_PORT},
|
||||
{"INNER", NEW_TK_INNER},
|
||||
{"ON", NEW_TK_ON},
|
||||
};
|
||||
|
||||
static const char isIdChar[] = {
|
||||
|
|
|
@ -53,8 +53,8 @@ protected:
|
|||
code = doTranslate(&cxt_, &query_);
|
||||
// cout << "doTranslate return " << code << endl;
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
cout << "sql:[" << cxt_.pSql << "] code:" << tstrerror(code) << ", msg:" << errMagBuf_ << endl;
|
||||
return (TSDB_CODE_SUCCESS != translateCode);
|
||||
cout << "sql:[" << cxt_.pSql << "] code:" << code << ", " << translateCode << ", msg:" << errMagBuf_ << endl;
|
||||
return (code == translateCode);
|
||||
}
|
||||
if (NULL != query_.pRoot && QUERY_NODE_SELECT_STMT == nodeType(query_.pRoot)) {
|
||||
cout << "input sql : [" << cxt_.pSql << "]" << endl;
|
||||
|
@ -71,6 +71,24 @@ protected:
|
|||
private:
|
||||
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) {
|
||||
switch (dt.type) {
|
||||
case TSDB_DATA_TYPE_NULL:
|
||||
|
@ -119,7 +137,7 @@ private:
|
|||
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) {
|
||||
case TSDB_DATA_TYPE_NULL:
|
||||
str.append("null");
|
||||
|
@ -160,20 +178,9 @@ private:
|
|||
default:
|
||||
break;
|
||||
}
|
||||
str.append(" [" + dataTypeToStr(pVal->node.resType) + "]");
|
||||
if (isProject) {
|
||||
str.append(" AS " + string(pVal->node.aliasName));
|
||||
}
|
||||
}
|
||||
|
||||
void nodeToStr(const SNode* node, string& str, bool isProject) {
|
||||
if (nullptr == node) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (nodeType(node)) {
|
||||
case QUERY_NODE_COLUMN: {
|
||||
SColumnNode* pCol = (SColumnNode*)node;
|
||||
void columnNodeToStr(const SColumnNode* pCol, string& str) {
|
||||
if ('\0' != pCol->dbName[0]) {
|
||||
str.append(pCol->dbName);
|
||||
str.append(".");
|
||||
|
@ -183,38 +190,73 @@ private:
|
|||
str.append(".");
|
||||
}
|
||||
str.append(pCol->colName);
|
||||
str.append(" [" + dataTypeToStr(pCol->node.resType) + "]");
|
||||
if (isProject) {
|
||||
str.append(" AS " + string(pCol->node.aliasName));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QUERY_NODE_VALUE: {
|
||||
valueNodeToStr((SValueNode*)node, str, isProject);
|
||||
break;
|
||||
}
|
||||
case QUERY_NODE_OPERATOR: {
|
||||
SOperatorNode* pOp = (SOperatorNode*)node;
|
||||
|
||||
void operatorToStr(const SOperatorNode* pOp, string& str) {
|
||||
nodeToStr(pOp->pLeft, str, false);
|
||||
str.append(opTypeToStr(pOp->opType));
|
||||
nodeToStr(pOp->pRight, str, false);
|
||||
str.append(" [" + dataTypeToStr(pOp->node.resType) + "]");
|
||||
if (isProject) {
|
||||
str.append(" AS " + string(pOp->node.aliasName));
|
||||
}
|
||||
|
||||
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) {
|
||||
if (nullptr == node) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (nodeType(node)) {
|
||||
case QUERY_NODE_COLUMN: {
|
||||
columnNodeToStr((SColumnNode*)node, str);
|
||||
break;
|
||||
}
|
||||
case QUERY_NODE_VALUE: {
|
||||
valueNodeToStr((SValueNode*)node, str);
|
||||
break;
|
||||
}
|
||||
case QUERY_NODE_OPERATOR: {
|
||||
operatorToStr((SOperatorNode*)node, str);
|
||||
break;
|
||||
}
|
||||
case QUERY_NODE_FUNCTION: {
|
||||
functionToStr((SFunctionNode*)node, str);
|
||||
break;
|
||||
}
|
||||
case QUERY_NODE_GROUPING_SET: {
|
||||
groupingSetToStr((SGroupingSetNode*)node, str);
|
||||
break;
|
||||
}
|
||||
case QUERY_NODE_ORDER_BY_EXPR: {
|
||||
orderByExprToStr((SOrderByExprNode*)node, str);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
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;
|
||||
FOREACH(node, nodelist) {
|
||||
str.append(prefix);
|
||||
nodeToStr(node, str, isProject);
|
||||
str.append("\n");
|
||||
str.append(sep);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -265,8 +307,20 @@ private:
|
|||
}
|
||||
str.append("\n");
|
||||
nodeListToStr(select->pProjectionList, prefix + "\t", str, true);
|
||||
str.append("\n" + prefix + "FROM\n");
|
||||
str.append(prefix + "FROM\n");
|
||||
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) {
|
||||
|
@ -332,15 +386,23 @@ private:
|
|||
case OP_TYPE_SUB:
|
||||
return " - ";
|
||||
case OP_TYPE_MULTI:
|
||||
return " * ";
|
||||
case OP_TYPE_DIV:
|
||||
return " / ";
|
||||
case OP_TYPE_MOD:
|
||||
return " % ";
|
||||
case OP_TYPE_GREATER_THAN:
|
||||
return " > ";
|
||||
case OP_TYPE_GREATER_EQUAL:
|
||||
return " >= ";
|
||||
case OP_TYPE_LOWER_THAN:
|
||||
return " < ";
|
||||
case OP_TYPE_LOWER_EQUAL:
|
||||
return " <= ";
|
||||
case OP_TYPE_EQUAL:
|
||||
return " = ";
|
||||
case OP_TYPE_NOT_EQUAL:
|
||||
return " != ";
|
||||
case OP_TYPE_IN:
|
||||
case OP_TYPE_NOT_IN:
|
||||
case OP_TYPE_LIKE:
|
||||
|
@ -454,6 +516,23 @@ TEST_F(NewParserTest, selectExpression) {
|
|||
TEST_F(NewParserTest, selectClause) {
|
||||
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");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
|
@ -480,15 +559,65 @@ TEST_F(NewParserTest, selectSyntaxError) {
|
|||
TEST_F(NewParserTest, selectSemanticError) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT * FROM t10");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_FAILED));
|
||||
|
||||
// TSDB_CODE_PAR_INVALID_COLUMN
|
||||
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");
|
||||
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");
|
||||
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
|
||||
} 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) {
|
||||
return true;
|
||||
return DEAL_RES_CONTINUE;
|
||||
}
|
||||
|
||||
if (TRAVERSAL_PREORDER == order && !walker(pNode, pContext)) {
|
||||
return false;
|
||||
EDealRes res = DEAL_RES_CONTINUE;
|
||||
|
||||
if (TRAVERSAL_PREORDER == order) {
|
||||
res = walker(pNode, pContext);
|
||||
if (DEAL_RES_CONTINUE != res) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
bool res = true;
|
||||
switch (nodeType(pNode)) {
|
||||
case QUERY_NODE_COLUMN:
|
||||
case QUERY_NODE_VALUE:
|
||||
|
@ -41,7 +45,7 @@ static bool walkNode(SNode* pNode, ETraversalOrder order, FQueryNodeWalker walke
|
|||
case QUERY_NODE_OPERATOR: {
|
||||
SOperatorNode* pOpNode = (SOperatorNode*)pNode;
|
||||
res = walkNode(pOpNode->pLeft, order, walker, pContext);
|
||||
if (res) {
|
||||
if (DEAL_RES_ERROR != res) {
|
||||
res = walkNode(pOpNode->pRight, order, walker, pContext);
|
||||
}
|
||||
break;
|
||||
|
@ -61,10 +65,10 @@ static bool walkNode(SNode* pNode, ETraversalOrder order, FQueryNodeWalker walke
|
|||
case QUERY_NODE_JOIN_TABLE: {
|
||||
SJoinTableNode* pJoinTableNode = (SJoinTableNode*)pNode;
|
||||
res = walkNode(pJoinTableNode->pLeft, order, walker, pContext);
|
||||
if (res) {
|
||||
if (DEAL_RES_ERROR != res) {
|
||||
res = walkNode(pJoinTableNode->pRight, order, walker, pContext);
|
||||
}
|
||||
if (res) {
|
||||
if (DEAL_RES_ERROR != res) {
|
||||
res = walkNode(pJoinTableNode->pOnCond, order, walker, pContext);
|
||||
}
|
||||
break;
|
||||
|
@ -84,13 +88,13 @@ static bool walkNode(SNode* pNode, ETraversalOrder order, FQueryNodeWalker walke
|
|||
case QUERY_NODE_INTERVAL_WINDOW: {
|
||||
SIntervalWindowNode* pInterval = (SIntervalWindowNode*)pNode;
|
||||
res = walkNode(pInterval->pInterval, order, walker, pContext);
|
||||
if (res) {
|
||||
if (DEAL_RES_ERROR != res) {
|
||||
res = walkNode(pInterval->pOffset, order, walker, pContext);
|
||||
}
|
||||
if (res) {
|
||||
if (DEAL_RES_ERROR != res) {
|
||||
res = walkNode(pInterval->pSliding, order, walker, pContext);
|
||||
}
|
||||
if (res) {
|
||||
if (DEAL_RES_ERROR != res) {
|
||||
res = walkNode(pInterval->pFill, order, walker, pContext);
|
||||
}
|
||||
break;
|
||||
|
@ -108,21 +112,21 @@ static bool walkNode(SNode* pNode, ETraversalOrder order, FQueryNodeWalker walke
|
|||
break;
|
||||
}
|
||||
|
||||
if (res && TRAVERSAL_POSTORDER == order) {
|
||||
if (DEAL_RES_ERROR != res && TRAVERSAL_POSTORDER == order) {
|
||||
res = walker(pNode, pContext);
|
||||
}
|
||||
|
||||
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;
|
||||
FOREACH(node, pNodeList) {
|
||||
if (!walkNode(node, order, walker, pContext)) {
|
||||
return false;
|
||||
if (DEAL_RES_ERROR == walkNode(node, order, walker, pContext)) {
|
||||
return DEAL_RES_ERROR;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return DEAL_RES_CONTINUE;
|
||||
}
|
||||
|
||||
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)walkList(pList, TRAVERSAL_POSTORDER, walker, pContext);
|
||||
}
|
||||
|
||||
bool nodesWalkStmt(SNode* pNode, FQueryNodeWalker walker, void* pContext) {
|
||||
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ SNode* nodesMakeNode(ENodeType type) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static bool destroyNode(SNode* pNode, void* pContext) {
|
||||
static EDealRes destroyNode(SNode* pNode, void* pContext) {
|
||||
switch (nodeType(pNode)) {
|
||||
case QUERY_NODE_VALUE:
|
||||
tfree(((SValueNode*)pNode)->literal);
|
||||
|
@ -85,6 +85,7 @@ static bool destroyNode(SNode* pNode, void* pContext) {
|
|||
break;
|
||||
}
|
||||
tfree(pNode);
|
||||
return DEAL_RES_CONTINUE;
|
||||
}
|
||||
|
||||
void nodesDestroyNode(SNode* pNode) {
|
||||
|
@ -116,9 +117,23 @@ SNodeList* nodesListAppend(SNodeList* pList, SNode* pNode) {
|
|||
pList->pTail->pNext = p;
|
||||
}
|
||||
pList->pTail = p;
|
||||
++(pList->length);
|
||||
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* node;
|
||||
FOREACH(node, pList) {
|
||||
|
@ -137,6 +152,11 @@ void nodesDestroyList(SNodeList* 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) {
|
||||
switch (pOp->opType) {
|
||||
case OP_TYPE_ADD:
|
||||
|
|
Loading…
Reference in New Issue