Merge remote-tracking branch 'origin/3.0' into fix/tsim
This commit is contained in:
commit
6aa602e468
|
@ -103,6 +103,7 @@ typedef struct SIndefRowsFuncLogicNode {
|
|||
SLogicNode node;
|
||||
SNodeList* pFuncs;
|
||||
bool isTailFunc;
|
||||
bool isUniqueFunc;
|
||||
} SIndefRowsFuncLogicNode;
|
||||
|
||||
typedef struct SInterpFuncLogicNode {
|
||||
|
|
|
@ -50,6 +50,7 @@ typedef struct SExprNode {
|
|||
char aliasName[TSDB_COL_NAME_LEN];
|
||||
char userAlias[TSDB_COL_NAME_LEN];
|
||||
SArray* pAssociation;
|
||||
bool orderAlias;
|
||||
} SExprNode;
|
||||
|
||||
typedef enum EColumnType { COLUMN_TYPE_COLUMN = 1, COLUMN_TYPE_TAG, COLUMN_TYPE_TBNAME } EColumnType;
|
||||
|
|
|
@ -48,6 +48,8 @@ int32_t qCreateQueryPlan(SPlanContext* pCxt, SQueryPlan** pPlan, SArray* pExecNo
|
|||
// @pSource one execution location of this group of datasource subplans
|
||||
int32_t qSetSubplanExecutionNode(SSubplan* pSubplan, int32_t groupId, SDownstreamSourceNode* pSource);
|
||||
|
||||
int32_t qClearSubplanExecutionNode(SSubplan* pSubplan, int32_t groupId);
|
||||
|
||||
// Convert to subplan to string for the scheduler to send to the executor
|
||||
int32_t qSubPlanToString(const SSubplan* pSubplan, char** pStr, int32_t* pLen);
|
||||
int32_t qStringToSubplan(const char* pStr, SSubplan** pSubplan);
|
||||
|
|
|
@ -271,19 +271,19 @@ extern int32_t (*queryProcessMsgRsp[TDMT_MAX])(void* output, char* msg, int32_t
|
|||
#define qDebug(...) \
|
||||
do { \
|
||||
if (qDebugFlag & DEBUG_DEBUG) { \
|
||||
taosPrintLog("QRY ", DEBUG_DEBUG, qDebugFlag, __VA_ARGS__); \
|
||||
taosPrintLog("QRY ", DEBUG_DEBUG, tsLogEmbedded ? 255 : qDebugFlag, __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
#define qTrace(...) \
|
||||
do { \
|
||||
if (qDebugFlag & DEBUG_TRACE) { \
|
||||
taosPrintLog("QRY ", DEBUG_TRACE, qDebugFlag, __VA_ARGS__); \
|
||||
taosPrintLog("QRY ", DEBUG_TRACE, tsLogEmbedded ? 255 : qDebugFlag, __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
#define qDebugL(...) \
|
||||
do { \
|
||||
if (qDebugFlag & DEBUG_DEBUG) { \
|
||||
taosPrintLongString("QRY ", DEBUG_DEBUG, qDebugFlag, __VA_ARGS__); \
|
||||
taosPrintLongString("QRY ", DEBUG_DEBUG, tsLogEmbedded ? 255 : qDebugFlag, __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
|
|
@ -1052,7 +1052,8 @@ static int32_t translateUniqueMode(SFunctionNode* pFunc, char* pErrBuf, int32_t
|
|||
|
||||
SNode* pPara = nodesListGetNode(pFunc->pParameterList, 0);
|
||||
if (!nodesExprHasColumn(pPara)) {
|
||||
return buildFuncErrMsg(pErrBuf, len, TSDB_CODE_FUNC_FUNTION_ERROR, "The parameters of %s must contain columns", isUnique ? "UNIQUE" : "MODE");
|
||||
return buildFuncErrMsg(pErrBuf, len, TSDB_CODE_FUNC_FUNTION_ERROR, "The parameters of %s must contain columns",
|
||||
isUnique ? "UNIQUE" : "MODE");
|
||||
}
|
||||
|
||||
pFunc->node.resType = ((SExprNode*)pPara)->resType;
|
||||
|
@ -1228,19 +1229,19 @@ static int32_t translateSubstr(SFunctionNode* pFunc, char* pErrBuf, int32_t len)
|
|||
|
||||
static int32_t translateCast(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
|
||||
// The number of parameters has been limited by the syntax definition
|
||||
//uint8_t para1Type = ((SExprNode*)nodesListGetNode(pFunc->pParameterList, 0))->resType.type;
|
||||
// uint8_t para1Type = ((SExprNode*)nodesListGetNode(pFunc->pParameterList, 0))->resType.type;
|
||||
|
||||
// The function return type has been set during syntax parsing
|
||||
uint8_t para2Type = pFunc->node.resType.type;
|
||||
//if (para2Type != TSDB_DATA_TYPE_BIGINT && para2Type != TSDB_DATA_TYPE_UBIGINT &&
|
||||
// para2Type != TSDB_DATA_TYPE_VARCHAR && para2Type != TSDB_DATA_TYPE_NCHAR &&
|
||||
// para2Type != TSDB_DATA_TYPE_TIMESTAMP) {
|
||||
// return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
|
||||
//}
|
||||
//if ((para2Type == TSDB_DATA_TYPE_TIMESTAMP && IS_VAR_DATA_TYPE(para1Type)) ||
|
||||
// (para2Type == TSDB_DATA_TYPE_BINARY && para1Type == TSDB_DATA_TYPE_NCHAR)) {
|
||||
// return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
|
||||
//}
|
||||
// if (para2Type != TSDB_DATA_TYPE_BIGINT && para2Type != TSDB_DATA_TYPE_UBIGINT &&
|
||||
// para2Type != TSDB_DATA_TYPE_VARCHAR && para2Type != TSDB_DATA_TYPE_NCHAR &&
|
||||
// para2Type != TSDB_DATA_TYPE_TIMESTAMP) {
|
||||
// return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
|
||||
// }
|
||||
// if ((para2Type == TSDB_DATA_TYPE_TIMESTAMP && IS_VAR_DATA_TYPE(para1Type)) ||
|
||||
// (para2Type == TSDB_DATA_TYPE_BINARY && para1Type == TSDB_DATA_TYPE_NCHAR)) {
|
||||
// return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
|
||||
// }
|
||||
|
||||
int32_t para2Bytes = pFunc->node.resType.bytes;
|
||||
if (IS_VAR_DATA_TYPE(para2Type)) {
|
||||
|
@ -1890,7 +1891,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
|
|||
{
|
||||
.name = "first",
|
||||
.type = FUNCTION_TYPE_FIRST,
|
||||
.classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_MULTI_RES_FUNC | FUNC_MGT_TIMELINE_FUNC,
|
||||
.classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_MULTI_RES_FUNC | FUNC_MGT_TIMELINE_FUNC,
|
||||
.translateFunc = translateFirstLast,
|
||||
.getEnvFunc = getFirstLastFuncEnv,
|
||||
.initFunc = functionSetup,
|
||||
|
@ -1925,7 +1926,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
|
|||
{
|
||||
.name = "last",
|
||||
.type = FUNCTION_TYPE_LAST,
|
||||
.classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_MULTI_RES_FUNC | FUNC_MGT_TIMELINE_FUNC,
|
||||
.classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_MULTI_RES_FUNC | FUNC_MGT_TIMELINE_FUNC,
|
||||
.translateFunc = translateFirstLast,
|
||||
.getEnvFunc = getFirstLastFuncEnv,
|
||||
.initFunc = functionSetup,
|
||||
|
@ -2117,7 +2118,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
|
|||
{
|
||||
.name = "unique",
|
||||
.type = FUNCTION_TYPE_UNIQUE,
|
||||
.classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_INDEFINITE_ROWS_FUNC | FUNC_MGT_TIMELINE_FUNC |
|
||||
.classification = FUNC_MGT_SELECT_FUNC | FUNC_MGT_INDEFINITE_ROWS_FUNC | FUNC_MGT_TIMELINE_FUNC |
|
||||
FUNC_MGT_FORBID_STREAM_FUNC | FUNC_MGT_FORBID_WINDOW_FUNC | FUNC_MGT_FORBID_GROUP_BY_FUNC,
|
||||
.translateFunc = translateUnique,
|
||||
.getEnvFunc = getUniqueFuncEnv,
|
||||
|
|
|
@ -100,6 +100,7 @@ static int32_t exprNodeCopy(const SExprNode* pSrc, SExprNode* pDst) {
|
|||
COPY_OBJECT_FIELD(resType, sizeof(SDataType));
|
||||
COPY_CHAR_ARRAY_FIELD(aliasName);
|
||||
COPY_CHAR_ARRAY_FIELD(userAlias);
|
||||
COPY_SCALAR_FIELD(orderAlias);
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -1500,7 +1500,8 @@ typedef struct SCollectFuncsCxt {
|
|||
|
||||
static EDealRes collectFuncs(SNode* pNode, void* pContext) {
|
||||
SCollectFuncsCxt* pCxt = (SCollectFuncsCxt*)pContext;
|
||||
if (QUERY_NODE_FUNCTION == nodeType(pNode) && pCxt->classifier(((SFunctionNode*)pNode)->funcId)) {
|
||||
if (QUERY_NODE_FUNCTION == nodeType(pNode) && pCxt->classifier(((SFunctionNode*)pNode)->funcId) &&
|
||||
!(((SExprNode*)pNode)->orderAlias)) {
|
||||
pCxt->errCode = nodesListStrictAppend(pCxt->pFuncs, nodesCloneNode(pNode));
|
||||
return (TSDB_CODE_SUCCESS == pCxt->errCode ? DEAL_RES_IGNORE_CHILD : DEAL_RES_ERROR);
|
||||
}
|
||||
|
|
|
@ -1355,25 +1355,6 @@ static EDealRes rewriteColToSelectValFunc(STranslateContext* pCxt, SNode** pNode
|
|||
return TSDB_CODE_SUCCESS == pCxt->errCode ? DEAL_RES_IGNORE_CHILD : DEAL_RES_ERROR;
|
||||
}
|
||||
|
||||
static EDealRes rewriteExprToGroupKeyFunc(STranslateContext* pCxt, SNode** pNode) {
|
||||
SFunctionNode* pFunc = (SFunctionNode*)nodesMakeNode(QUERY_NODE_FUNCTION);
|
||||
if (NULL == pFunc) {
|
||||
pCxt->errCode = TSDB_CODE_OUT_OF_MEMORY;
|
||||
return DEAL_RES_ERROR;
|
||||
}
|
||||
|
||||
strcpy(pFunc->functionName, "_group_key");
|
||||
strcpy(pFunc->node.aliasName, ((SExprNode*)*pNode)->aliasName);
|
||||
pCxt->errCode = nodesListMakeAppend(&pFunc->pParameterList, *pNode);
|
||||
if (TSDB_CODE_SUCCESS == pCxt->errCode) {
|
||||
*pNode = (SNode*)pFunc;
|
||||
pCxt->errCode = fmGetFuncInfo(pFunc, pCxt->msgBuf.buf, pCxt->msgBuf.len);
|
||||
}
|
||||
pCxt->pCurrSelectStmt->hasAggFuncs = true;
|
||||
|
||||
return (TSDB_CODE_SUCCESS == pCxt->errCode ? DEAL_RES_IGNORE_CHILD : DEAL_RES_ERROR);
|
||||
}
|
||||
|
||||
static EDealRes doCheckExprForGroupBy(SNode** pNode, void* pContext) {
|
||||
SCheckExprForGroupByCxt* pCxt = (SCheckExprForGroupByCxt*)pContext;
|
||||
if (!nodesIsExprNode(*pNode) || isAliasColumn(*pNode)) {
|
||||
|
@ -1393,7 +1374,13 @@ static EDealRes doCheckExprForGroupBy(SNode** pNode, void* pContext) {
|
|||
SNode* pGroupNode = NULL;
|
||||
FOREACH(pGroupNode, getGroupByList(pCxt->pTranslateCxt)) {
|
||||
if (nodesEqualNode(getGroupByNode(pGroupNode), *pNode)) {
|
||||
return rewriteExprToGroupKeyFunc(pCxt->pTranslateCxt, pNode);
|
||||
return DEAL_RES_IGNORE_CHILD;
|
||||
}
|
||||
}
|
||||
SNode* pPartKey = NULL;
|
||||
FOREACH(pPartKey, pCxt->pTranslateCxt->pCurrSelectStmt->pPartitionByList) {
|
||||
if (nodesEqualNode(pPartKey, *pNode)) {
|
||||
return DEAL_RES_IGNORE_CHILD;
|
||||
}
|
||||
}
|
||||
if (isScanPseudoColumnFunc(*pNode) || QUERY_NODE_COLUMN == nodeType(*pNode)) {
|
||||
|
@ -1451,25 +1438,6 @@ static int32_t rewriteColsToSelectValFunc(STranslateContext* pCxt, SSelectStmt*
|
|||
return pCxt->errCode;
|
||||
}
|
||||
|
||||
static EDealRes rewriteExprsToGroupKeyFuncImpl(SNode** pNode, void* pContext) {
|
||||
STranslateContext* pCxt = pContext;
|
||||
SNode* pPartKey = NULL;
|
||||
FOREACH(pPartKey, pCxt->pCurrSelectStmt->pPartitionByList) {
|
||||
if (nodesEqualNode(pPartKey, *pNode)) {
|
||||
return rewriteExprToGroupKeyFunc(pCxt, pNode);
|
||||
}
|
||||
}
|
||||
return DEAL_RES_CONTINUE;
|
||||
}
|
||||
|
||||
static int32_t rewriteExprsToGroupKeyFunc(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||
nodesRewriteExprs(pSelect->pProjectionList, rewriteExprsToGroupKeyFuncImpl, pCxt);
|
||||
if (TSDB_CODE_SUCCESS == pCxt->errCode && !pSelect->isDistinct) {
|
||||
nodesRewriteExprs(pSelect->pOrderByList, rewriteExprsToGroupKeyFuncImpl, pCxt);
|
||||
}
|
||||
return pCxt->errCode;
|
||||
}
|
||||
|
||||
typedef struct CheckAggColCoexistCxt {
|
||||
STranslateContext* pTranslateCxt;
|
||||
bool existAggFunc;
|
||||
|
@ -1529,9 +1497,6 @@ static int32_t checkAggColCoexist(STranslateContext* pCxt, SSelectStmt* pSelect)
|
|||
if (cxt.existIndefiniteRowsFunc && cxt.existCol) {
|
||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC);
|
||||
}
|
||||
if (cxt.existAggFunc && NULL != pSelect->pPartitionByList) {
|
||||
return rewriteExprsToGroupKeyFunc(pCxt, pSelect);
|
||||
}
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -2408,54 +2373,6 @@ static EDealRes rewriteSeletcValueFunc(STranslateContext* pCxt, SNode** pNode) {
|
|||
return TSDB_CODE_SUCCESS == pCxt->errCode ? DEAL_RES_IGNORE_CHILD : DEAL_RES_ERROR;
|
||||
}
|
||||
|
||||
static EDealRes rewriteUniqueFunc(SNode** pNode, void* pContext) {
|
||||
SRwriteUniqueCxt* pCxt = pContext;
|
||||
if (QUERY_NODE_FUNCTION == nodeType(*pNode)) {
|
||||
SFunctionNode* pFunc = (SFunctionNode*)*pNode;
|
||||
if (FUNCTION_TYPE_UNIQUE == pFunc->funcType) {
|
||||
SNode* pExpr = nodesListGetNode(pFunc->pParameterList, 0);
|
||||
NODES_CLEAR_LIST(pFunc->pParameterList);
|
||||
strcpy(((SExprNode*)pExpr)->aliasName, ((SExprNode*)*pNode)->aliasName);
|
||||
nodesDestroyNode(*pNode);
|
||||
*pNode = pExpr;
|
||||
pCxt->pExpr = pExpr;
|
||||
return DEAL_RES_IGNORE_CHILD;
|
||||
} else if (FUNCTION_TYPE_SELECT_VALUE == pFunc->funcType) {
|
||||
return rewriteSeletcValueFunc(pCxt->pTranslateCxt, pNode);
|
||||
}
|
||||
}
|
||||
return DEAL_RES_CONTINUE;
|
||||
}
|
||||
|
||||
static SNode* createGroupingSet(SNode* pExpr) {
|
||||
SGroupingSetNode* pGroupingSet = (SGroupingSetNode*)nodesMakeNode(QUERY_NODE_GROUPING_SET);
|
||||
if (NULL == pGroupingSet) {
|
||||
return NULL;
|
||||
}
|
||||
pGroupingSet->groupingSetType = GP_TYPE_NORMAL;
|
||||
if (TSDB_CODE_SUCCESS != nodesListMakeStrictAppend(&pGroupingSet->pParameterList, nodesCloneNode(pExpr))) {
|
||||
nodesDestroyNode((SNode*)pGroupingSet);
|
||||
return NULL;
|
||||
}
|
||||
return (SNode*)pGroupingSet;
|
||||
}
|
||||
|
||||
// from: select unique(expr), col1 + col2 from t where_clause partition_by_clause order_by_clause ...
|
||||
// to: select expr, first(col1) + first(col2) from t where_clause partition_by_clause group by expr order_by_clause ...
|
||||
static int32_t rewriteUniqueStmt(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||
if (!pSelect->hasUniqueFunc) {
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
SRwriteUniqueCxt cxt = {.pTranslateCxt = pCxt, .pExpr = NULL};
|
||||
nodesRewriteExprs(pSelect->pProjectionList, rewriteUniqueFunc, &cxt);
|
||||
if (TSDB_CODE_SUCCESS == cxt.pTranslateCxt->errCode) {
|
||||
cxt.pTranslateCxt->errCode = nodesListMakeStrictAppend(&pSelect->pGroupByList, createGroupingSet(cxt.pExpr));
|
||||
}
|
||||
pSelect->hasIndefiniteRowsFunc = false;
|
||||
return cxt.pTranslateCxt->errCode;
|
||||
}
|
||||
|
||||
typedef struct SReplaceOrderByAliasCxt {
|
||||
STranslateContext* pTranslateCxt;
|
||||
SNodeList* pProjectionList;
|
||||
|
@ -2474,6 +2391,7 @@ static EDealRes replaceOrderByAliasImpl(SNode** pNode, void* pContext) {
|
|||
pCxt->pTranslateCxt->errCode = TSDB_CODE_OUT_OF_MEMORY;
|
||||
return DEAL_RES_ERROR;
|
||||
}
|
||||
((SExprNode*)pNew)->orderAlias = true;
|
||||
nodesDestroyNode(*pNode);
|
||||
*pNode = pNew;
|
||||
return DEAL_RES_CONTINUE;
|
||||
|
@ -2529,9 +2447,6 @@ static int32_t translateSelectFrom(STranslateContext* pCxt, SSelectStmt* pSelect
|
|||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = translateInterp(pCxt, pSelect);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = rewriteUniqueStmt(pCxt, pSelect);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = rewriteTimelineFunc(pCxt, pSelect);
|
||||
}
|
||||
|
|
|
@ -232,8 +232,6 @@ TEST_F(ParserSelectTest, groupBySemanticCheck) {
|
|||
|
||||
run("SELECT COUNT(*) cnt, c1 FROM t1 WHERE c1 > 0", TSDB_CODE_PAR_NOT_SINGLE_GROUP);
|
||||
run("SELECT COUNT(*) cnt, c2 FROM t1 WHERE c1 > 0 GROUP BY c1", TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION);
|
||||
run("SELECT COUNT(*) cnt, c2 FROM t1 WHERE c1 > 0 PARTITION BY c2 GROUP BY c1",
|
||||
TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION);
|
||||
}
|
||||
|
||||
TEST_F(ParserSelectTest, orderBy) {
|
||||
|
|
|
@ -437,6 +437,33 @@ static SColumnNode* createColumnByExpr(const char* pStmtName, SExprNode* pExpr)
|
|||
return pCol;
|
||||
}
|
||||
|
||||
static SNode* createGroupingSetNode(SNode* pExpr) {
|
||||
SGroupingSetNode* pGroupingSet = (SGroupingSetNode*)nodesMakeNode(QUERY_NODE_GROUPING_SET);
|
||||
if (NULL == pGroupingSet) {
|
||||
return NULL;
|
||||
}
|
||||
pGroupingSet->groupingSetType = GP_TYPE_NORMAL;
|
||||
if (TSDB_CODE_SUCCESS != nodesListMakeStrictAppend(&pGroupingSet->pParameterList, nodesCloneNode(pExpr))) {
|
||||
nodesDestroyNode((SNode*)pGroupingSet);
|
||||
return NULL;
|
||||
}
|
||||
return (SNode*)pGroupingSet;
|
||||
}
|
||||
|
||||
static int32_t createGroupKeysFromPartKeys(SNodeList* pPartKeys, SNodeList** pOutput) {
|
||||
SNodeList* pGroupKeys = NULL;
|
||||
SNode* pPartKey = NULL;
|
||||
FOREACH(pPartKey, pPartKeys) {
|
||||
int32_t code = nodesListMakeStrictAppend(&pGroupKeys, createGroupingSetNode(pPartKey));
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
nodesDestroyList(pGroupKeys);
|
||||
return code;
|
||||
}
|
||||
}
|
||||
*pOutput = pGroupKeys;
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static int32_t createAggLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect, SLogicNode** pLogicNode) {
|
||||
if (!pSelect->hasAggFuncs && NULL == pSelect->pGroupByList) {
|
||||
return TSDB_CODE_SUCCESS;
|
||||
|
@ -459,10 +486,18 @@ static int32_t createAggLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect,
|
|||
code = rewriteExprsForSelect(pAgg->pAggFuncs, pSelect, SQL_CLAUSE_GROUP_BY);
|
||||
}
|
||||
|
||||
if (NULL != pSelect->pPartitionByList) {
|
||||
code = createGroupKeysFromPartKeys(pSelect->pPartitionByList, &pAgg->pGroupKeys);
|
||||
}
|
||||
|
||||
if (NULL != pSelect->pGroupByList) {
|
||||
pAgg->pGroupKeys = nodesCloneList(pSelect->pGroupByList);
|
||||
if (NULL == pAgg->pGroupKeys) {
|
||||
code = TSDB_CODE_OUT_OF_MEMORY;
|
||||
if (NULL != pAgg->pGroupKeys) {
|
||||
code = nodesListStrictAppendList(pAgg->pGroupKeys, nodesCloneList(pSelect->pGroupByList));
|
||||
} else {
|
||||
pAgg->pGroupKeys = nodesCloneList(pSelect->pGroupByList);
|
||||
if (NULL == pAgg->pGroupKeys) {
|
||||
code = TSDB_CODE_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -508,6 +543,7 @@ static int32_t createIndefRowsFuncLogicNode(SLogicPlanContext* pCxt, SSelectStmt
|
|||
}
|
||||
|
||||
pIdfRowsFunc->isTailFunc = pSelect->hasTailFunc;
|
||||
pIdfRowsFunc->isUniqueFunc = pSelect->hasUniqueFunc;
|
||||
|
||||
// indefinite rows functions and _select_values functions
|
||||
int32_t code = nodesCollectFuncs(pSelect, SQL_CLAUSE_SELECT, fmIsVectorFunc, &pIdfRowsFunc->pFuncs);
|
||||
|
@ -809,7 +845,8 @@ static int32_t createProjectLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSel
|
|||
}
|
||||
|
||||
static int32_t createPartitionLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect, SLogicNode** pLogicNode) {
|
||||
if (NULL == pSelect->pPartitionByList) {
|
||||
if (NULL == pSelect->pPartitionByList || (pSelect->hasAggFuncs && NULL == pSelect->pWindow) ||
|
||||
NULL != pSelect->pGroupByList) {
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -987,6 +987,7 @@ static int32_t smaIndexOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogi
|
|||
code = smaIndexOptApplyIndex(pLogicSubplan, pScan, pIndex, pSmaCols, wstrartIndex);
|
||||
taosArrayDestroyEx(pScan->pSmaIndexes, smaIndexOptDestroySmaIndex);
|
||||
pScan->pSmaIndexes = NULL;
|
||||
pCxt->optimized = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1033,12 +1034,30 @@ static SNodeList* partTagsGetPartKeys(SLogicNode* pNode) {
|
|||
}
|
||||
}
|
||||
|
||||
static SNodeList* partTagsGetFuncs(SLogicNode* pNode) {
|
||||
if (QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pNode)) {
|
||||
return NULL;
|
||||
} else {
|
||||
return ((SAggLogicNode*)pNode)->pAggFuncs;
|
||||
}
|
||||
}
|
||||
|
||||
static bool partTagsOptAreSupportedFuncs(SNodeList* pFuncs) {
|
||||
SNode* pFunc = NULL;
|
||||
FOREACH(pFunc, pFuncs) {
|
||||
if (fmIsIndefiniteRowsFunc(((SFunctionNode*)pFunc)->funcId) && !fmIsSelectFunc(((SFunctionNode*)pFunc)->funcId)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool partTagsOptMayBeOptimized(SLogicNode* pNode) {
|
||||
if (!partTagsIsOptimizableNode(pNode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !partTagsOptHasCol(partTagsGetPartKeys(pNode));
|
||||
return !partTagsOptHasCol(partTagsGetPartKeys(pNode)) && partTagsOptAreSupportedFuncs(partTagsGetFuncs(pNode));
|
||||
}
|
||||
|
||||
static EDealRes partTagsOptRebuildTbanmeImpl(SNode** pNode, void* pContext) {
|
||||
|
@ -1064,6 +1083,59 @@ static int32_t partTagsOptRebuildTbanme(SNodeList* pPartKeys) {
|
|||
return code;
|
||||
}
|
||||
|
||||
static SNode* partTagsCreateWrapperFunc(const char* pFuncName, SNode* pNode) {
|
||||
SFunctionNode* pFunc = (SFunctionNode*)nodesMakeNode(QUERY_NODE_FUNCTION);
|
||||
if (NULL == pFunc) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(pFunc->functionName, pFuncName);
|
||||
if (QUERY_NODE_COLUMN == nodeType(pNode)) {
|
||||
SColumnNode* pCol = (SColumnNode*)pNode;
|
||||
sprintf(pFunc->node.aliasName, "%s.%s", pCol->tableAlias, pCol->colName);
|
||||
} else {
|
||||
strcpy(pFunc->node.aliasName, ((SExprNode*)pNode)->aliasName);
|
||||
}
|
||||
int32_t code = nodesListMakeStrictAppend(&pFunc->pParameterList, nodesCloneNode(pNode));
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = fmGetFuncInfo(pFunc, NULL, 0);
|
||||
}
|
||||
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
nodesDestroyNode((SNode*)pFunc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (SNode*)pFunc;
|
||||
}
|
||||
|
||||
static bool partTagsHasIndefRowsSelectFunc(SNodeList* pFuncs) {
|
||||
SNode* pFunc = NULL;
|
||||
FOREACH(pFunc, pFuncs) {
|
||||
if (fmIsIndefiniteRowsFunc(((SFunctionNode*)pFunc)->funcId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int32_t partTagsRewriteGroupTagsToFuncs(SNodeList* pGroupTags, SNodeList* pAggFuncs) {
|
||||
bool hasIndefRowsSelectFunc = partTagsHasIndefRowsSelectFunc(pAggFuncs);
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
SNode* pNode = NULL;
|
||||
FOREACH(pNode, pGroupTags) {
|
||||
if (hasIndefRowsSelectFunc) {
|
||||
code = nodesListStrictAppend(pAggFuncs, partTagsCreateWrapperFunc("_select_value", pNode));
|
||||
} else {
|
||||
code = nodesListStrictAppend(pAggFuncs, partTagsCreateWrapperFunc("_group_key", pNode));
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t partTagsOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
|
||||
SLogicNode* pNode = optFindPossibleNode(pLogicSubplan->pNode, partTagsOptMayBeOptimized);
|
||||
if (NULL == pNode) {
|
||||
|
@ -1080,15 +1152,17 @@ static int32_t partTagsOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSub
|
|||
nodesDestroyNode((SNode*)pNode);
|
||||
}
|
||||
} else {
|
||||
SNode* pGroupKey = NULL;
|
||||
FOREACH(pGroupKey, ((SAggLogicNode*)pNode)->pGroupKeys) {
|
||||
SAggLogicNode* pAgg = (SAggLogicNode*)pNode;
|
||||
SNode* pGroupKey = NULL;
|
||||
FOREACH(pGroupKey, pAgg->pGroupKeys) {
|
||||
code = nodesListMakeStrictAppend(
|
||||
&pScan->pGroupTags, nodesCloneNode(nodesListGetNode(((SGroupingSetNode*)pGroupKey)->pParameterList, 0)));
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
NODES_DESTORY_LIST(((SAggLogicNode*)pNode)->pGroupKeys);
|
||||
NODES_DESTORY_LIST(pAgg->pGroupKeys);
|
||||
code = partTagsRewriteGroupTagsToFuncs(pScan->pGroupTags, pAgg->pAggFuncs);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = partTagsOptRebuildTbanme(pScan->pGroupTags);
|
||||
|
@ -1125,7 +1199,8 @@ static bool eliminateProjOptMayBeOptimized(SLogicNode* pNode) {
|
|||
}
|
||||
|
||||
SProjectLogicNode* pProjectNode = (SProjectLogicNode*)pNode;
|
||||
if (NULL != pProjectNode->node.pLimit || NULL != pProjectNode->node.pSlimit) {
|
||||
if (NULL != pProjectNode->node.pLimit || NULL != pProjectNode->node.pSlimit ||
|
||||
NULL != pProjectNode->node.pConditions) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1163,6 +1238,7 @@ static int32_t eliminateProjOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan*
|
|||
NODES_CLEAR_LIST(pProjectNode->node.pChildren);
|
||||
nodesDestroyNode((SNode*)pProjectNode);
|
||||
}
|
||||
pCxt->optimized = true;
|
||||
return code;
|
||||
}
|
||||
|
||||
|
@ -1306,6 +1382,7 @@ static int32_t rewriteTailOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pL
|
|||
nodesDestroyNode((SNode*)pSort);
|
||||
nodesDestroyNode((SNode*)pProject);
|
||||
}
|
||||
pCxt->optimized = true;
|
||||
return code;
|
||||
}
|
||||
|
||||
|
@ -1344,6 +1421,7 @@ static int32_t eliminateSetOpOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan*
|
|||
|
||||
pSetOpNode->pChildren = NULL;
|
||||
ERASE_NODE(pSetOpNode->pParent->pChildren);
|
||||
pCxt->optimized = true;
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
@ -1360,15 +1438,192 @@ static int32_t eliminateSetOpOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLo
|
|||
return eliminateSetOpOptimizeImpl(pCxt, pLogicSubplan, pSetOpNode);
|
||||
}
|
||||
|
||||
//===================================================================================================================
|
||||
static bool rewriteUniqueOptMayBeOptimized(SLogicNode* pNode) {
|
||||
return QUERY_NODE_LOGIC_PLAN_INDEF_ROWS_FUNC == nodeType(pNode) && ((SIndefRowsFuncLogicNode*)pNode)->isUniqueFunc;
|
||||
}
|
||||
|
||||
static SNode* rewriteUniqueOptCreateGroupingSet(SNode* pExpr) {
|
||||
SGroupingSetNode* pGroupingSet = (SGroupingSetNode*)nodesMakeNode(QUERY_NODE_GROUPING_SET);
|
||||
if (NULL == pGroupingSet) {
|
||||
return NULL;
|
||||
}
|
||||
pGroupingSet->groupingSetType = GP_TYPE_NORMAL;
|
||||
SExprNode* pGroupExpr = (SExprNode*)nodesCloneNode(pExpr);
|
||||
if (TSDB_CODE_SUCCESS != nodesListMakeStrictAppend(&pGroupingSet->pParameterList, (SNode*)pGroupExpr)) {
|
||||
nodesDestroyNode((SNode*)pGroupingSet);
|
||||
return NULL;
|
||||
}
|
||||
return (SNode*)pGroupingSet;
|
||||
}
|
||||
|
||||
static SNode* rewriteUniqueOptCreateFirstFunc(SFunctionNode* pSelectValue, SNode* pCol) {
|
||||
SFunctionNode* pFunc = (SFunctionNode*)nodesMakeNode(QUERY_NODE_FUNCTION);
|
||||
if (NULL == pFunc) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(pFunc->functionName, "first");
|
||||
if (NULL != pSelectValue) {
|
||||
sprintf(pFunc->node.aliasName, "%s", pSelectValue->node.aliasName);
|
||||
} else {
|
||||
sprintf(pFunc->node.aliasName, "%s.%p", pFunc->functionName, pFunc);
|
||||
}
|
||||
int32_t code = nodesListMakeStrictAppend(&pFunc->pParameterList, nodesCloneNode(pCol));
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = fmGetFuncInfo(pFunc, NULL, 0);
|
||||
}
|
||||
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
nodesDestroyNode((SNode*)pFunc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (SNode*)pFunc;
|
||||
}
|
||||
|
||||
static int32_t rewriteUniqueOptCreateAgg(SIndefRowsFuncLogicNode* pIndef, SLogicNode** pOutput) {
|
||||
SAggLogicNode* pAgg = (SAggLogicNode*)nodesMakeNode(QUERY_NODE_LOGIC_PLAN_AGG);
|
||||
if (NULL == pAgg) {
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
TSWAP(pAgg->node.pChildren, pIndef->node.pChildren);
|
||||
pAgg->node.precision = pIndef->node.precision;
|
||||
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
bool hasSelectPrimaryKey = false;
|
||||
SNode* pPrimaryKey = NULL;
|
||||
SNode* pNode = NULL;
|
||||
FOREACH(pNode, pIndef->pFuncs) {
|
||||
SFunctionNode* pFunc = (SFunctionNode*)pNode;
|
||||
SNode* pExpr = nodesListGetNode(pFunc->pParameterList, 0);
|
||||
if (FUNCTION_TYPE_UNIQUE == pFunc->funcType) {
|
||||
pPrimaryKey = nodesListGetNode(pFunc->pParameterList, 1);
|
||||
code = nodesListMakeStrictAppend(&pAgg->pGroupKeys, rewriteUniqueOptCreateGroupingSet(pExpr));
|
||||
} else if (PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pExpr)->colId) { // _select_value(ts) => first(ts)
|
||||
hasSelectPrimaryKey = true;
|
||||
code = nodesListMakeStrictAppend(&pAgg->pAggFuncs, rewriteUniqueOptCreateFirstFunc(pFunc, pExpr));
|
||||
} else { // _select_value(other_col)
|
||||
code = nodesListMakeStrictAppend(&pAgg->pAggFuncs, nodesCloneNode(pNode));
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = createColumnByRewriteExprs(pAgg->pGroupKeys, &pAgg->node.pTargets);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code && NULL != pAgg->pAggFuncs) {
|
||||
code = createColumnByRewriteExprs(pAgg->pAggFuncs, &pAgg->node.pTargets);
|
||||
}
|
||||
|
||||
if (TSDB_CODE_SUCCESS == code && !hasSelectPrimaryKey && NULL != pAgg->pAggFuncs) {
|
||||
code = nodesListMakeStrictAppend(&pAgg->pAggFuncs, rewriteUniqueOptCreateFirstFunc(NULL, pPrimaryKey));
|
||||
}
|
||||
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
*pOutput = (SLogicNode*)pAgg;
|
||||
} else {
|
||||
nodesDestroyNode((SNode*)pAgg);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
static SNode* rewriteUniqueOptCreateProjectCol(SFunctionNode* pFunc) {
|
||||
SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN);
|
||||
if (NULL == pCol) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pCol->node.resType = pFunc->node.resType;
|
||||
if (FUNCTION_TYPE_UNIQUE == pFunc->funcType) {
|
||||
SExprNode* pExpr = (SExprNode*)nodesListGetNode(pFunc->pParameterList, 0);
|
||||
if (QUERY_NODE_COLUMN == nodeType(pExpr)) {
|
||||
strcpy(pCol->tableAlias, ((SColumnNode*)pExpr)->tableAlias);
|
||||
strcpy(pCol->colName, ((SColumnNode*)pExpr)->colName);
|
||||
} else {
|
||||
strcpy(pCol->colName, pExpr->aliasName);
|
||||
}
|
||||
} else {
|
||||
strcpy(pCol->colName, pFunc->node.aliasName);
|
||||
}
|
||||
strcpy(pCol->node.aliasName, pFunc->node.aliasName);
|
||||
|
||||
return (SNode*)pCol;
|
||||
}
|
||||
|
||||
static int32_t rewriteUniqueOptCreateProject(SIndefRowsFuncLogicNode* pIndef, SLogicNode** pOutput) {
|
||||
SProjectLogicNode* pProject = (SProjectLogicNode*)nodesMakeNode(QUERY_NODE_LOGIC_PLAN_PROJECT);
|
||||
if (NULL == pProject) {
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
TSWAP(pProject->node.pTargets, pIndef->node.pTargets);
|
||||
pProject->node.precision = pIndef->node.precision;
|
||||
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
SNode* pNode = NULL;
|
||||
FOREACH(pNode, pIndef->pFuncs) {
|
||||
code = nodesListMakeStrictAppend(&pProject->pProjections, rewriteUniqueOptCreateProjectCol((SFunctionNode*)pNode));
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
*pOutput = (SLogicNode*)pProject;
|
||||
} else {
|
||||
nodesDestroyNode((SNode*)pProject);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t rewriteUniqueOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan,
|
||||
SIndefRowsFuncLogicNode* pIndef) {
|
||||
SLogicNode* pAgg = NULL;
|
||||
SLogicNode* pProject = NULL;
|
||||
int32_t code = rewriteUniqueOptCreateAgg(pIndef, &pAgg);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = rewriteUniqueOptCreateProject(pIndef, &pProject);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = nodesListMakeAppend(&pProject->pChildren, (SNode*)pAgg);
|
||||
pAgg->pParent = pProject;
|
||||
pAgg = NULL;
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = replaceLogicNode(pLogicSubplan, (SLogicNode*)pIndef, pProject);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
nodesDestroyNode((SNode*)pIndef);
|
||||
} else {
|
||||
nodesDestroyNode((SNode*)pAgg);
|
||||
nodesDestroyNode((SNode*)pProject);
|
||||
}
|
||||
pCxt->optimized = true;
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t rewriteUniqueOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
|
||||
SIndefRowsFuncLogicNode* pIndef =
|
||||
(SIndefRowsFuncLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, rewriteUniqueOptMayBeOptimized);
|
||||
|
||||
if (NULL == pIndef) {
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
return rewriteUniqueOptimizeImpl(pCxt, pLogicSubplan, pIndef);
|
||||
}
|
||||
|
||||
// merge projects
|
||||
static bool mergeProjectsMayBeOptimized(SLogicNode* pNode) {
|
||||
if (QUERY_NODE_LOGIC_PLAN_PROJECT != nodeType(pNode) || 1 != LIST_LENGTH(pNode->pChildren)) {
|
||||
return false;
|
||||
}
|
||||
SLogicNode *pChild = (SLogicNode*)nodesListGetNode(pNode->pChildren, 0);
|
||||
SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pNode->pChildren, 0);
|
||||
if (QUERY_NODE_LOGIC_PLAN_PROJECT != nodeType(pChild) || 1 < LIST_LENGTH(pChild->pChildren) ||
|
||||
NULL != pChild->pConditions || NULL != pNode->pLimit || NULL != pNode->pSlimit) {
|
||||
NULL != pChild->pConditions || NULL != pChild->pLimit || NULL != pChild->pSlimit) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -1376,12 +1631,12 @@ static bool mergeProjectsMayBeOptimized(SLogicNode* pNode) {
|
|||
|
||||
typedef struct SMergeProjectionsContext {
|
||||
SProjectLogicNode* pChildProj;
|
||||
int32_t errCode;
|
||||
int32_t errCode;
|
||||
} SMergeProjectionsContext;
|
||||
|
||||
static EDealRes mergeProjectionsExpr(SNode** pNode, void* pContext) {
|
||||
SMergeProjectionsContext* pCxt = pContext;
|
||||
SProjectLogicNode* pChildProj = pCxt->pChildProj;
|
||||
SProjectLogicNode* pChildProj = pCxt->pChildProj;
|
||||
if (QUERY_NODE_COLUMN == nodeType(*pNode)) {
|
||||
SNode* pTarget;
|
||||
FOREACH(pTarget, ((SLogicNode*)pChildProj)->pTargets) {
|
||||
|
@ -1406,7 +1661,7 @@ static EDealRes mergeProjectionsExpr(SNode** pNode, void* pContext) {
|
|||
}
|
||||
|
||||
static int32_t mergeProjectsOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan, SLogicNode* pSelfNode) {
|
||||
SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pSelfNode->pChildren, 0);
|
||||
SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pSelfNode->pChildren, 0);
|
||||
SMergeProjectionsContext cxt = {.pChildProj = (SProjectLogicNode*)pChild, .errCode = TSDB_CODE_SUCCESS};
|
||||
|
||||
nodesRewriteExprs(((SProjectLogicNode*)pSelfNode)->pProjections, mergeProjectionsExpr, &cxt);
|
||||
|
@ -1425,6 +1680,7 @@ static int32_t mergeProjectsOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan*
|
|||
NODES_CLEAR_LIST(pChild->pChildren);
|
||||
}
|
||||
nodesDestroyNode((SNode*)pChild);
|
||||
pCxt->optimized = true;
|
||||
return code;
|
||||
}
|
||||
|
||||
|
@ -1447,23 +1703,37 @@ static const SOptimizeRule optimizeRuleSet[] = {
|
|||
{.pName = "MergeProjects", .optimizeFunc = mergeProjectsOptimize},
|
||||
{.pName = "EliminateProject", .optimizeFunc = eliminateProjOptimize},
|
||||
{.pName = "EliminateSetOperator", .optimizeFunc = eliminateSetOpOptimize},
|
||||
{.pName = "RewriteTail", .optimizeFunc = rewriteTailOptimize}
|
||||
{.pName = "RewriteTail", .optimizeFunc = rewriteTailOptimize},
|
||||
{.pName = "RewriteUnique", .optimizeFunc = rewriteUniqueOptimize}
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
static const int32_t optimizeRuleNum = (sizeof(optimizeRuleSet) / sizeof(SOptimizeRule));
|
||||
|
||||
static void dumpLogicSubplan(const char* pRuleName, SLogicSubplan* pSubplan) {
|
||||
char* pStr = NULL;
|
||||
nodesNodeToString((SNode*)pSubplan, false, &pStr, NULL);
|
||||
qDebugL("apply optimize %s rule: %s", pRuleName, pStr);
|
||||
taosMemoryFree(pStr);
|
||||
}
|
||||
|
||||
static int32_t applyOptimizeRule(SPlanContext* pCxt, SLogicSubplan* pLogicSubplan) {
|
||||
SOptimizeContext cxt = {.pPlanCxt = pCxt, .optimized = false};
|
||||
bool optimized = false;
|
||||
do {
|
||||
cxt.optimized = false;
|
||||
optimized = false;
|
||||
for (int32_t i = 0; i < optimizeRuleNum; ++i) {
|
||||
cxt.optimized = false;
|
||||
int32_t code = optimizeRuleSet[i].optimizeFunc(&cxt, pLogicSubplan);
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
return code;
|
||||
}
|
||||
if (cxt.optimized) {
|
||||
optimized = true;
|
||||
dumpLogicSubplan(optimizeRuleSet[i].pName, pLogicSubplan);
|
||||
}
|
||||
}
|
||||
} while (cxt.optimized);
|
||||
} while (optimized);
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -1237,7 +1237,7 @@ static const int32_t splitRuleNum = (sizeof(splitRuleSet) / sizeof(SSplitRule));
|
|||
static void dumpLogicSubplan(const char* pRuleName, SLogicSubplan* pSubplan) {
|
||||
char* pStr = NULL;
|
||||
nodesNodeToString((SNode*)pSubplan, false, &pStr, NULL);
|
||||
qDebugL("apply %s rule: %s", pRuleName, pStr);
|
||||
qDebugL("apply split %s rule: %s", pRuleName, pStr);
|
||||
taosMemoryFree(pStr);
|
||||
}
|
||||
|
||||
|
|
|
@ -85,6 +85,11 @@ int32_t qSetSubplanExecutionNode(SSubplan* subplan, int32_t groupId, SDownstream
|
|||
return setSubplanExecutionNode(subplan->pNode, groupId, pSource);
|
||||
}
|
||||
|
||||
int32_t qClearSubplanExecutionNode(SSubplan* pSubplan, int32_t groupId) {
|
||||
// todo
|
||||
return TSDB_CODE_FAILED;
|
||||
}
|
||||
|
||||
int32_t qSubPlanToString(const SSubplan* pSubplan, char** pStr, int32_t* pLen) {
|
||||
if (SUBPLAN_TYPE_MODIFY == pSubplan->subplanType && NULL == pSubplan->pNode) {
|
||||
SDataInserterNode* insert = (SDataInserterNode*)pSubplan->pDataSink;
|
||||
|
|
|
@ -56,6 +56,8 @@ TEST_F(PlanBasicTest, uniqueFunc) {
|
|||
|
||||
run("SELECT UNIQUE(c2 + 10) FROM t1 WHERE c1 > 10");
|
||||
|
||||
run("SELECT UNIQUE(c2 + 10), c2 FROM t1 WHERE c1 > 10");
|
||||
|
||||
run("SELECT UNIQUE(c2 + 10), ts, c2 FROM t1 WHERE c1 > 10");
|
||||
|
||||
run("SELECT UNIQUE(c1) a FROM t1 ORDER BY a");
|
||||
|
@ -75,6 +77,8 @@ TEST_F(PlanBasicTest, tailFunc) {
|
|||
run("SELECT TAIL(c2 + 10, 10, 80) FROM t1 WHERE c1 > 10 LIMIT 5");
|
||||
|
||||
run("SELECT TAIL(c2 + 10, 10, 80) FROM t1 WHERE c1 > 10 PARTITION BY c1 LIMIT 5");
|
||||
|
||||
run("SELECT TAIL(c1, 2, 1) FROM st1s1 UNION ALL SELECT c1 FROM st1s2");
|
||||
}
|
||||
|
||||
TEST_F(PlanBasicTest, interpFunc) {
|
||||
|
@ -97,6 +101,16 @@ TEST_F(PlanBasicTest, lastRowFunc) {
|
|||
run("SELECT LAST_ROW(c1) FROM st1");
|
||||
}
|
||||
|
||||
TEST_F(PlanBasicTest, sampleFunc) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("SELECT SAMPLE(c1, 10) FROM t1");
|
||||
|
||||
run("SELECT SAMPLE(c1, 10) FROM st1");
|
||||
|
||||
run("SELECT SAMPLE(c1, 10) FROM st1 PARTITION BY TBNAME");
|
||||
}
|
||||
|
||||
TEST_F(PlanBasicTest, withoutFrom) {
|
||||
useDb("root", "test");
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ using namespace std;
|
|||
|
||||
class PlanOptimizeTest : public PlannerTestBase {};
|
||||
|
||||
TEST_F(PlanOptimizeTest, optimizeScanData) {
|
||||
TEST_F(PlanOptimizeTest, scanPath) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("SELECT COUNT(*) FROM t1");
|
||||
|
@ -32,7 +32,7 @@ TEST_F(PlanOptimizeTest, optimizeScanData) {
|
|||
run("SELECT PERCENTILE(c1, 40), COUNT(*) FROM t1");
|
||||
}
|
||||
|
||||
TEST_F(PlanOptimizeTest, ConditionPushDown) {
|
||||
TEST_F(PlanOptimizeTest, pushDownCondition) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("SELECT ts, c1 FROM st1 WHERE tag1 > 4");
|
||||
|
@ -42,9 +42,11 @@ TEST_F(PlanOptimizeTest, ConditionPushDown) {
|
|||
run("SELECT ts, c1 FROM st1 WHERE tag1 > 4 AND tag2 = 'hello'");
|
||||
|
||||
run("SELECT ts, c1 FROM st1 WHERE tag1 > 4 AND tag2 = 'hello' AND c1 > 10");
|
||||
|
||||
run("SELECT ts, c1 FROM (SELECT * FROM st1) WHERE tag1 > 4");
|
||||
}
|
||||
|
||||
TEST_F(PlanOptimizeTest, orderByPrimaryKey) {
|
||||
TEST_F(PlanOptimizeTest, sortPrimaryKey) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("SELECT c1 FROM t1 ORDER BY ts");
|
||||
|
|
|
@ -1488,18 +1488,6 @@ char* syncNode2SimpleStr(const SSyncNode* pSyncNode) {
|
|||
pSyncNode->commitIndex, logBeginIndex, logLastIndex, snapshot.lastApplyIndex, pSyncNode->pRaftCfg->isStandBy,
|
||||
pSyncNode->replicaNum, pSyncNode->pRaftCfg->lastConfigIndex, pSyncNode->changing, pSyncNode->restoreFinish);
|
||||
|
||||
/*
|
||||
snprintf(s, len,
|
||||
"syncNode: vgId:%d, term:%lu, commit:%ld, state:%d %s, standby:%d, "
|
||||
"lc:%lu, "
|
||||
"lc-user:%lu, "
|
||||
"ems:%d, replica-num:%d, restore:%d, changing:%d",
|
||||
pSyncNode->vgId, pSyncNode->pRaftStore->currentTerm, pSyncNode->commitIndex, pSyncNode->state,
|
||||
syncUtilState2String(pSyncNode->state), pSyncNode->pRaftCfg->isStandBy, pSyncNode->electTimerLogicClock,
|
||||
pSyncNode->electTimerLogicClockUser, pSyncNode->electTimerMS, pSyncNode->replicaNum,
|
||||
pSyncNode->restoreFinish, pSyncNode->changing);
|
||||
*/
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
|
|
@ -683,7 +683,16 @@ int32_t syncNodeOnSnapshotSendCb(SSyncNode *pSyncNode, SyncSnapshotSend *pMsg) {
|
|||
needRsp = true;
|
||||
|
||||
} else {
|
||||
ASSERT(0);
|
||||
// error log
|
||||
do {
|
||||
char logBuf[96];
|
||||
snprintf(logBuf, sizeof(logBuf), "snapshot receiver recv error seq:%d, my ack:%d", pMsg->seq, pReceiver->ack);
|
||||
char *eventLog = snapshotReceiver2SimpleStr(pReceiver, logBuf);
|
||||
syncNodeErrorLog(pSyncNode, eventLog);
|
||||
taosMemoryFree(eventLog);
|
||||
} while (0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// send ack
|
||||
|
@ -764,8 +773,8 @@ int32_t syncNodeOnSnapshotRspCb(SSyncNode *pSyncNode, SyncSnapshotRsp *pMsg) {
|
|||
|
||||
} else {
|
||||
do {
|
||||
char logBuf[64];
|
||||
snprintf(logBuf, sizeof(logBuf), "error ack, recv ack:%d, my seq:%d", pMsg->ack, pSender->seq);
|
||||
char logBuf[96];
|
||||
snprintf(logBuf, sizeof(logBuf), "snapshot sender recv error ack:%d, my seq:%d", pMsg->ack, pSender->seq);
|
||||
char *eventLog = snapshotSender2SimpleStr(pSender, logBuf);
|
||||
syncNodeErrorLog(pSyncNode, eventLog);
|
||||
taosMemoryFree(eventLog);
|
||||
|
|
|
@ -301,13 +301,13 @@ class TDTestCase:
|
|||
tdSql.checkRows(1)
|
||||
tdSql.query("select ceil(num1) , min(num1) from tb;")
|
||||
tdSql.checkRows(1)
|
||||
tdSql.error("select udf1(num1) , first(num1) from tb;")
|
||||
tdSql.query("select udf1(num1) , first(num1) from tb;")
|
||||
|
||||
tdSql.error("select abs(num1) , first(num1) from tb;")
|
||||
tdSql.query("select abs(num1) , first(num1) from tb;")
|
||||
|
||||
tdSql.error("select udf1(num1) , last(num1) from tb;")
|
||||
tdSql.query("select udf1(num1) , last(num1) from tb;")
|
||||
|
||||
tdSql.error("select round(num1) , last(num1) from tb;")
|
||||
tdSql.query("select round(num1) , last(num1) from tb;")
|
||||
|
||||
tdSql.query("select udf1(num1) , top(num1,1) from tb;")
|
||||
tdSql.checkRows(1)
|
||||
|
@ -327,9 +327,9 @@ class TDTestCase:
|
|||
tdSql.checkRows(1)
|
||||
tdSql.query("select floor(c1) , min(c1) from stb1;")
|
||||
tdSql.checkRows(1)
|
||||
tdSql.error("select udf1(c1) , first(c1) from stb1;")
|
||||
tdSql.query("select udf1(c1) , first(c1) from stb1;")
|
||||
|
||||
tdSql.error("select udf1(c1) , last(c1) from stb1;")
|
||||
tdSql.query("select udf1(c1) , last(c1) from stb1;")
|
||||
|
||||
tdSql.query("select udf1(c1) , top(c1 ,1) from stb1;")
|
||||
tdSql.checkRows(1)
|
||||
|
|
|
@ -303,13 +303,13 @@ class TDTestCase:
|
|||
tdSql.checkRows(1)
|
||||
tdSql.query("select ceil(num1) , min(num1) from tb;")
|
||||
tdSql.checkRows(1)
|
||||
tdSql.error("select udf1(num1) , first(num1) from tb;")
|
||||
tdSql.query("select udf1(num1) , first(num1) from tb;")
|
||||
|
||||
tdSql.error("select abs(num1) , first(num1) from tb;")
|
||||
tdSql.query("select abs(num1) , first(num1) from tb;")
|
||||
|
||||
tdSql.error("select udf1(num1) , last(num1) from tb;")
|
||||
tdSql.query("select udf1(num1) , last(num1) from tb;")
|
||||
|
||||
tdSql.error("select round(num1) , last(num1) from tb;")
|
||||
tdSql.query("select round(num1) , last(num1) from tb;")
|
||||
|
||||
tdSql.query("select udf1(num1) , top(num1,1) from tb;")
|
||||
tdSql.checkRows(1)
|
||||
|
@ -329,9 +329,9 @@ class TDTestCase:
|
|||
tdSql.checkRows(1)
|
||||
tdSql.query("select floor(c1) , min(c1) from stb1;")
|
||||
tdSql.checkRows(1)
|
||||
tdSql.error("select udf1(c1) , first(c1) from stb1;")
|
||||
tdSql.query("select udf1(c1) , first(c1) from stb1;")
|
||||
|
||||
tdSql.error("select udf1(c1) , last(c1) from stb1;")
|
||||
tdSql.query("select udf1(c1) , last(c1) from stb1;")
|
||||
|
||||
tdSql.query("select udf1(c1) , top(c1 ,1) from stb1;")
|
||||
tdSql.checkRows(1)
|
||||
|
|
|
@ -300,13 +300,13 @@ class TDTestCase:
|
|||
tdSql.checkRows(1)
|
||||
tdSql.query("select ceil(num1) , min(num1) from tb;")
|
||||
tdSql.checkRows(1)
|
||||
tdSql.error("select udf1(num1) , first(num1) from tb;")
|
||||
tdSql.query("select udf1(num1) , first(num1) from tb;")
|
||||
|
||||
tdSql.error("select abs(num1) , first(num1) from tb;")
|
||||
tdSql.query("select abs(num1) , first(num1) from tb;")
|
||||
|
||||
tdSql.error("select udf1(num1) , last(num1) from tb;")
|
||||
tdSql.query("select udf1(num1) , last(num1) from tb;")
|
||||
|
||||
tdSql.error("select round(num1) , last(num1) from tb;")
|
||||
tdSql.query("select round(num1) , last(num1) from tb;")
|
||||
|
||||
tdSql.query("select udf1(num1) , top(num1,1) from tb;")
|
||||
tdSql.checkRows(1)
|
||||
|
@ -326,9 +326,9 @@ class TDTestCase:
|
|||
tdSql.checkRows(1)
|
||||
tdSql.query("select floor(c1) , min(c1) from stb1;")
|
||||
tdSql.checkRows(1)
|
||||
tdSql.error("select udf1(c1) , first(c1) from stb1;")
|
||||
tdSql.query("select udf1(c1) , first(c1) from stb1;")
|
||||
|
||||
tdSql.error("select udf1(c1) , last(c1) from stb1;")
|
||||
tdSql.query("select udf1(c1) , last(c1) from stb1;")
|
||||
|
||||
tdSql.query("select udf1(c1) , top(c1 ,1) from stb1;")
|
||||
tdSql.checkRows(1)
|
||||
|
|
|
@ -266,7 +266,7 @@ class TDTestCase:
|
|||
tdSql.query("select unique(c1) from ct4")
|
||||
tdSql.checkRows(10)
|
||||
|
||||
tdSql.error("select unique(c1),tbname from ct1")
|
||||
#tdSql.error("select unique(c1),tbname from ct1") #support
|
||||
#tdSql.error("select unique(c1),t1 from ct1") #support
|
||||
|
||||
# unique with common col
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit a875a057d1225d85c6323b9edaccc2b1a9641987
|
||||
Subproject commit 28a49b447f71c4f014ebbac858b7215b897d57fd
|
Loading…
Reference in New Issue