cols
This commit is contained in:
parent
d3fa16b998
commit
d3e86d9854
|
@ -907,6 +907,9 @@ int32_t taosGetErrSize();
|
||||||
#define TSDB_CODE_PAR_INVALID_FORECAST_CLAUSE TAOS_DEF_ERROR_CODE(0, 0x2685)
|
#define TSDB_CODE_PAR_INVALID_FORECAST_CLAUSE TAOS_DEF_ERROR_CODE(0, 0x2685)
|
||||||
#define TSDB_CODE_PAR_INVALID_VGID_LIST TAOS_DEF_ERROR_CODE(0, 0x2686)
|
#define TSDB_CODE_PAR_INVALID_VGID_LIST TAOS_DEF_ERROR_CODE(0, 0x2686)
|
||||||
#define TSDB_CODE_PAR_INVALID_COLS_FUNCTION TAOS_DEF_ERROR_CODE(0, 0x2687)
|
#define TSDB_CODE_PAR_INVALID_COLS_FUNCTION TAOS_DEF_ERROR_CODE(0, 0x2687)
|
||||||
|
#define TSDB_CODE_PAR_INVALID_COLS_SELECTFUNC TAOS_DEF_ERROR_CODE(0, 0x2688)
|
||||||
|
#define TSDB_CODE_INVALID_MULITI_COLS_FUNC TAOS_DEF_ERROR_CODE(0, 0x2688)
|
||||||
|
#define TSDB_CODE_INVALID_COLS_ALIAS TAOS_DEF_ERROR_CODE(0, 0x2689)
|
||||||
#define TSDB_CODE_PAR_INTERNAL_ERROR TAOS_DEF_ERROR_CODE(0, 0x26FF)
|
#define TSDB_CODE_PAR_INTERNAL_ERROR TAOS_DEF_ERROR_CODE(0, 0x26FF)
|
||||||
|
|
||||||
//planner
|
//planner
|
||||||
|
|
|
@ -1696,6 +1696,10 @@ static int32_t translateOutVarchar(SFunctionNode* pFunc, char* pErrBuf, int32_t
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int32_t translateColsFunction(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
|
||||||
|
return TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
|
||||||
|
}
|
||||||
|
|
||||||
static int32_t translateHistogramImpl(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
|
static int32_t translateHistogramImpl(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
|
||||||
FUNC_ERR_RET(validateParam(pFunc, pErrBuf, len));
|
FUNC_ERR_RET(validateParam(pFunc, pErrBuf, len));
|
||||||
int32_t numOfParams = LIST_LENGTH(pFunc->pParameterList);
|
int32_t numOfParams = LIST_LENGTH(pFunc->pParameterList);
|
||||||
|
@ -5644,6 +5648,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "cols",
|
.name = "cols",
|
||||||
|
.translateFunc = translateColsFunction,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
|
@ -1076,6 +1076,14 @@ static bool isForecastPseudoColumnFunc(const SNode* pNode) {
|
||||||
return (QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsForecastPseudoColumnFunc(((SFunctionNode*)pNode)->funcId));
|
return (QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsForecastPseudoColumnFunc(((SFunctionNode*)pNode)->funcId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isColsFunctionResult(const SNode* pNode) {
|
||||||
|
return ((nodesIsExprNode(pNode)) && ((SExprNode*)pNode)->bindTupleFuncIdx > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isInvalidColsBindFunction(const SFunctionNode* pFunc) {
|
||||||
|
return (!fmIsSelectFunc(pFunc->funcId) && pFunc->node.tupleFuncIdx != 0);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef BUILD_NO_CALL
|
#ifdef BUILD_NO_CALL
|
||||||
static bool isTimelineFunc(const SNode* pNode) {
|
static bool isTimelineFunc(const SNode* pNode) {
|
||||||
return (QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsTimelineFunc(((SFunctionNode*)pNode)->funcId));
|
return (QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsTimelineFunc(((SFunctionNode*)pNode)->funcId));
|
||||||
|
@ -2311,7 +2319,7 @@ static EDealRes translateOperator(STranslateContext* pCxt, SOperatorNode* pOp) {
|
||||||
|
|
||||||
static EDealRes haveVectorFunction(SNode* pNode, void* pContext) {
|
static EDealRes haveVectorFunction(SNode* pNode, void* pContext) {
|
||||||
if (isAggFunc(pNode) || isIndefiniteRowsFunc(pNode) || isWindowPseudoColumnFunc(pNode) ||
|
if (isAggFunc(pNode) || isIndefiniteRowsFunc(pNode) || isWindowPseudoColumnFunc(pNode) ||
|
||||||
isInterpPseudoColumnFunc(pNode) || isForecastPseudoColumnFunc(pNode)) {
|
isInterpPseudoColumnFunc(pNode) || isForecastPseudoColumnFunc(pNode) || isColsFunctionResult(pNode)) {
|
||||||
*((bool*)pContext) = true;
|
*((bool*)pContext) = true;
|
||||||
return DEAL_RES_END;
|
return DEAL_RES_END;
|
||||||
}
|
}
|
||||||
|
@ -3298,6 +3306,10 @@ static EDealRes translateFunction(STranslateContext* pCxt, SFunctionNode** pFunc
|
||||||
pCxt->errCode = TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION;
|
pCxt->errCode = TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (isInvalidColsBindFunction(*pFunc)) {
|
||||||
|
pCxt->errCode = TSDB_CODE_PAR_INVALID_COLS_SELECTFUNC;
|
||||||
|
return DEAL_RES_ERROR;
|
||||||
|
}
|
||||||
if (TSDB_CODE_SUCCESS == pCxt->errCode) {
|
if (TSDB_CODE_SUCCESS == pCxt->errCode) {
|
||||||
pCxt->errCode = translateFunctionImpl(pCxt, pFunc);
|
pCxt->errCode = translateFunctionImpl(pCxt, pFunc);
|
||||||
}
|
}
|
||||||
|
@ -3813,7 +3825,7 @@ static EDealRes doCheckExprForGroupBy(SNode** pNode, void* pContext) {
|
||||||
if (isVectorFunc(*pNode) && !isDistinctOrderBy(pCxt)) {
|
if (isVectorFunc(*pNode) && !isDistinctOrderBy(pCxt)) {
|
||||||
return DEAL_RES_IGNORE_CHILD;
|
return DEAL_RES_IGNORE_CHILD;
|
||||||
}
|
}
|
||||||
if (isColsFunc(*pNode)) {
|
if (isColsFunctionResult(*pNode)) {
|
||||||
return DEAL_RES_IGNORE_CHILD;
|
return DEAL_RES_IGNORE_CHILD;
|
||||||
}
|
}
|
||||||
SNode* pGroupNode = NULL;
|
SNode* pGroupNode = NULL;
|
||||||
|
@ -3918,10 +3930,10 @@ static EDealRes doCheckAggColCoexist(SNode** pNode, void* pContext) {
|
||||||
if (isVectorFunc(*pNode)) {
|
if (isVectorFunc(*pNode)) {
|
||||||
return DEAL_RES_IGNORE_CHILD;
|
return DEAL_RES_IGNORE_CHILD;
|
||||||
}
|
}
|
||||||
if(isColsFunc(*pNode)) {
|
if(isColsFunctionResult(*pNode)) {
|
||||||
pCxt->hasColFunc = true;
|
pCxt->hasColFunc = true;
|
||||||
return DEAL_RES_IGNORE_CHILD;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SNode* pPartKey = NULL;
|
SNode* pPartKey = NULL;
|
||||||
bool partionByTbname = false;
|
bool partionByTbname = false;
|
||||||
if (fromSingleTable(((SSelectStmt*)pCxt->pTranslateCxt->pCurrStmt)->pFromTable) ||
|
if (fromSingleTable(((SSelectStmt*)pCxt->pTranslateCxt->pCurrStmt)->pFromTable) ||
|
||||||
|
@ -7300,7 +7312,8 @@ static int32_t translateSelectWithoutFrom(STranslateContext* pCxt, SSelectStmt*
|
||||||
}
|
}
|
||||||
typedef struct SCheckColsFuncCxt {
|
typedef struct SCheckColsFuncCxt {
|
||||||
bool hasColsFunc;
|
bool hasColsFunc;
|
||||||
bool hasMultiColsFunc;
|
SNodeList** selectFuncList;
|
||||||
|
int32_t status;
|
||||||
} SCheckColsFuncCxt;
|
} SCheckColsFuncCxt;
|
||||||
|
|
||||||
static bool isColsFuncByName(SFunctionNode* pFunc) {
|
static bool isColsFuncByName(SFunctionNode* pFunc) {
|
||||||
|
@ -7310,26 +7323,16 @@ static bool isColsFuncByName(SFunctionNode* pFunc) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isMultiColsFunc(SFunctionNode* pFunc) {
|
static bool isMultiColsFuncNode(SNode* pNode) {
|
||||||
if (strcasecmp(pFunc->functionName, "cols") != 0) {
|
if (QUERY_NODE_FUNCTION == nodeType(pNode)) {
|
||||||
return false;
|
SFunctionNode* pFunc = (SFunctionNode*)pNode;
|
||||||
}
|
|
||||||
return pFunc->pParameterList->length > 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static EDealRes isMultiColsFuncNode(SNode** pNode, void* pContext) {
|
|
||||||
SCheckColsFuncCxt* pCxt = pContext;
|
|
||||||
if (QUERY_NODE_FUNCTION == nodeType(*pNode)) {
|
|
||||||
SFunctionNode* pFunc = (SFunctionNode*)*pNode;
|
|
||||||
if (isColsFuncByName(pFunc)) {
|
if (isColsFuncByName(pFunc)) {
|
||||||
pCxt->hasColsFunc = true;
|
|
||||||
if (pFunc->pParameterList->length > 2) {
|
if (pFunc->pParameterList->length > 2) {
|
||||||
pCxt->hasMultiColsFunc = true;
|
return true;
|
||||||
return DEAL_RES_END;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return DEAL_RES_CONTINUE;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct SBindTupleFuncCxt {
|
typedef struct SBindTupleFuncCxt {
|
||||||
|
@ -7347,16 +7350,6 @@ static EDealRes pushDownBindSelectFunc(SNode** pNode, void* pContext) {
|
||||||
return DEAL_RES_CONTINUE;
|
return DEAL_RES_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void checkColsFuncInList(SNodeList* nodeList, SCheckColsFuncCxt* pCheckouColsFuncCxt) {
|
|
||||||
nodesRewriteExprs(nodeList, isMultiColsFuncNode, pCheckouColsFuncCxt);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void checkColsFunc(SNode** pNode, SCheckColsFuncCxt* pCheckouColsFuncCxt) {
|
|
||||||
nodesRewriteExpr(pNode, isMultiColsFuncNode, pCheckouColsFuncCxt);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool invalidColsAlias(SFunctionNode* pFunc) {
|
static bool invalidColsAlias(SFunctionNode* pFunc) {
|
||||||
if (pFunc->node.asAlias) {
|
if (pFunc->node.asAlias) {
|
||||||
if (pFunc->pParameterList->length > 2) {
|
if (pFunc->pParameterList->length > 2) {
|
||||||
|
@ -7374,37 +7367,6 @@ static bool invalidColsAlias(SFunctionNode* pFunc) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t hasInvalidColsFunction(STranslateContext* pCxt, SNodeList* nodeList,
|
|
||||||
SCheckColsFuncCxt* pCheckouColsFuncCxt) {
|
|
||||||
SNode* pTmpNode = NULL;
|
|
||||||
FOREACH(pTmpNode, nodeList) {
|
|
||||||
if (QUERY_NODE_FUNCTION == nodeType(pTmpNode)) {
|
|
||||||
SFunctionNode* pFunc = (SFunctionNode*)pTmpNode;
|
|
||||||
if (isColsFuncByName(pFunc)) {
|
|
||||||
pCheckouColsFuncCxt->hasColsFunc = true;
|
|
||||||
if (invalidColsAlias(pFunc)) {
|
|
||||||
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_COLS_FUNCTION,
|
|
||||||
"Invalid using alias for cols function");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
checkColsFuncInList(pFunc->pParameterList, pCheckouColsFuncCxt);
|
|
||||||
if (pCheckouColsFuncCxt->hasMultiColsFunc) {
|
|
||||||
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_COLS_FUNCTION,
|
|
||||||
"Invalid cols function in function %s", pFunc->functionName);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
checkColsFunc(&pTmpNode, pCheckouColsFuncCxt);
|
|
||||||
if (pCheckouColsFuncCxt->hasMultiColsFunc) {
|
|
||||||
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_COLS_FUNCTION,
|
|
||||||
"Invalid cols function, can't be used at here");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TSDB_CODE_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int32_t getSelectFuncIndex(SNodeList* FuncNodeList, SNode* pSelectFunc) {
|
static int32_t getSelectFuncIndex(SNodeList* FuncNodeList, SNode* pSelectFunc) {
|
||||||
SNode* pNode = NULL;
|
SNode* pNode = NULL;
|
||||||
int32_t selectFuncIndex = 0;
|
int32_t selectFuncIndex = 0;
|
||||||
|
@ -7417,47 +7379,178 @@ static int32_t getSelectFuncIndex(SNodeList* FuncNodeList, SNode* pSelectFunc) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t rewriteColsFunction(STranslateContext* pCxt, SNodeList** nodeList) {
|
static EDealRes checkHasColsFunc(SNode** pNode, void* pContext){
|
||||||
SCheckColsFuncCxt pCheckouColsFuncCxt = {false, false};
|
if (QUERY_NODE_FUNCTION == nodeType(*pNode)) {
|
||||||
int32_t code = hasInvalidColsFunction(pCxt, *nodeList, &pCheckouColsFuncCxt);
|
SFunctionNode* pFunc = (SFunctionNode*)*pNode;
|
||||||
|
if (isColsFuncByName(pFunc)) {
|
||||||
|
*(bool*)pContext = true;
|
||||||
|
return DEAL_RES_END;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DEAL_RES_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t checkMultColsFuncParam(SNodeList* pParameterList) {
|
||||||
|
if (!pParameterList || pParameterList->length < 2) {
|
||||||
|
return TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
|
||||||
|
}
|
||||||
|
int32_t index = 0;
|
||||||
|
SNode* pNode = NULL;
|
||||||
|
FOREACH(pNode, pParameterList) {
|
||||||
|
if (index == 0) { // the first parameter is select function
|
||||||
|
if (QUERY_NODE_FUNCTION != nodeType(pNode)) {
|
||||||
|
return TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
|
||||||
|
}
|
||||||
|
SFunctionNode* pFunc = (SFunctionNode*)pNode;
|
||||||
|
// pFunc->funcId is zero at here, so need to check at * step
|
||||||
|
// if(!fmIsSelectFunc(pFunc->funcId)) {
|
||||||
|
// return TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
|
||||||
|
// }
|
||||||
|
SNode* pTmpNode = NULL;
|
||||||
|
FOREACH(pTmpNode, pFunc->pParameterList) {
|
||||||
|
bool hasColsFunc = false;
|
||||||
|
nodesRewriteExpr(&pTmpNode, checkHasColsFunc, (void*)&hasColsFunc);
|
||||||
|
if (hasColsFunc) {
|
||||||
|
return TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bool hasColsFunc = false;
|
||||||
|
nodesRewriteExpr(&pNode, checkHasColsFunc, &hasColsFunc);
|
||||||
|
if (hasColsFunc) {
|
||||||
|
return TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EDealRes rewriteSingleColsFunc(SNode** pNode, void* pContext) {
|
||||||
|
int32_t code = TSDB_CODE_SUCCESS;
|
||||||
|
if (QUERY_NODE_FUNCTION != nodeType(*pNode)) {
|
||||||
|
return DEAL_RES_CONTINUE;
|
||||||
|
}
|
||||||
|
SCheckColsFuncCxt* pCxt = pContext;
|
||||||
|
SFunctionNode* pFunc = (SFunctionNode*)*pNode;
|
||||||
|
if (isColsFuncByName(pFunc)) {
|
||||||
|
if(pFunc->pParameterList->length > 2) {
|
||||||
|
pCxt->status = TSDB_CODE_PAR_INVALID_COLS_SELECTFUNC;
|
||||||
|
return DEAL_RES_ERROR;
|
||||||
|
}
|
||||||
|
SNode* pSelectFunc = nodesListGetNode(pFunc->pParameterList, 0);
|
||||||
|
SNode* pExpr = nodesListGetNode(pFunc->pParameterList, 1);
|
||||||
|
if (nodeType(pSelectFunc) != QUERY_NODE_FUNCTION) {
|
||||||
|
pCxt->status = TSDB_CODE_PAR_INVALID_COLS_SELECTFUNC;
|
||||||
|
parserError("Invalid cols function, the first parameter must be a select function");
|
||||||
|
return DEAL_RES_ERROR;
|
||||||
|
}
|
||||||
|
if (pFunc->node.asAlias) {
|
||||||
|
if (((SExprNode*)pExpr)->asAlias) {
|
||||||
|
pCxt->status = TSDB_CODE_INVALID_COLS_ALIAS;
|
||||||
|
parserError("Invalid using alias for cols function");
|
||||||
|
return DEAL_RES_ERROR;
|
||||||
|
} else {
|
||||||
|
((SExprNode*)pExpr)->asAlias = true;
|
||||||
|
tstrncpy(((SExprNode*)pExpr)->userAlias, pFunc->node.userAlias, TSDB_COL_NAME_LEN + TSDB_COL_NAME_EXLEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(*pCxt->selectFuncList == NULL) {
|
||||||
|
nodesMakeList(pCxt->selectFuncList);
|
||||||
|
if (NULL == *pCxt->selectFuncList) {
|
||||||
|
pCxt->status = terrno;
|
||||||
|
return DEAL_RES_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int32_t selectFuncCount = (*pCxt->selectFuncList)->length;
|
||||||
|
int32_t selectFuncIndex = getSelectFuncIndex(*pCxt->selectFuncList, pSelectFunc);
|
||||||
|
if (selectFuncIndex == 0) {
|
||||||
|
++selectFuncCount;
|
||||||
|
selectFuncIndex = selectFuncCount;
|
||||||
|
SNode* pNewNode = NULL;
|
||||||
|
code = nodesCloneNode(pSelectFunc, &pNewNode);
|
||||||
|
((SExprNode*)pNewNode)->tupleFuncIdx = selectFuncIndex;
|
||||||
|
nodesListMakeStrictAppend(pCxt->selectFuncList, pNewNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
SNode* pNewNode = NULL;
|
||||||
|
code = nodesCloneNode(pExpr, &pNewNode);
|
||||||
|
if (nodesIsExprNode(pNewNode)) {
|
||||||
|
SBindTupleFuncCxt pCxt = {selectFuncIndex};
|
||||||
|
nodesRewriteExpr(&pNewNode, pushDownBindSelectFunc, &pCxt);
|
||||||
|
} else {
|
||||||
|
pCxt->status = TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
|
||||||
|
parserError("Invalid cols function, the first parameter must be a select function");
|
||||||
|
return DEAL_RES_ERROR;
|
||||||
|
}
|
||||||
|
nodesDestroyNode(*pNode);
|
||||||
|
*pNode = pNewNode;
|
||||||
|
}
|
||||||
|
return DEAL_RES_CONTINUE;
|
||||||
|
_end:
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t rewriteColsFunction(STranslateContext* pCxt, SNodeList** nodeList, SNodeList** selectFuncList) {
|
||||||
|
int32_t code = TSDB_CODE_SUCCESS;
|
||||||
|
bool needRewrite = false;
|
||||||
|
SNode** pNode = NULL;
|
||||||
|
FOREACH_FOR_REWRITE(pNode, *nodeList) {
|
||||||
|
if (isMultiColsFuncNode(*pNode)) {
|
||||||
|
code = checkMultColsFuncParam(((SFunctionNode*)*pNode)->pParameterList);
|
||||||
if (TSDB_CODE_SUCCESS != code) {
|
if (TSDB_CODE_SUCCESS != code) {
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
bool needRewrite = false;
|
|
||||||
if (pCheckouColsFuncCxt.hasColsFunc) {
|
|
||||||
needRewrite = true;
|
needRewrite = true;
|
||||||
|
} else {
|
||||||
|
SCheckColsFuncCxt pSelectFuncCxt = {false, selectFuncList, TSDB_CODE_SUCCESS};
|
||||||
|
nodesRewriteExpr(pNode, rewriteSingleColsFunc, &pSelectFuncCxt);
|
||||||
|
if (pSelectFuncCxt.status != TSDB_CODE_SUCCESS) {
|
||||||
|
return pSelectFuncCxt.status;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SNodeList* pNewNodeList = NULL;
|
SNodeList* pNewNodeList = NULL;
|
||||||
SNodeList* tmpFuncNodeList = NULL;
|
|
||||||
if (needRewrite) {
|
if (needRewrite) {
|
||||||
code = nodesMakeList(&pNewNodeList);
|
code = nodesMakeList(&pNewNodeList);
|
||||||
if (NULL == pNewNodeList) {
|
if (NULL == pNewNodeList) {
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
code = nodesMakeList(&tmpFuncNodeList);
|
if (*selectFuncList == NULL) {
|
||||||
if (NULL == tmpFuncNodeList) {
|
code = nodesMakeList(selectFuncList);
|
||||||
|
if (NULL == *selectFuncList) {
|
||||||
|
nodesDestroyList(pNewNodeList);
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SNode* pNewNode = NULL;
|
SNode* pNewNode = NULL;
|
||||||
int32_t nums = 0;
|
int32_t nums = 0;
|
||||||
int32_t selectFuncCount = 0;
|
int32_t selectFuncCount = (*selectFuncList)->length;
|
||||||
SNode* pTmpNode = NULL;
|
SNode* pTmpNode = NULL;
|
||||||
FOREACH(pTmpNode, *nodeList) {
|
FOREACH(pTmpNode, *nodeList) {
|
||||||
if (QUERY_NODE_FUNCTION == nodeType(pTmpNode)) {
|
if (isMultiColsFuncNode(pTmpNode)) {
|
||||||
SFunctionNode* pFunc = (SFunctionNode*)pTmpNode;
|
SFunctionNode* pFunc = (SFunctionNode*)pTmpNode;
|
||||||
if (strcasecmp(pFunc->functionName, "cols") == 0) {
|
if(pFunc->node.asAlias) {
|
||||||
|
code = TSDB_CODE_INVALID_COLS_ALIAS;
|
||||||
|
parserError("Invalid using alias for cols function");
|
||||||
|
goto _end;
|
||||||
|
}
|
||||||
|
|
||||||
SNode* pSelectFunc = nodesListGetNode(pFunc->pParameterList, 0);
|
SNode* pSelectFunc = nodesListGetNode(pFunc->pParameterList, 0);
|
||||||
if (nodeType(pSelectFunc) != QUERY_NODE_FUNCTION) {
|
if (nodeType(pSelectFunc) != QUERY_NODE_FUNCTION) {
|
||||||
code = TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
|
code = TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
|
||||||
parserError("Invalid cols function, the first parameter must be a select function");
|
parserError("Invalid cols function, the first parameter must be a select function");
|
||||||
goto _end;
|
goto _end;
|
||||||
}
|
}
|
||||||
int32_t selectFuncIndex = getSelectFuncIndex(tmpFuncNodeList, pSelectFunc);
|
int32_t selectFuncIndex = getSelectFuncIndex(*selectFuncList, pSelectFunc);
|
||||||
if (selectFuncIndex == 0) {
|
if (selectFuncIndex == 0) {
|
||||||
++selectFuncCount;
|
++selectFuncCount;
|
||||||
selectFuncIndex = selectFuncCount;
|
selectFuncIndex = selectFuncCount;
|
||||||
nodesListMakeStrictAppend(&tmpFuncNodeList, pSelectFunc);
|
code = nodesCloneNode(pSelectFunc, &pNewNode);
|
||||||
|
((SExprNode*)pNewNode)->tupleFuncIdx = selectFuncIndex;
|
||||||
|
nodesListMakeStrictAppend(selectFuncList, pNewNode);
|
||||||
}
|
}
|
||||||
// start from index 1, because the first parameter is select function which needn't to output.
|
// start from index 1, because the first parameter is select function which needn't to output.
|
||||||
for (int i = 1; i < pFunc->pParameterList->length; ++i) {
|
for (int i = 1; i < pFunc->pParameterList->length; ++i) {
|
||||||
|
@ -7478,48 +7571,43 @@ static int32_t rewriteColsFunction(STranslateContext* pCxt, SNodeList** nodeList
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
code = nodesCloneNode(pTmpNode, &pNewNode);
|
code = nodesCloneNode(pTmpNode, &pNewNode);
|
||||||
if (TSDB_CODE_SUCCESS != code) goto _end;
|
if (TSDB_CODE_SUCCESS != code) goto _end;
|
||||||
code = nodesListMakeStrictAppend(&pNewNodeList, pNewNode);
|
code = nodesListMakeStrictAppend(&pNewNodeList, pNewNode);
|
||||||
if (TSDB_CODE_SUCCESS != code) goto _end;
|
if (TSDB_CODE_SUCCESS != code) goto _end;
|
||||||
}
|
}
|
||||||
SNode* pNode = NULL;
|
|
||||||
int32_t pNewSelectFuncIds = 0;
|
|
||||||
FOREACH(pNode, tmpFuncNodeList) {
|
|
||||||
++pNewSelectFuncIds;
|
|
||||||
code = nodesCloneNode(pNode, &pNewNode);
|
|
||||||
if (TSDB_CODE_SUCCESS != code) goto _end;
|
|
||||||
if (nodesIsExprNode(pNewNode)) {
|
|
||||||
SExprNode* pExprNode = (SExprNode*)pNewNode;
|
|
||||||
pExprNode->tupleFuncIdx = pNewSelectFuncIds;
|
|
||||||
} else {
|
|
||||||
code = TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
|
|
||||||
parserError("Invalid cols function, the first parameter must be a select function");
|
|
||||||
goto _end;
|
|
||||||
}
|
|
||||||
code = nodesListMakeStrictAppend(&pNewNodeList, pNewNode);
|
|
||||||
if (TSDB_CODE_SUCCESS != code) goto _end;
|
|
||||||
}
|
|
||||||
nodesDestroyList(*nodeList);
|
nodesDestroyList(*nodeList);
|
||||||
nodesDestroyList(tmpFuncNodeList);
|
|
||||||
*nodeList = pNewNodeList;
|
*nodeList = pNewNodeList;
|
||||||
}
|
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
_end:
|
_end:
|
||||||
if (TSDB_CODE_SUCCESS != code) {
|
if (TSDB_CODE_SUCCESS != code) {
|
||||||
nodesDestroyList(pNewNodeList);
|
nodesDestroyList(pNewNodeList);
|
||||||
nodesDestroyList(tmpFuncNodeList);
|
|
||||||
}
|
}
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t translateColsFunction(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
static int32_t translateColsFunction(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||||
int32_t code = rewriteColsFunction(pCxt, &pSelect->pProjectionList);
|
SNodeList* selectFuncList = NULL;
|
||||||
|
int32_t code = rewriteColsFunction(pCxt, &pSelect->pProjectionList, &selectFuncList);
|
||||||
if (code == TSDB_CODE_SUCCESS) {
|
if (code == TSDB_CODE_SUCCESS) {
|
||||||
code = rewriteColsFunction(pCxt, &pSelect->pOrderByList);
|
code = rewriteColsFunction(pCxt, &pSelect->pOrderByList, &selectFuncList);
|
||||||
}
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS != code) {
|
||||||
|
goto _end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectFuncList != NULL) {
|
||||||
|
nodesListAppendList(pSelect->pProjectionList, selectFuncList);
|
||||||
|
selectFuncList = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
_end:
|
||||||
|
if (selectFuncList) {
|
||||||
|
nodesDestroyList(selectFuncList);
|
||||||
|
}
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -751,6 +751,10 @@ TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INVALID_FORECAST_CLAUSE, "Invalid forecast cl
|
||||||
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_REGULAR_EXPRESSION_ERROR, "Syntax error in regular expression")
|
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_REGULAR_EXPRESSION_ERROR, "Syntax error in regular expression")
|
||||||
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INVALID_VGID_LIST, "Invalid vgid list")
|
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INVALID_VGID_LIST, "Invalid vgid list")
|
||||||
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INVALID_COLS_FUNCTION, "Invalid cols function")
|
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INVALID_COLS_FUNCTION, "Invalid cols function")
|
||||||
|
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INVALID_COLS_SELECTFUNC, "cols function's first param must be a select function")
|
||||||
|
TAOS_DEFINE_ERROR(TSDB_CODE_INVALID_MULITI_COLS_FUNC, "Improper use of cols function with multiple output columns")
|
||||||
|
TAOS_DEFINE_ERROR(TSDB_CODE_INVALID_COLS_ALIAS, "Invalid using alias for cols function")
|
||||||
|
|
||||||
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INTERNAL_ERROR, "Parser internal error")
|
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INTERNAL_ERROR, "Parser internal error")
|
||||||
|
|
||||||
//planner
|
//planner
|
||||||
|
|
|
@ -233,6 +233,7 @@ class TDTestCase:
|
||||||
tdSql.error(f'select cols(last(ts), ts t1) tt from {self.dbname}.meters')
|
tdSql.error(f'select cols(last(ts), ts t1) tt from {self.dbname}.meters')
|
||||||
tdSql.error(f'select cols(first(ts+1), c0+2 cc0, c1 cc1) cc from {self.dbname}.meters')
|
tdSql.error(f'select cols(first(ts+1), c0+2 cc0, c1 cc1) cc from {self.dbname}.meters')
|
||||||
tdSql.error(f'select cols(last(ts)+1, c0+2 as cc0) as cc from {self.dbname}.meters')
|
tdSql.error(f'select cols(last(ts)+1, c0+2 as cc0) as cc from {self.dbname}.meters')
|
||||||
|
tdSql.error(f'select cols(ABS(c0), c1) from {self.dbname}.meters group by tbname')
|
||||||
|
|
||||||
tdSql.error(f'select cols(last(ts)+1, ts) from {self.dbname}.meters')
|
tdSql.error(f'select cols(last(ts)+1, ts) from {self.dbname}.meters')
|
||||||
tdSql.error(f'select cols(last(ts)+10, c1+10) from {self.dbname}.meters group by tbname')
|
tdSql.error(f'select cols(last(ts)+10, c1+10) from {self.dbname}.meters group by tbname')
|
||||||
|
|
Loading…
Reference in New Issue