planOptimizer.c 42.7 KB
Newer Older
X
Xiaoyu Wang 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
 *
 * This program is free software: you can use, redistribute, and/or modify
 * it under the terms of the GNU Affero General Public License, version 3
 * or later ("AGPL"), as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

16
#include "filter.h"
X
Xiaoyu Wang 已提交
17
#include "functionMgt.h"
X
Xiaoyu Wang 已提交
18
#include "index.h"
X
Xiaoyu Wang 已提交
19
#include "planInt.h"
X
Xiaoyu Wang 已提交
20
#include "ttime.h"
X
Xiaoyu Wang 已提交
21

X
Xiaoyu Wang 已提交
22
#define OPTIMIZE_FLAG_MASK(n) (1 << n)
23 24

#define OPTIMIZE_FLAG_OSD OPTIMIZE_FLAG_MASK(0)
X
Xiaoyu Wang 已提交
25 26
#define OPTIMIZE_FLAG_CPD OPTIMIZE_FLAG_MASK(1)
#define OPTIMIZE_FLAG_OPK OPTIMIZE_FLAG_MASK(2)
27

X
Xiaoyu Wang 已提交
28
#define OPTIMIZE_FLAG_SET_MASK(val, mask)  (val) |= (mask)
29 30 31
#define OPTIMIZE_FLAG_TEST_MASK(val, mask) (((val) & (mask)) != 0)

typedef struct SOptimizeContext {
X
Xiaoyu Wang 已提交
32
  SPlanContext* pPlanCxt;
X
Xiaoyu Wang 已提交
33
  bool          optimized;
34 35
} SOptimizeContext;

X
Xiaoyu Wang 已提交
36
typedef int32_t (*FOptimize)(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan);
37 38

typedef struct SOptimizeRule {
X
Xiaoyu Wang 已提交
39
  char*     pName;
40 41 42 43 44
  FOptimize optimizeFunc;
} SOptimizeRule;

typedef struct SOsdInfo {
  SScanLogicNode* pScan;
X
Xiaoyu Wang 已提交
45 46
  SNodeList*      pSdrFuncs;
  SNodeList*      pDsoFuncs;
47 48
} SOsdInfo;

49 50 51
typedef struct SCpdIsMultiTableCondCxt {
  SNodeList* pLeftCols;
  SNodeList* pRightCols;
X
Xiaoyu Wang 已提交
52 53
  bool       havaLeftCol;
  bool       haveRightCol;
54 55 56 57 58 59 60 61 62 63
} SCpdIsMultiTableCondCxt;

typedef enum ECondAction {
  COND_ACTION_STAY = 1,
  COND_ACTION_PUSH_JOIN,
  COND_ACTION_PUSH_LEFT_CHILD,
  COND_ACTION_PUSH_RIGHT_CHILD
  // after supporting outer join, there are other possibilities
} ECondAction;

X
Xiaoyu Wang 已提交
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
typedef bool (*FMayBeOptimized)(SLogicNode* pNode);

static SLogicNode* optFindPossibleNode(SLogicNode* pNode, FMayBeOptimized func) {
  if (func(pNode)) {
    return pNode;
  }
  SNode* pChild;
  FOREACH(pChild, pNode->pChildren) {
    SLogicNode* pScanNode = optFindPossibleNode((SLogicNode*)pChild, func);
    if (NULL != pScanNode) {
      return pScanNode;
    }
  }
  return NULL;
}

EDealRes osdHaveNormalColImpl(SNode* pNode, void* pContext) {
81 82 83 84 85 86 87
  if (QUERY_NODE_COLUMN == nodeType(pNode)) {
    *((bool*)pContext) = (COLUMN_TYPE_TAG != ((SColumnNode*)pNode)->colType);
    return *((bool*)pContext) ? DEAL_RES_END : DEAL_RES_IGNORE_CHILD;
  }
  return DEAL_RES_CONTINUE;
}

X
Xiaoyu Wang 已提交
88
static bool osdHaveNormalCol(SNodeList* pList) {
89
  bool res = false;
X
Xiaoyu Wang 已提交
90
  nodesWalkExprsPostOrder(pList, osdHaveNormalColImpl, &res);
91 92 93
  return res;
}

94 95 96 97 98 99 100
static bool osdMayBeOptimized(SLogicNode* pNode) {
  if (OPTIMIZE_FLAG_TEST_MASK(pNode->optimizedFlag, OPTIMIZE_FLAG_OSD)) {
    return false;
  }
  if (QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(pNode)) {
    return false;
  }
X
Xiaoyu Wang 已提交
101
  if (NULL == pNode->pParent || (QUERY_NODE_LOGIC_PLAN_WINDOW != nodeType(pNode->pParent) &&
102 103
                                 QUERY_NODE_LOGIC_PLAN_AGG != nodeType(pNode->pParent) &&
                                 QUERY_NODE_LOGIC_PLAN_PARTITION != nodeType(pNode->pParent))) {
104 105
    return false;
  }
106
  if (QUERY_NODE_LOGIC_PLAN_WINDOW == nodeType(pNode->pParent) ||
X
Xiaoyu Wang 已提交
107 108
      (QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pNode->pParent) && pNode->pParent->pParent &&
       QUERY_NODE_LOGIC_PLAN_WINDOW == nodeType(pNode->pParent->pParent))) {
5
54liuyao 已提交
109
    return true;
110
  }
X
Xiaoyu Wang 已提交
111
  return !osdHaveNormalCol(((SAggLogicNode*)pNode->pParent)->pGroupKeys);
112 113 114 115 116 117 118 119 120 121 122 123 124 125
}

static SNodeList* osdGetAllFuncs(SLogicNode* pNode) {
  switch (nodeType(pNode)) {
    case QUERY_NODE_LOGIC_PLAN_WINDOW:
      return ((SWindowLogicNode*)pNode)->pFuncs;
    case QUERY_NODE_LOGIC_PLAN_AGG:
      return ((SAggLogicNode*)pNode)->pAggFuncs;
    default:
      break;
  }
  return NULL;
}

126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
static bool needOptimizeDataRequire(const SFunctionNode* pFunc) {
  if (!fmIsSpecialDataRequiredFunc(pFunc->funcId)) {
    return false;
  }
  SNode* pPara = NULL;
  FOREACH(pPara, pFunc->pParameterList) {
    if (QUERY_NODE_COLUMN != nodeType(pPara) && QUERY_NODE_VALUE != nodeType(pPara)) {
      return false;
    }
  }
  return true;
}

static bool needOptimizeDynamicScan(const SFunctionNode* pFunc) {
  if (!fmIsDynamicScanOptimizedFunc(pFunc->funcId)) {
    return false;
  }
  SNode* pPara = NULL;
  FOREACH(pPara, pFunc->pParameterList) {
    if (QUERY_NODE_COLUMN != nodeType(pPara) && QUERY_NODE_VALUE != nodeType(pPara)) {
      return false;
    }
  }
  return true;
}

152 153
static int32_t osdGetRelatedFuncs(SScanLogicNode* pScan, SNodeList** pSdrFuncs, SNodeList** pDsoFuncs) {
  SNodeList* pAllFuncs = osdGetAllFuncs(pScan->node.pParent);
X
Xiaoyu Wang 已提交
154 155
  SNodeList* pTmpSdrFuncs = NULL;
  SNodeList* pTmpDsoFuncs = NULL;
X
Xiaoyu Wang 已提交
156
  SNode*     pFunc = NULL;
X
Xiaoyu Wang 已提交
157
  bool       otherFunc = false;
158 159
  FOREACH(pFunc, pAllFuncs) {
    int32_t code = TSDB_CODE_SUCCESS;
160
    if (needOptimizeDataRequire((SFunctionNode*)pFunc)) {
X
Xiaoyu Wang 已提交
161
      code = nodesListMakeStrictAppend(&pTmpSdrFuncs, nodesCloneNode(pFunc));
162
    } else if (needOptimizeDynamicScan((SFunctionNode*)pFunc)) {
X
Xiaoyu Wang 已提交
163 164 165
      code = nodesListMakeStrictAppend(&pTmpDsoFuncs, nodesCloneNode(pFunc));
    } else {
      otherFunc = true;
166 167
    }
    if (TSDB_CODE_SUCCESS != code) {
X
Xiaoyu Wang 已提交
168 169
      nodesDestroyList(pTmpSdrFuncs);
      nodesDestroyList(pTmpDsoFuncs);
170 171
      return code;
    }
X
Xiaoyu Wang 已提交
172
  }
X
Xiaoyu Wang 已提交
173 174 175 176 177 178 179
  if (otherFunc) {
    nodesDestroyList(pTmpSdrFuncs);
    nodesDestroyList(pTmpDsoFuncs);
  } else {
    *pSdrFuncs = pTmpSdrFuncs;
    *pDsoFuncs = pTmpDsoFuncs;
  }
180 181 182 183
  return TSDB_CODE_SUCCESS;
}

static int32_t osdMatch(SOptimizeContext* pCxt, SLogicNode* pLogicNode, SOsdInfo* pInfo) {
X
Xiaoyu Wang 已提交
184
  pInfo->pScan = (SScanLogicNode*)optFindPossibleNode(pLogicNode, osdMayBeOptimized);
185 186 187 188 189 190
  if (NULL == pInfo->pScan) {
    return TSDB_CODE_SUCCESS;
  }
  return osdGetRelatedFuncs(pInfo->pScan, &pInfo->pSdrFuncs, &pInfo->pDsoFuncs);
}

X
Xiaoyu Wang 已提交
191
static EFuncDataRequired osdPromoteDataRequired(EFuncDataRequired l, EFuncDataRequired r) {
192
  switch (l) {
193
    case FUNC_DATA_REQUIRED_DATA_LOAD:
194
      return l;
195 196 197 198
    case FUNC_DATA_REQUIRED_STATIS_LOAD:
      return FUNC_DATA_REQUIRED_DATA_LOAD == r ? r : l;
    case FUNC_DATA_REQUIRED_NOT_LOAD:
      return FUNC_DATA_REQUIRED_FILTEROUT == r ? l : r;
199 200 201 202 203 204 205 206
    default:
      break;
  }
  return r;
}

static int32_t osdGetDataRequired(SNodeList* pFuncs) {
  if (NULL == pFuncs) {
207
    return FUNC_DATA_REQUIRED_DATA_LOAD;
208
  }
209
  EFuncDataRequired dataRequired = FUNC_DATA_REQUIRED_FILTEROUT;
X
Xiaoyu Wang 已提交
210
  SNode*            pFunc = NULL;
211 212 213 214 215 216
  FOREACH(pFunc, pFuncs) {
    dataRequired = osdPromoteDataRequired(dataRequired, fmFuncDataRequired((SFunctionNode*)pFunc, NULL));
  }
  return dataRequired;
}

X
Xiaoyu Wang 已提交
217
static void setScanWindowInfo(SScanLogicNode* pScan) {
218
  SLogicNode* pParent = pScan->node.pParent;
X
Xiaoyu Wang 已提交
219 220
  if (QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pParent) && pParent->pParent &&
      QUERY_NODE_LOGIC_PLAN_WINDOW == nodeType(pParent->pParent)) {
221 222 223 224 225 226 227 228 229 230 231 232
    pParent = pParent->pParent;
  }
  if (QUERY_NODE_LOGIC_PLAN_WINDOW == nodeType(pParent)) {
    pScan->interval = ((SWindowLogicNode*)pParent)->interval;
    pScan->offset = ((SWindowLogicNode*)pParent)->offset;
    pScan->sliding = ((SWindowLogicNode*)pParent)->sliding;
    pScan->intervalUnit = ((SWindowLogicNode*)pParent)->intervalUnit;
    pScan->slidingUnit = ((SWindowLogicNode*)pParent)->slidingUnit;
    pScan->triggerType = ((SWindowLogicNode*)pParent)->triggerType;
    pScan->watermark = ((SWindowLogicNode*)pParent)->watermark;
    pScan->tsColId = ((SColumnNode*)((SWindowLogicNode*)pParent)->pTspk)->colId;
    pScan->filesFactor = ((SWindowLogicNode*)pParent)->filesFactor;
X
Xiaoyu Wang 已提交
233 234 235
  }
}

X
Xiaoyu Wang 已提交
236
static int32_t osdOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
237
  SOsdInfo info = {0};
X
Xiaoyu Wang 已提交
238
  int32_t  code = osdMatch(pCxt, pLogicSubplan->pNode, &info);
5
54liuyao 已提交
239 240 241
  if (TSDB_CODE_SUCCESS == code && info.pScan) {
    setScanWindowInfo((SScanLogicNode*)info.pScan);
  }
242 243 244 245 246 247 248 249 250 251
  if (TSDB_CODE_SUCCESS == code && (NULL != info.pDsoFuncs || NULL != info.pSdrFuncs)) {
    info.pScan->dataRequired = osdGetDataRequired(info.pSdrFuncs);
    info.pScan->pDynamicScanFuncs = info.pDsoFuncs;
    OPTIMIZE_FLAG_SET_MASK(info.pScan->node.optimizedFlag, OPTIMIZE_FLAG_OSD);
    pCxt->optimized = true;
  }
  nodesDestroyList(info.pSdrFuncs);
  return code;
}

252
static int32_t cpdMergeCond(SNode** pDst, SNode** pSrc) {
253
  SLogicConditionNode* pLogicCond = (SLogicConditionNode*)nodesMakeNode(QUERY_NODE_LOGIC_CONDITION);
254 255 256
  if (NULL == pLogicCond) {
    return TSDB_CODE_OUT_OF_MEMORY;
  }
D
dapan1121 已提交
257 258
  pLogicCond->node.resType.type = TSDB_DATA_TYPE_BOOL;
  pLogicCond->node.resType.bytes = tDataTypes[TSDB_DATA_TYPE_BOOL].bytes;
259 260 261 262 263 264 265 266 267
  pLogicCond->condType = LOGIC_COND_TYPE_AND;
  int32_t code = nodesListMakeAppend(&pLogicCond->pParameterList, *pSrc);
  if (TSDB_CODE_SUCCESS == code) {
    *pSrc = NULL;
    code = nodesListMakeAppend(&pLogicCond->pParameterList, *pDst);
  }
  if (TSDB_CODE_SUCCESS == code) {
    *pDst = (SNode*)pLogicCond;
  } else {
268
    nodesDestroyNode((SNode*)pLogicCond);
269 270 271 272 273 274
  }
  return code;
}

static int32_t cpdCondAppend(SNode** pCond, SNode** pAdditionalCond) {
  if (NULL == *pCond) {
wafwerar's avatar
wafwerar 已提交
275
    TSWAP(*pCond, *pAdditionalCond);
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
    return TSDB_CODE_SUCCESS;
  }

  int32_t code = TSDB_CODE_SUCCESS;
  if (QUERY_NODE_LOGIC_CONDITION == nodeType(*pCond)) {
    code = nodesListAppend(((SLogicConditionNode*)*pCond)->pParameterList, *pAdditionalCond);
    if (TSDB_CODE_SUCCESS == code) {
      *pAdditionalCond = NULL;
    }
  } else {
    code = cpdMergeCond(pCond, pAdditionalCond);
  }
  return code;
}

291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
static int32_t cpdCalcTimeRange(SOptimizeContext* pCxt, SScanLogicNode* pScan, SNode** pPrimaryKeyCond,
                                SNode** pOtherCond) {
  int32_t code = TSDB_CODE_SUCCESS;
  if (pCxt->pPlanCxt->topicQuery || pCxt->pPlanCxt->streamQuery) {
    code = cpdCondAppend(pOtherCond, pPrimaryKeyCond);
  } else {
    bool isStrict = false;
    code = filterGetTimeRange(*pPrimaryKeyCond, &pScan->scanRange, &isStrict);
    if (TSDB_CODE_SUCCESS == code) {
      if (isStrict) {
        nodesDestroyNode(*pPrimaryKeyCond);
      } else {
        code = cpdCondAppend(pOtherCond, pPrimaryKeyCond);
      }
      *pPrimaryKeyCond = NULL;
306 307 308 309 310
    }
  }
  return code;
}

X
Xiaoyu Wang 已提交
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
static int32_t cpdApplyTagIndex(SScanLogicNode* pScan, SNode** pTagCond, SNode** pOtherCond) {
  int32_t       code = TSDB_CODE_SUCCESS;
  SIdxFltStatus idxStatus = idxGetFltStatus(*pTagCond);
  switch (idxStatus) {
    case SFLT_NOT_INDEX:
      code = cpdCondAppend(pOtherCond, pTagCond);
      break;
    case SFLT_COARSE_INDEX:
      pScan->pTagCond = nodesCloneNode(*pTagCond);
      if (NULL == pScan->pTagCond) {
        code = TSDB_CODE_OUT_OF_MEMORY;
        break;
      }
      code = cpdCondAppend(pOtherCond, pTagCond);
      break;
    case SFLT_ACCURATE_INDEX:
      pScan->pTagCond = *pTagCond;
      *pTagCond = NULL;
      break;
    default:
      code = TSDB_CODE_FAILED;
      break;
  }
  return code;
}

337
static int32_t cpdOptimizeScanCondition(SOptimizeContext* pCxt, SScanLogicNode* pScan) {
X
Xiaoyu Wang 已提交
338
  if (NULL == pScan->node.pConditions || OPTIMIZE_FLAG_TEST_MASK(pScan->node.optimizedFlag, OPTIMIZE_FLAG_CPD) ||
X
Xiaoyu Wang 已提交
339
      TSDB_SYSTEM_TABLE == pScan->tableType) {
340 341 342
    return TSDB_CODE_SUCCESS;
  }

X
Xiaoyu Wang 已提交
343
  SNode*  pPrimaryKeyCond = NULL;
X
Xiaoyu Wang 已提交
344
  SNode*  pTagCond = NULL;
X
Xiaoyu Wang 已提交
345
  SNode*  pOtherCond = NULL;
X
Xiaoyu Wang 已提交
346
  int32_t code = nodesPartitionCond(&pScan->node.pConditions, &pPrimaryKeyCond, &pTagCond, &pOtherCond);
347
  if (TSDB_CODE_SUCCESS == code && NULL != pPrimaryKeyCond) {
348
    code = cpdCalcTimeRange(pCxt, pScan, &pPrimaryKeyCond, &pOtherCond);
349
  }
X
Xiaoyu Wang 已提交
350 351 352
  if (TSDB_CODE_SUCCESS == code && NULL != pTagCond) {
    code = cpdApplyTagIndex(pScan, &pTagCond, &pOtherCond);
  }
353 354 355 356
  if (TSDB_CODE_SUCCESS == code) {
    pScan->node.pConditions = pOtherCond;
  }

X
Xiaoyu Wang 已提交
357 358 359 360
  if (TSDB_CODE_SUCCESS == code) {
    OPTIMIZE_FLAG_SET_MASK(pScan->node.optimizedFlag, OPTIMIZE_FLAG_CPD);
    pCxt->optimized = true;
  } else {
361 362 363 364 365 366 367
    nodesDestroyNode(pPrimaryKeyCond);
    nodesDestroyNode(pOtherCond);
  }

  return code;
}

X
Xiaoyu Wang 已提交
368
static bool cpdBelongThisTable(SNode* pCondCol, SNodeList* pTableCols) {
369 370 371 372 373 374 375
  SNode* pTableCol = NULL;
  FOREACH(pTableCol, pTableCols) {
    if (nodesEqualNode(pCondCol, pTableCol)) {
      return true;
    }
  }
  return false;
376 377
}

378 379 380
static EDealRes cpdIsMultiTableCondImpl(SNode* pNode, void* pContext) {
  SCpdIsMultiTableCondCxt* pCxt = pContext;
  if (QUERY_NODE_COLUMN == nodeType(pNode)) {
X
Xiaoyu Wang 已提交
381
    if (cpdBelongThisTable(pNode, pCxt->pLeftCols)) {
382
      pCxt->havaLeftCol = true;
X
Xiaoyu Wang 已提交
383
    } else if (cpdBelongThisTable(pNode, pCxt->pRightCols)) {
384 385 386 387 388
      pCxt->haveRightCol = true;
    }
    return pCxt->havaLeftCol && pCxt->haveRightCol ? DEAL_RES_END : DEAL_RES_CONTINUE;
  }
  return DEAL_RES_CONTINUE;
389 390
}

391
static ECondAction cpdCondAction(EJoinType joinType, SNodeList* pLeftCols, SNodeList* pRightCols, SNode* pNode) {
X
Xiaoyu Wang 已提交
392 393
  SCpdIsMultiTableCondCxt cxt = {
      .pLeftCols = pLeftCols, .pRightCols = pRightCols, .havaLeftCol = false, .haveRightCol = false};
394
  nodesWalkExpr(pNode, cpdIsMultiTableCondImpl, &cxt);
X
Xiaoyu Wang 已提交
395 396 397 398 399
  return (JOIN_TYPE_INNER != joinType
              ? COND_ACTION_STAY
              : (cxt.havaLeftCol && cxt.haveRightCol
                     ? COND_ACTION_PUSH_JOIN
                     : (cxt.havaLeftCol ? COND_ACTION_PUSH_LEFT_CHILD : COND_ACTION_PUSH_RIGHT_CHILD)));
400 401
}

X
Xiaoyu Wang 已提交
402 403
static int32_t cpdPartitionLogicCond(SJoinLogicNode* pJoin, SNode** pOnCond, SNode** pLeftChildCond,
                                     SNode** pRightChildCond) {
404 405 406 407 408 409 410
  SLogicConditionNode* pLogicCond = (SLogicConditionNode*)pJoin->node.pConditions;
  if (LOGIC_COND_TYPE_AND != pLogicCond->condType) {
    return TSDB_CODE_SUCCESS;
  }

  SNodeList* pLeftCols = ((SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 0))->pTargets;
  SNodeList* pRightCols = ((SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 1))->pTargets;
X
Xiaoyu Wang 已提交
411
  int32_t    code = TSDB_CODE_SUCCESS;
412 413 414 415 416

  SNodeList* pOnConds = NULL;
  SNodeList* pLeftChildConds = NULL;
  SNodeList* pRightChildConds = NULL;
  SNodeList* pRemainConds = NULL;
X
Xiaoyu Wang 已提交
417
  SNode*     pCond = NULL;
418 419 420 421 422 423 424 425 426 427
  FOREACH(pCond, pLogicCond->pParameterList) {
    ECondAction condAction = cpdCondAction(pJoin->joinType, pLeftCols, pRightCols, pCond);
    if (COND_ACTION_PUSH_JOIN == condAction) {
      code = nodesListMakeAppend(&pOnConds, nodesCloneNode(pCond));
    } else if (COND_ACTION_PUSH_LEFT_CHILD == condAction) {
      code = nodesListMakeAppend(&pLeftChildConds, nodesCloneNode(pCond));
    } else if (COND_ACTION_PUSH_RIGHT_CHILD == condAction) {
      code = nodesListMakeAppend(&pRightChildConds, nodesCloneNode(pCond));
    } else {
      code = nodesListMakeAppend(&pRemainConds, nodesCloneNode(pCond));
428
    }
429 430
    if (TSDB_CODE_SUCCESS != code) {
      break;
431 432
    }
  }
433 434 435 436 437 438

  SNode* pTempOnCond = NULL;
  SNode* pTempLeftChildCond = NULL;
  SNode* pTempRightChildCond = NULL;
  SNode* pTempRemainCond = NULL;
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
439
    code = nodesMergeConds(&pTempOnCond, &pOnConds);
440 441
  }
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
442
    code = nodesMergeConds(&pTempLeftChildCond, &pLeftChildConds);
443 444
  }
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
445
    code = nodesMergeConds(&pTempRightChildCond, &pRightChildConds);
446 447
  }
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
448
    code = nodesMergeConds(&pTempRemainCond, &pRemainConds);
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
  }

  if (TSDB_CODE_SUCCESS == code) {
    *pOnCond = pTempOnCond;
    *pLeftChildCond = pTempLeftChildCond;
    *pRightChildCond = pTempRightChildCond;
    nodesDestroyNode(pJoin->node.pConditions);
    pJoin->node.pConditions = pTempRemainCond;
  } else {
    nodesDestroyList(pOnConds);
    nodesDestroyList(pLeftChildConds);
    nodesDestroyList(pRightChildConds);
    nodesDestroyList(pRemainConds);
    nodesDestroyNode(pTempOnCond);
    nodesDestroyNode(pTempLeftChildCond);
    nodesDestroyNode(pTempRightChildCond);
    nodesDestroyNode(pTempRemainCond);
  }

  return code;
}

X
Xiaoyu Wang 已提交
471 472 473 474
static int32_t cpdPartitionOpCond(SJoinLogicNode* pJoin, SNode** pOnCond, SNode** pLeftChildCond,
                                  SNode** pRightChildCond) {
  SNodeList*  pLeftCols = ((SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 0))->pTargets;
  SNodeList*  pRightCols = ((SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 1))->pTargets;
475 476 477 478 479 480 481 482 483 484 485
  ECondAction condAction = cpdCondAction(pJoin->joinType, pLeftCols, pRightCols, pJoin->node.pConditions);
  if (COND_ACTION_STAY == condAction) {
    return TSDB_CODE_SUCCESS;
  } else if (COND_ACTION_PUSH_JOIN == condAction) {
    *pOnCond = pJoin->node.pConditions;
  } else if (COND_ACTION_PUSH_LEFT_CHILD == condAction) {
    *pLeftChildCond = pJoin->node.pConditions;
  } else if (COND_ACTION_PUSH_RIGHT_CHILD == condAction) {
    *pRightChildCond = pJoin->node.pConditions;
  }
  pJoin->node.pConditions = NULL;
486 487 488
  return TSDB_CODE_SUCCESS;
}

X
Xiaoyu Wang 已提交
489 490
static int32_t cpdPartitionCond(SJoinLogicNode* pJoin, SNode** pOnCond, SNode** pLeftChildCond,
                                SNode** pRightChildCond) {
491 492 493 494 495 496 497 498
  if (QUERY_NODE_LOGIC_CONDITION == nodeType(pJoin->node.pConditions)) {
    return cpdPartitionLogicCond(pJoin, pOnCond, pLeftChildCond, pRightChildCond);
  } else {
    return cpdPartitionOpCond(pJoin, pOnCond, pLeftChildCond, pRightChildCond);
  }
}

static int32_t cpdPushCondToOnCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin, SNode** pCond) {
499
  return cpdCondAppend(&pJoin->pOnConditions, pCond);
500 501 502
}

static int32_t cpdPushCondToScan(SOptimizeContext* pCxt, SScanLogicNode* pScan, SNode** pCond) {
503
  return cpdCondAppend(&pScan->node.pConditions, pCond);
504 505 506 507 508
}

static int32_t cpdPushCondToChild(SOptimizeContext* pCxt, SLogicNode* pChild, SNode** pCond) {
  switch (nodeType(pChild)) {
    case QUERY_NODE_LOGIC_PLAN_SCAN:
X
Xiaoyu Wang 已提交
509
      return cpdPushCondToScan(pCxt, (SScanLogicNode*)pChild, pCond);
510 511 512
    default:
      break;
  }
513
  planError("cpdPushCondToChild failed, invalid logic plan node %s", nodesNodeName(nodeType(pChild)));
514 515 516
  return TSDB_CODE_PLAN_INTERNAL_ERROR;
}

X
Xiaoyu Wang 已提交
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
static bool cpdIsPrimaryKey(SNode* pNode, SNodeList* pTableCols) {
  if (QUERY_NODE_COLUMN != nodeType(pNode)) {
    return false;
  }
  SColumnNode* pCol = (SColumnNode*)pNode;
  if (PRIMARYKEY_TIMESTAMP_COL_ID != pCol->colId) {
    return false;
  }
  return cpdBelongThisTable(pNode, pTableCols);
}

static bool cpdIsPrimaryKeyEqualCond(SJoinLogicNode* pJoin, SNode* pCond) {
  if (QUERY_NODE_OPERATOR != nodeType(pCond)) {
    return false;
  }
532

533
  SOperatorNode* pOper = (SOperatorNode*)pCond;
534 535 536 537 538 539
  if (OP_TYPE_EQUAL != pOper->opType) {
    return false;
  }

  SNodeList* pLeftCols = ((SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 0))->pTargets;
  SNodeList* pRightCols = ((SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 1))->pTargets;
X
Xiaoyu Wang 已提交
540 541 542 543 544 545 546 547
  if (cpdIsPrimaryKey(pOper->pLeft, pLeftCols)) {
    return cpdIsPrimaryKey(pOper->pRight, pRightCols);
  } else if (cpdIsPrimaryKey(pOper->pLeft, pRightCols)) {
    return cpdIsPrimaryKey(pOper->pRight, pLeftCols);
  }
  return false;
}

548 549 550 551 552
static bool cpdContainPrimaryKeyEqualCond(SJoinLogicNode* pJoin, SNode* pCond) {
  if (QUERY_NODE_LOGIC_CONDITION == nodeType(pCond)) {
    SLogicConditionNode* pLogicCond = (SLogicConditionNode*)pCond;
    if (LOGIC_COND_TYPE_AND != pLogicCond->condType) {
      return false;
X
Xiaoyu Wang 已提交
553
    }
554 555 556 557 558 559 560 561 562 563 564 565 566 567
    bool   hasPrimaryKeyEqualCond = false;
    SNode* pCond = NULL;
    FOREACH(pCond, pLogicCond->pParameterList) {
      if (cpdContainPrimaryKeyEqualCond(pJoin, pCond)) {
        hasPrimaryKeyEqualCond = true;
        break;
      }
    }
    return hasPrimaryKeyEqualCond;
  } else {
    return cpdIsPrimaryKeyEqualCond(pJoin, pCond);
  }
}

X
Xiaoyu Wang 已提交
568 569
static int32_t cpdCheckJoinOnCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) {
  if (NULL == pJoin->pOnConditions) {
X
Xiaoyu Wang 已提交
570
    return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_NOT_SUPPORT_CROSS_JOIN);
X
Xiaoyu Wang 已提交
571
  }
572 573
  if (!cpdContainPrimaryKeyEqualCond(pJoin, pJoin->pOnConditions)) {
    return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_EXPECTED_TS_EQUAL);
X
Xiaoyu Wang 已提交
574
  }
575
  return TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
576 577
}

578
static int32_t cpdPushJoinCondition(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) {
X
Xiaoyu Wang 已提交
579
  if (OPTIMIZE_FLAG_TEST_MASK(pJoin->node.optimizedFlag, OPTIMIZE_FLAG_CPD)) {
580 581 582
    return TSDB_CODE_SUCCESS;
  }

X
Xiaoyu Wang 已提交
583 584 585 586
  if (NULL == pJoin->node.pConditions) {
    return cpdCheckJoinOnCond(pCxt, pJoin);
  }

X
Xiaoyu Wang 已提交
587 588 589
  SNode*  pOnCond = NULL;
  SNode*  pLeftChildCond = NULL;
  SNode*  pRightChildCond = NULL;
590 591 592 593 594 595 596 597 598 599 600
  int32_t code = cpdPartitionCond(pJoin, &pOnCond, &pLeftChildCond, &pRightChildCond);
  if (TSDB_CODE_SUCCESS == code && NULL != pOnCond) {
    code = cpdPushCondToOnCond(pCxt, pJoin, &pOnCond);
  }
  if (TSDB_CODE_SUCCESS == code && NULL != pLeftChildCond) {
    code = cpdPushCondToChild(pCxt, (SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 0), &pLeftChildCond);
  }
  if (TSDB_CODE_SUCCESS == code && NULL != pRightChildCond) {
    code = cpdPushCondToChild(pCxt, (SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 1), &pRightChildCond);
  }

X
Xiaoyu Wang 已提交
601 602 603
  if (TSDB_CODE_SUCCESS == code) {
    OPTIMIZE_FLAG_SET_MASK(pJoin->node.optimizedFlag, OPTIMIZE_FLAG_CPD);
    pCxt->optimized = true;
X
Xiaoyu Wang 已提交
604
    code = cpdCheckJoinOnCond(pCxt, pJoin);
X
Xiaoyu Wang 已提交
605
  } else {
606 607 608 609 610 611 612 613
    nodesDestroyNode(pOnCond);
    nodesDestroyNode(pLeftChildCond);
    nodesDestroyNode(pRightChildCond);
  }

  return code;
}

614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
static int32_t cpdPushAggCondition(SOptimizeContext* pCxt, SAggLogicNode* pAgg) {
  // todo
  return TSDB_CODE_SUCCESS;
}

static int32_t cpdPushCondition(SOptimizeContext* pCxt, SLogicNode* pLogicNode) {
  int32_t code = TSDB_CODE_SUCCESS;
  switch (nodeType(pLogicNode)) {
    case QUERY_NODE_LOGIC_PLAN_SCAN:
      code = cpdOptimizeScanCondition(pCxt, (SScanLogicNode*)pLogicNode);
      break;
    case QUERY_NODE_LOGIC_PLAN_JOIN:
      code = cpdPushJoinCondition(pCxt, (SJoinLogicNode*)pLogicNode);
      break;
    case QUERY_NODE_LOGIC_PLAN_AGG:
      code = cpdPushAggCondition(pCxt, (SAggLogicNode*)pLogicNode);
      break;
    default:
      break;
  }
  if (TSDB_CODE_SUCCESS == code) {
    SNode* pChild = NULL;
    FOREACH(pChild, pLogicNode->pChildren) {
      code = cpdPushCondition(pCxt, (SLogicNode*)pChild);
      if (TSDB_CODE_SUCCESS != code) {
        break;
      }
    }
  }
  return code;
}

X
Xiaoyu Wang 已提交
646 647
static int32_t cpdOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
  return cpdPushCondition(pCxt, pLogicSubplan->pNode);
648 649
}

X
Xiaoyu Wang 已提交
650 651 652 653
static bool opkIsPrimaryKeyOrderBy(SNodeList* pSortKeys) {
  if (1 != LIST_LENGTH(pSortKeys)) {
    return false;
  }
X
Xiaoyu Wang 已提交
654
  SNode* pNode = ((SOrderByExprNode*)nodesListGetNode(pSortKeys, 0))->pExpr;
X
Xiaoyu Wang 已提交
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672
  return (QUERY_NODE_COLUMN == nodeType(pNode) ? (PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pNode)->colId) : false);
}

static bool opkSortMayBeOptimized(SLogicNode* pNode) {
  if (QUERY_NODE_LOGIC_PLAN_SORT != nodeType(pNode)) {
    return false;
  }
  if (OPTIMIZE_FLAG_TEST_MASK(pNode->optimizedFlag, OPTIMIZE_FLAG_OPK)) {
    return false;
  }
  return true;
}

static int32_t opkGetScanNodesImpl(SLogicNode* pNode, bool* pNotOptimize, SNodeList** pScanNodes) {
  int32_t code = TSDB_CODE_SUCCESS;

  switch (nodeType(pNode)) {
    case QUERY_NODE_LOGIC_PLAN_SCAN:
X
Xiaoyu Wang 已提交
673
      if (TSDB_SUPER_TABLE != ((SScanLogicNode*)pNode)->tableType) {
674
        return nodesListMakeAppend(pScanNodes, (SNode*)pNode);
675 676
      }
      break;
X
Xiaoyu Wang 已提交
677
    case QUERY_NODE_LOGIC_PLAN_JOIN:
678
      code = opkGetScanNodesImpl((SLogicNode*)nodesListGetNode(pNode->pChildren, 0), pNotOptimize, pScanNodes);
X
Xiaoyu Wang 已提交
679
      if (TSDB_CODE_SUCCESS == code) {
680
        code = opkGetScanNodesImpl((SLogicNode*)nodesListGetNode(pNode->pChildren, 1), pNotOptimize, pScanNodes);
X
Xiaoyu Wang 已提交
681 682 683 684 685 686 687 688 689 690 691
      }
      return code;
    case QUERY_NODE_LOGIC_PLAN_AGG:
      *pNotOptimize = true;
      return code;
    default:
      break;
  }

  if (1 != LIST_LENGTH(pNode->pChildren)) {
    *pNotOptimize = true;
692
    return TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
693 694
  }

695
  return opkGetScanNodesImpl((SLogicNode*)nodesListGetNode(pNode->pChildren, 0), pNotOptimize, pScanNodes);
X
Xiaoyu Wang 已提交
696 697 698
}

static int32_t opkGetScanNodes(SLogicNode* pNode, SNodeList** pScanNodes) {
X
Xiaoyu Wang 已提交
699
  bool    notOptimize = false;
X
Xiaoyu Wang 已提交
700 701 702 703 704 705 706 707 708 709 710 711 712 713
  int32_t code = opkGetScanNodesImpl(pNode, &notOptimize, pScanNodes);
  if (TSDB_CODE_SUCCESS != code || notOptimize) {
    nodesClearList(*pScanNodes);
  }
  return code;
}

static EOrder opkGetPrimaryKeyOrder(SSortLogicNode* pSort) {
  return ((SOrderByExprNode*)nodesListGetNode(pSort->pSortKeys, 0))->order;
}

static SNode* opkRewriteDownNode(SSortLogicNode* pSort) {
  SNode* pDownNode = nodesListGetNode(pSort->node.pChildren, 0);
  // todo
X
Xiaoyu Wang 已提交
714
  pSort->node.pChildren = NULL;
X
Xiaoyu Wang 已提交
715 716 717 718 719
  return pDownNode;
}

static int32_t opkDoOptimized(SOptimizeContext* pCxt, SSortLogicNode* pSort, SNodeList* pScanNodes) {
  EOrder order = opkGetPrimaryKeyOrder(pSort);
X
Xiaoyu Wang 已提交
720 721
  if (ORDER_DESC == order) {
    SNode* pScan = NULL;
X
Xiaoyu Wang 已提交
722
    FOREACH(pScan, pScanNodes) { TSWAP(((SScanLogicNode*)pScan)->scanSeq[0], ((SScanLogicNode*)pScan)->scanSeq[1]); }
X
Xiaoyu Wang 已提交
723
  }
X
Xiaoyu Wang 已提交
724

X
Xiaoyu Wang 已提交
725 726 727 728 729 730 731 732
  if (NULL == pSort->node.pParent) {
    // todo
    return TSDB_CODE_SUCCESS;
  }

  SNode* pDownNode = opkRewriteDownNode(pSort);
  SNode* pNode;
  FOREACH(pNode, pSort->node.pParent->pChildren) {
733
    if (nodesEqualNode(pNode, (SNode*)pSort)) {
X
Xiaoyu Wang 已提交
734
      REPLACE_NODE(pDownNode);
D
dapan1121 已提交
735
      ((SLogicNode*)pDownNode)->pParent = pSort->node.pParent;
X
Xiaoyu Wang 已提交
736 737 738
      break;
    }
  }
739
  nodesDestroyNode((SNode*)pSort);
X
Xiaoyu Wang 已提交
740 741 742 743 744 745 746 747 748
  return TSDB_CODE_SUCCESS;
}

static int32_t opkOptimizeImpl(SOptimizeContext* pCxt, SSortLogicNode* pSort) {
  OPTIMIZE_FLAG_SET_MASK(pSort->node.optimizedFlag, OPTIMIZE_FLAG_OPK);
  if (!opkIsPrimaryKeyOrderBy(pSort->pSortKeys) || 1 != LIST_LENGTH(pSort->node.pChildren)) {
    return TSDB_CODE_SUCCESS;
  }
  SNodeList* pScanNodes = NULL;
749
  int32_t    code = opkGetScanNodes((SLogicNode*)nodesListGetNode(pSort->node.pChildren, 0), &pScanNodes);
X
Xiaoyu Wang 已提交
750 751 752 753 754 755 756
  if (TSDB_CODE_SUCCESS == code && NULL != pScanNodes) {
    code = opkDoOptimized(pCxt, pSort, pScanNodes);
  }
  nodesClearList(pScanNodes);
  return code;
}

X
Xiaoyu Wang 已提交
757 758
static int32_t opkOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
  SSortLogicNode* pSort = (SSortLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, opkSortMayBeOptimized);
X
Xiaoyu Wang 已提交
759 760 761 762 763 764
  if (NULL == pSort) {
    return TSDB_CODE_SUCCESS;
  }
  return opkOptimizeImpl(pCxt, pSort);
}

X
Xiaoyu Wang 已提交
765
static bool smaOptMayBeOptimized(SLogicNode* pNode) {
X
Xiaoyu Wang 已提交
766 767 768
  if (QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(pNode) || NULL == pNode->pParent ||
      QUERY_NODE_LOGIC_PLAN_WINDOW != nodeType(pNode->pParent) ||
      WINDOW_TYPE_INTERVAL != ((SWindowLogicNode*)pNode->pParent)->winType) {
X
Xiaoyu Wang 已提交
769 770 771 772 773 774 775 776
    return false;
  }

  SScanLogicNode* pScan = (SScanLogicNode*)pNode;
  if (0 == pScan->interval || NULL == pScan->pSmaIndexes || NULL != pScan->node.pConditions) {
    return false;
  }

X
Xiaoyu Wang 已提交
777
  return true;
X
Xiaoyu Wang 已提交
778 779
}

X
Xiaoyu Wang 已提交
780
static int32_t smaOptCreateMerge(SLogicNode* pChild, SNodeList* pMergeKeys, SNodeList* pTargets, SLogicNode** pOutput) {
781
  SMergeLogicNode* pMerge = (SMergeLogicNode*)nodesMakeNode(QUERY_NODE_LOGIC_PLAN_MERGE);
X
Xiaoyu Wang 已提交
782 783 784
  if (NULL == pMerge) {
    return TSDB_CODE_OUT_OF_MEMORY;
  }
X
Xiaoyu Wang 已提交
785
  pMerge->node.precision = pChild->precision;
X
Xiaoyu Wang 已提交
786
  pMerge->numOfChannels = 2;
X
Xiaoyu Wang 已提交
787
  pMerge->pMergeKeys = pMergeKeys;
X
Xiaoyu Wang 已提交
788
  pMerge->node.pTargets = pTargets;
X
Xiaoyu Wang 已提交
789
  pMerge->pInputs = nodesCloneList(pChild->pTargets);
X
Xiaoyu Wang 已提交
790
  if (NULL == pMerge->pInputs) {
791
    nodesDestroyNode((SNode*)pMerge);
X
Xiaoyu Wang 已提交
792
    return TSDB_CODE_OUT_OF_MEMORY;
X
Xiaoyu Wang 已提交
793
  }
X
Xiaoyu Wang 已提交
794 795 796 797 798 799 800

  *pOutput = (SLogicNode*)pMerge;
  return TSDB_CODE_SUCCESS;
}

static int32_t smaOptRecombinationNode(SLogicSubplan* pLogicSubplan, SLogicNode* pInterval, SLogicNode* pMerge,
                                       SLogicNode* pSmaScan) {
801
  int32_t code = nodesListMakeAppend(&pMerge->pChildren, (SNode*)pInterval);
X
Xiaoyu Wang 已提交
802
  if (TSDB_CODE_SUCCESS == code) {
803
    code = nodesListMakeAppend(&pMerge->pChildren, (SNode*)pSmaScan);
X
Xiaoyu Wang 已提交
804
  }
X
Xiaoyu Wang 已提交
805 806 807 808
  if (TSDB_CODE_SUCCESS == code) {
    code = replaceLogicNode(pLogicSubplan, pInterval, pMerge);
    pSmaScan->pParent = pMerge;
    pInterval->pParent = pMerge;
X
Xiaoyu Wang 已提交
809 810 811 812 813
  }
  return code;
}

static int32_t smaOptCreateSmaScan(SScanLogicNode* pScan, STableIndexInfo* pIndex, SNodeList* pCols,
X
Xiaoyu Wang 已提交
814
                                   SLogicNode** pOutput) {
815
  SScanLogicNode* pSmaScan = (SScanLogicNode*)nodesMakeNode(QUERY_NODE_LOGIC_PLAN_SCAN);
X
Xiaoyu Wang 已提交
816 817 818 819 820 821 822 823 824 825 826 827 828 829
  if (NULL == pSmaScan) {
    return TSDB_CODE_OUT_OF_MEMORY;
  }
  pSmaScan->pScanCols = pCols;
  pSmaScan->tableType = TSDB_SUPER_TABLE;
  pSmaScan->tableId = pIndex->dstTbUid;
  pSmaScan->stableId = pIndex->dstTbUid;
  pSmaScan->scanType = SCAN_TYPE_TABLE;
  pSmaScan->scanSeq[0] = pScan->scanSeq[0];
  pSmaScan->scanSeq[1] = pScan->scanSeq[1];
  pSmaScan->scanRange = pScan->scanRange;
  pSmaScan->dataRequired = FUNC_DATA_REQUIRED_DATA_LOAD;

  pSmaScan->pVgroupList = taosMemoryCalloc(1, sizeof(SVgroupsInfo) + sizeof(SVgroupInfo));
X
Xiaoyu Wang 已提交
830 831
  pSmaScan->node.pTargets = nodesCloneList(pCols);
  if (NULL == pSmaScan->pVgroupList || NULL == pSmaScan->node.pTargets) {
832
    nodesDestroyNode((SNode*)pSmaScan);
X
Xiaoyu Wang 已提交
833 834 835 836 837 838
    return TSDB_CODE_OUT_OF_MEMORY;
  }
  pSmaScan->pVgroupList->numOfVgroups = 1;
  pSmaScan->pVgroupList->vgroups[0].vgId = pIndex->dstVgId;
  memcpy(&(pSmaScan->pVgroupList->vgroups[0].epSet), &pIndex->epSet, sizeof(SEpSet));

X
Xiaoyu Wang 已提交
839
  *pOutput = (SLogicNode*)pSmaScan;
X
Xiaoyu Wang 已提交
840 841 842
  return TSDB_CODE_SUCCESS;
}

X
Xiaoyu Wang 已提交
843
static bool smaOptEqualInterval(SScanLogicNode* pScan, SWindowLogicNode* pWindow, STableIndexInfo* pIndex) {
X
Xiaoyu Wang 已提交
844 845 846 847 848
  if (pWindow->interval != pIndex->interval || pWindow->intervalUnit != pIndex->intervalUnit ||
      pWindow->offset != pIndex->offset || pWindow->sliding != pIndex->sliding ||
      pWindow->slidingUnit != pIndex->slidingUnit) {
    return false;
  }
X
Xiaoyu Wang 已提交
849 850 851 852 853 854 855 856 857 858 859
  if (IS_TSWINDOW_SPECIFIED(pScan->scanRange)) {
    SInterval interval = {.interval = pIndex->interval,
                          .intervalUnit = pIndex->intervalUnit,
                          .offset = pIndex->offset,
                          .offsetUnit = TIME_UNIT_MILLISECOND,
                          .sliding = pIndex->sliding,
                          .slidingUnit = pIndex->slidingUnit,
                          .precision = pScan->node.precision};
    return (pScan->scanRange.skey == taosTimeTruncate(pScan->scanRange.skey, &interval, pScan->node.precision)) &&
           (pScan->scanRange.ekey + 1 == taosTimeTruncate(pScan->scanRange.ekey + 1, &interval, pScan->node.precision));
  }
X
Xiaoyu Wang 已提交
860 861 862 863
  return true;
}

static SNode* smaOptCreateSmaCol(SNode* pFunc, uint64_t tableId, int32_t colId) {
864
  SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN);
X
Xiaoyu Wang 已提交
865 866 867 868 869 870 871
  if (NULL == pCol) {
    return NULL;
  }
  pCol->tableId = tableId;
  pCol->tableType = TSDB_SUPER_TABLE;
  pCol->colId = colId;
  pCol->colType = COLUMN_TYPE_COLUMN;
X
Xiaoyu Wang 已提交
872
  strcpy(pCol->colName, ((SExprNode*)pFunc)->aliasName);
X
Xiaoyu Wang 已提交
873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895
  pCol->node.resType = ((SExprNode*)pFunc)->resType;
  strcpy(pCol->node.aliasName, ((SExprNode*)pFunc)->aliasName);
  return (SNode*)pCol;
}

static int32_t smaOptFindSmaFunc(SNode* pQueryFunc, SNodeList* pSmaFuncs) {
  int32_t index = 0;
  SNode*  pSmaFunc = NULL;
  FOREACH(pSmaFunc, pSmaFuncs) {
    if (nodesEqualNode(pQueryFunc, pSmaFunc)) {
      return index;
    }
    ++index;
  }
  return -1;
}

static int32_t smaOptCreateSmaCols(SNodeList* pFuncs, uint64_t tableId, SNodeList* pSmaFuncs, SNodeList** pOutput,
                                   int32_t* pWStrartIndex) {
  SNodeList* pCols = NULL;
  SNode*     pFunc = NULL;
  int32_t    code = TSDB_CODE_SUCCESS;
  int32_t    index = 0;
X
Xiaoyu Wang 已提交
896
  int32_t    smaFuncIndex = -1;
X
Xiaoyu Wang 已提交
897
  *pWStrartIndex = -1;
X
Xiaoyu Wang 已提交
898 899 900 901
  FOREACH(pFunc, pFuncs) {
    if (FUNCTION_TYPE_WSTARTTS == ((SFunctionNode*)pFunc)->funcType) {
      *pWStrartIndex = index;
    }
X
Xiaoyu Wang 已提交
902
    smaFuncIndex = smaOptFindSmaFunc(pFunc, pSmaFuncs);
X
Xiaoyu Wang 已提交
903 904 905 906 907 908 909 910 911 912 913
    if (smaFuncIndex < 0) {
      break;
    } else {
      code = nodesListMakeStrictAppend(&pCols, smaOptCreateSmaCol(pFunc, tableId, smaFuncIndex + 2));
      if (TSDB_CODE_SUCCESS != code) {
        break;
      }
    }
    ++index;
  }

X
Xiaoyu Wang 已提交
914
  if (TSDB_CODE_SUCCESS == code && smaFuncIndex >= 0) {
X
Xiaoyu Wang 已提交
915 916 917 918 919 920 921 922
    *pOutput = pCols;
  } else {
    nodesDestroyList(pCols);
  }

  return code;
}

X
Xiaoyu Wang 已提交
923
static int32_t smaOptCouldApplyIndex(SScanLogicNode* pScan, STableIndexInfo* pIndex, SNodeList** pCols,
X
Xiaoyu Wang 已提交
924
                                     int32_t* pWStrartIndex) {
X
Xiaoyu Wang 已提交
925 926
  SWindowLogicNode* pWindow = (SWindowLogicNode*)pScan->node.pParent;
  if (!smaOptEqualInterval(pScan, pWindow, pIndex)) {
X
Xiaoyu Wang 已提交
927 928 929 930 931 932 933 934 935 936 937
    return TSDB_CODE_SUCCESS;
  }
  SNodeList* pSmaFuncs = NULL;
  int32_t    code = nodesStringToList(pIndex->expr, &pSmaFuncs);
  if (TSDB_CODE_SUCCESS == code) {
    code = smaOptCreateSmaCols(pWindow->pFuncs, pIndex->dstTbUid, pSmaFuncs, pCols, pWStrartIndex);
  }
  nodesDestroyList(pSmaFuncs);
  return code;
}

X
Xiaoyu Wang 已提交
938
static SNode* smaOptCreateWStartTs() {
939
  SFunctionNode* pWStart = (SFunctionNode*)nodesMakeNode(QUERY_NODE_FUNCTION);
X
Xiaoyu Wang 已提交
940 941 942 943 944 945
  if (NULL == pWStart) {
    return NULL;
  }
  strcpy(pWStart->functionName, "_wstartts");
  snprintf(pWStart->node.aliasName, sizeof(pWStart->node.aliasName), "%s.%p", pWStart->functionName, pWStart);
  if (TSDB_CODE_SUCCESS != fmGetFuncInfo(pWStart, NULL, 0)) {
946
    nodesDestroyNode((SNode*)pWStart);
X
Xiaoyu Wang 已提交
947 948 949 950 951 952
    return NULL;
  }
  return (SNode*)pWStart;
}

static int32_t smaOptCreateMergeKey(SNode* pCol, SNodeList** pMergeKeys) {
953
  SOrderByExprNode* pMergeKey = (SOrderByExprNode*)nodesMakeNode(QUERY_NODE_ORDER_BY_EXPR);
X
Xiaoyu Wang 已提交
954 955 956 957 958
  if (NULL == pMergeKey) {
    return TSDB_CODE_OUT_OF_MEMORY;
  }
  pMergeKey->pExpr = nodesCloneNode(pCol);
  if (NULL == pMergeKey->pExpr) {
959
    nodesDestroyNode((SNode*)pMergeKey);
X
Xiaoyu Wang 已提交
960 961 962 963
    return TSDB_CODE_OUT_OF_MEMORY;
  }
  pMergeKey->order = ORDER_ASC;
  pMergeKey->nullOrder = NULL_ORDER_FIRST;
964
  return nodesListMakeStrictAppend(pMergeKeys, (SNode*)pMergeKey);
X
Xiaoyu Wang 已提交
965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982
}

static int32_t smaOptRewriteInterval(SWindowLogicNode* pInterval, int32_t wstrartIndex, SNodeList** pMergeKeys) {
  if (wstrartIndex < 0) {
    SNode* pWStart = smaOptCreateWStartTs();
    if (NULL == pWStart) {
      return TSDB_CODE_OUT_OF_MEMORY;
    }
    int32_t code = createColumnByRewriteExpr(pWStart, &pInterval->node.pTargets);
    if (TSDB_CODE_SUCCESS != code) {
      nodesDestroyNode(pWStart);
      return code;
    }
    wstrartIndex = LIST_LENGTH(pInterval->node.pTargets) - 1;
  }
  return smaOptCreateMergeKey(nodesListGetNode(pInterval->node.pTargets, wstrartIndex), pMergeKeys);
}

X
Xiaoyu Wang 已提交
983 984
static int32_t smaOptApplyIndexExt(SLogicSubplan* pLogicSubplan, SScanLogicNode* pScan, STableIndexInfo* pIndex,
                                   SNodeList* pSmaCols, int32_t wstrartIndex) {
X
Xiaoyu Wang 已提交
985 986 987 988 989
  SWindowLogicNode* pInterval = (SWindowLogicNode*)pScan->node.pParent;
  SNodeList*        pMergeTargets = nodesCloneList(pInterval->node.pTargets);
  if (NULL == pMergeTargets) {
    return TSDB_CODE_OUT_OF_MEMORY;
  }
X
Xiaoyu Wang 已提交
990 991
  SLogicNode* pSmaScan = NULL;
  SLogicNode* pMerge = NULL;
X
Xiaoyu Wang 已提交
992 993
  SNodeList*  pMergeKeys = NULL;
  int32_t     code = smaOptRewriteInterval(pInterval, wstrartIndex, &pMergeKeys);
X
Xiaoyu Wang 已提交
994
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
995 996 997 998
    code = smaOptCreateSmaScan(pScan, pIndex, pSmaCols, &pSmaScan);
  }
  if (TSDB_CODE_SUCCESS == code) {
    code = smaOptCreateMerge(pScan->node.pParent, pMergeKeys, pMergeTargets, &pMerge);
X
Xiaoyu Wang 已提交
999 1000 1001 1002 1003 1004 1005
  }
  if (TSDB_CODE_SUCCESS == code) {
    code = smaOptRecombinationNode(pLogicSubplan, pScan->node.pParent, pMerge, pSmaScan);
  }
  return code;
}

X
Xiaoyu Wang 已提交
1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
static int32_t smaOptApplyIndex(SLogicSubplan* pLogicSubplan, SScanLogicNode* pScan, STableIndexInfo* pIndex,
                                SNodeList* pSmaCols, int32_t wstrartIndex) {
  SLogicNode* pSmaScan = NULL;
  int32_t     code = smaOptCreateSmaScan(pScan, pIndex, pSmaCols, &pSmaScan);
  if (TSDB_CODE_SUCCESS == code) {
    code = replaceLogicNode(pLogicSubplan, pScan->node.pParent, pSmaScan);
  }
  return code;
}

X
Xiaoyu Wang 已提交
1016 1017
static void smaOptDestroySmaIndex(void* p) { taosMemoryFree(((STableIndexInfo*)p)->expr); }

X
Xiaoyu Wang 已提交
1018
static int32_t smaOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan, SScanLogicNode* pScan) {
X
Xiaoyu Wang 已提交
1019
  int32_t code = TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
1020 1021 1022 1023 1024
  int32_t nindexes = taosArrayGetSize(pScan->pSmaIndexes);
  for (int32_t i = 0; i < nindexes; ++i) {
    STableIndexInfo* pIndex = taosArrayGet(pScan->pSmaIndexes, i);
    SNodeList*       pSmaCols = NULL;
    int32_t          wstrartIndex = -1;
X
Xiaoyu Wang 已提交
1025
    code = smaOptCouldApplyIndex(pScan, pIndex, &pSmaCols, &wstrartIndex);
X
Xiaoyu Wang 已提交
1026
    if (TSDB_CODE_SUCCESS == code && NULL != pSmaCols) {
X
Xiaoyu Wang 已提交
1027 1028 1029 1030
      code = smaOptApplyIndex(pLogicSubplan, pScan, pIndex, pSmaCols, wstrartIndex);
      taosArrayDestroyEx(pScan->pSmaIndexes, smaOptDestroySmaIndex);
      pScan->pSmaIndexes = NULL;
      break;
X
Xiaoyu Wang 已提交
1031 1032
    }
  }
X
Xiaoyu Wang 已提交
1033
  return code;
X
Xiaoyu Wang 已提交
1034
}
X
Xiaoyu Wang 已提交
1035

X
Xiaoyu Wang 已提交
1036 1037
static int32_t smaOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
  SScanLogicNode* pScan = (SScanLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, smaOptMayBeOptimized);
X
Xiaoyu Wang 已提交
1038 1039 1040
  if (NULL == pScan) {
    return TSDB_CODE_SUCCESS;
  }
X
Xiaoyu Wang 已提交
1041
  return smaOptimizeImpl(pCxt, pLogicSubplan, pScan);
X
Xiaoyu Wang 已提交
1042 1043
}

X
Xiaoyu Wang 已提交
1044 1045
static EDealRes partTagsOptHasColImpl(SNode* pNode, void* pContext) {
  if (QUERY_NODE_COLUMN == nodeType(pNode)) {
X
Xiaoyu Wang 已提交
1046
    if (COLUMN_TYPE_TAG != ((SColumnNode*)pNode)->colType && COLUMN_TYPE_TBNAME != ((SColumnNode*)pNode)->colType) {
X
Xiaoyu Wang 已提交
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059
      *(bool*)pContext = true;
      return DEAL_RES_END;
    }
  }
  return DEAL_RES_CONTINUE;
}

static bool partTagsOptHasCol(SNodeList* pPartKeys) {
  bool hasCol = false;
  nodesWalkExprs(pPartKeys, partTagsOptHasColImpl, &hasCol);
  return hasCol;
}

X
Xiaoyu Wang 已提交
1060
static bool partTagsIsOptimizableNode(SLogicNode* pNode) {
X
Xiaoyu Wang 已提交
1061
  return ((QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pNode) ||
X
Xiaoyu Wang 已提交
1062
           (QUERY_NODE_LOGIC_PLAN_AGG == nodeType(pNode) && NULL != ((SAggLogicNode*)pNode)->pGroupKeys &&
X
Xiaoyu Wang 已提交
1063
            NULL != ((SAggLogicNode*)pNode)->pAggFuncs)) &&
X
Xiaoyu Wang 已提交
1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075
          1 == LIST_LENGTH(pNode->pChildren) &&
          QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(nodesListGetNode(pNode->pChildren, 0)));
}

static SNodeList* partTagsGetPartKeys(SLogicNode* pNode) {
  if (QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pNode)) {
    return ((SPartitionLogicNode*)pNode)->pPartitionKeys;
  } else {
    return ((SAggLogicNode*)pNode)->pGroupKeys;
  }
}

X
Xiaoyu Wang 已提交
1076
static bool partTagsOptMayBeOptimized(SLogicNode* pNode) {
X
Xiaoyu Wang 已提交
1077
  if (!partTagsIsOptimizableNode(pNode)) {
X
Xiaoyu Wang 已提交
1078 1079 1080
    return false;
  }

X
Xiaoyu Wang 已提交
1081
  return !partTagsOptHasCol(partTagsGetPartKeys(pNode));
X
Xiaoyu Wang 已提交
1082 1083
}

X
Xiaoyu Wang 已提交
1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
static EDealRes partTagsOptRebuildTbanmeImpl(SNode** pNode, void* pContext) {
  if (QUERY_NODE_COLUMN == nodeType(*pNode) && COLUMN_TYPE_TBNAME == ((SColumnNode*)*pNode)->colType) {
    SFunctionNode* pFunc = (SFunctionNode*)nodesMakeNode(QUERY_NODE_FUNCTION);
    if (NULL == pFunc) {
      *(int32_t*)pContext = TSDB_CODE_OUT_OF_MEMORY;
      return DEAL_RES_ERROR;
    }
    strcpy(pFunc->functionName, "tbname");
    pFunc->funcType = FUNCTION_TYPE_TBNAME;
    nodesDestroyNode(*pNode);
    *pNode = (SNode*)pFunc;
    return DEAL_RES_IGNORE_CHILD;
  }
  return DEAL_RES_CONTINUE;
}

static int32_t partTagsOptRebuildTbanme(SNodeList* pPartKeys) {
  int32_t code = TSDB_CODE_SUCCESS;
  nodesRewriteExprs(pPartKeys, partTagsOptRebuildTbanmeImpl, &code);
  return code;
}

X
Xiaoyu Wang 已提交
1106
static int32_t partTagsOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
X
Xiaoyu Wang 已提交
1107 1108
  SLogicNode* pNode = optFindPossibleNode(pLogicSubplan->pNode, partTagsOptMayBeOptimized);
  if (NULL == pNode) {
X
Xiaoyu Wang 已提交
1109 1110 1111
    return TSDB_CODE_SUCCESS;
  }

X
Xiaoyu Wang 已提交
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
  int32_t         code = TSDB_CODE_SUCCESS;
  SScanLogicNode* pScan = (SScanLogicNode*)nodesListGetNode(pNode->pChildren, 0);
  if (QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pNode)) {
    TSWAP(((SPartitionLogicNode*)pNode)->pPartitionKeys, pScan->pPartTags);
    int32_t code = replaceLogicNode(pLogicSubplan, pNode, (SLogicNode*)pScan);
    if (TSDB_CODE_SUCCESS == code) {
      NODES_CLEAR_LIST(pNode->pChildren);
      nodesDestroyNode((SNode*)pNode);
    }
  } else {
X
Xiaoyu Wang 已提交
1122 1123 1124 1125 1126 1127 1128 1129
    SNode* pGroupKey = NULL;
    FOREACH(pGroupKey, ((SAggLogicNode*)pNode)->pGroupKeys) {
      code = nodesListMakeStrictAppend(
          &pScan->pPartTags, nodesCloneNode(nodesListGetNode(((SGroupingSetNode*)pGroupKey)->pParameterList, 0)));
      if (TSDB_CODE_SUCCESS != code) {
        break;
      }
    }
X
Xiaoyu Wang 已提交
1130
    NODES_DESTORY_LIST(((SAggLogicNode*)pNode)->pGroupKeys);
X
Xiaoyu Wang 已提交
1131 1132 1133
  }
  if (TSDB_CODE_SUCCESS == code) {
    code = partTagsOptRebuildTbanme(pScan->pPartTags);
X
Xiaoyu Wang 已提交
1134 1135 1136 1137
  }
  return code;
}

1138
static bool eliminateProjOptMayBeOptimized(SLogicNode* pNode) {
X
Xiaoyu Wang 已提交
1139
  // TODO: enable this optimization after new mechanising that map projection and targets of project node
1140 1141 1142
  if (NULL != pNode->pParent) {
    return false;
  }
X
Xiaoyu Wang 已提交
1143

1144 1145 1146 1147 1148
  if (QUERY_NODE_LOGIC_PLAN_PROJECT != nodeType(pNode) || 1 != LIST_LENGTH(pNode->pChildren)) {
    return false;
  }

  SProjectLogicNode* pProjectNode = (SProjectLogicNode*)pNode;
X
Xiaoyu Wang 已提交
1149 1150
  if (-1 != pProjectNode->limit || -1 != pProjectNode->slimit || -1 != pProjectNode->offset ||
      -1 != pProjectNode->soffset) {
1151 1152 1153
    return false;
  }

1154
  SHashObj* pProjColNameHash = taosHashInit(16, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
X
Xiaoyu Wang 已提交
1155
  SNode*    pProjection;
1156 1157 1158
  FOREACH(pProjection, pProjectNode->pProjections) {
    SExprNode* pExprNode = (SExprNode*)pProjection;
    if (QUERY_NODE_COLUMN != nodeType(pExprNode)) {
1159
      taosHashCleanup(pProjColNameHash);
1160 1161
      return false;
    }
1162

X
Xiaoyu Wang 已提交
1163
    char*    projColumnName = ((SColumnNode*)pProjection)->colName;
1164 1165 1166 1167 1168 1169 1170 1171
    int32_t* pExist = taosHashGet(pProjColNameHash, projColumnName, strlen(projColumnName));
    if (NULL != pExist) {
      taosHashCleanup(pProjColNameHash);
      return false;
    } else {
      int32_t exist = 1;
      taosHashPut(pProjColNameHash, projColumnName, strlen(projColumnName), &exist, sizeof(exist));
    }
1172
  }
1173
  taosHashCleanup(pProjColNameHash);
1174

1175 1176 1177
  return true;
}

X
Xiaoyu Wang 已提交
1178 1179
static int32_t eliminateProjOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan,
                                         SProjectLogicNode* pProjectNode) {
1180
  SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pProjectNode->node.pChildren, 0);
X
Xiaoyu Wang 已提交
1181
  SNodeList*  pNewChildTargets = nodesMakeList();
1182 1183 1184 1185 1186

  SNode* pProjection = NULL;
  FOREACH(pProjection, pProjectNode->pProjections) {
    SNode* pChildTarget = NULL;
    FOREACH(pChildTarget, pChild->pTargets) {
1187
      if (strcmp(((SColumnNode*)pProjection)->colName, ((SColumnNode*)pChildTarget)->colName) == 0) {
1188
        nodesListAppend(pNewChildTargets, nodesCloneNode(pChildTarget));
1189
        break;
1190 1191 1192
      }
    }
  }
1193 1194
  nodesDestroyList(pChild->pTargets);
  pChild->pTargets = pNewChildTargets;
X
Xiaoyu Wang 已提交
1195

1196 1197 1198 1199 1200 1201 1202 1203 1204 1205
  int32_t code = replaceLogicNode(pLogicSubplan, (SLogicNode*)pProjectNode, pChild);
  if (TSDB_CODE_SUCCESS == code) {
    NODES_CLEAR_LIST(pProjectNode->node.pChildren);
    nodesDestroyNode((SNode*)pProjectNode);
  }
  return code;
}

static int32_t eliminateProjOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
  SProjectLogicNode* pProjectNode =
X
Xiaoyu Wang 已提交
1206
      (SProjectLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, eliminateProjOptMayBeOptimized);
1207 1208 1209 1210 1211 1212 1213 1214

  if (NULL == pProjectNode) {
    return TSDB_CODE_SUCCESS;
  }

  return eliminateProjOptimizeImpl(pCxt, pLogicSubplan, pProjectNode);
}

X
Xiaoyu Wang 已提交
1215 1216
// clang-format off
static const SOptimizeRule optimizeRuleSet[] = {
X
Xiaoyu Wang 已提交
1217
  {.pName = "OptimizeScanData",  .optimizeFunc = osdOptimize},
X
Xiaoyu Wang 已提交
1218 1219
  {.pName = "ConditionPushDown", .optimizeFunc = cpdOptimize},
  {.pName = "OrderByPrimaryKey", .optimizeFunc = opkOptimize},
X
Xiaoyu Wang 已提交
1220
  {.pName = "SmaIndex",          .optimizeFunc = smaOptimize},
X
Xiaoyu Wang 已提交
1221
  // {.pName = "PartitionTags",     .optimizeFunc = partTagsOptimize},
1222
  {.pName = "EliminateProject",  .optimizeFunc = eliminateProjOptimize}
X
Xiaoyu Wang 已提交
1223 1224
};
// clang-format on
1225 1226 1227

static const int32_t optimizeRuleNum = (sizeof(optimizeRuleSet) / sizeof(SOptimizeRule));

X
Xiaoyu Wang 已提交
1228
static int32_t applyOptimizeRule(SPlanContext* pCxt, SLogicSubplan* pLogicSubplan) {
X
Xiaoyu Wang 已提交
1229
  SOptimizeContext cxt = {.pPlanCxt = pCxt, .optimized = false};
1230 1231 1232
  do {
    cxt.optimized = false;
    for (int32_t i = 0; i < optimizeRuleNum; ++i) {
X
Xiaoyu Wang 已提交
1233
      int32_t code = optimizeRuleSet[i].optimizeFunc(&cxt, pLogicSubplan);
1234 1235 1236 1237 1238
      if (TSDB_CODE_SUCCESS != code) {
        return code;
      }
    }
  } while (cxt.optimized);
X
Xiaoyu Wang 已提交
1239 1240
  return TSDB_CODE_SUCCESS;
}
1241

X
Xiaoyu Wang 已提交
1242
int32_t optimizeLogicPlan(SPlanContext* pCxt, SLogicSubplan* pLogicSubplan) {
X
Xiaoyu Wang 已提交
1243
  return applyOptimizeRule(pCxt, pLogicSubplan);
X
Xiaoyu Wang 已提交
1244
}