planOptimizer.c 61.4 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 18
#include "functionMgt.h"
#include "planInt.h"
X
Xiaoyu Wang 已提交
19
#include "ttime.h"
X
Xiaoyu Wang 已提交
20

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

23
#define OPTIMIZE_FLAG_SCAN_PATH       OPTIMIZE_FLAG_MASK(0)
24
#define OPTIMIZE_FLAG_PUSH_DOWN_CONDE OPTIMIZE_FLAG_MASK(1)
25

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

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

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

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

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

47 48 49
typedef struct SCpdIsMultiTableCondCxt {
  SNodeList* pLeftCols;
  SNodeList* pRightCols;
X
Xiaoyu Wang 已提交
50 51
  bool       havaLeftCol;
  bool       haveRightCol;
52 53 54 55 56 57 58 59 60 61
} 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 已提交
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
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;
}

78
EDealRes scanPathOptHaveNormalColImpl(SNode* pNode, void* pContext) {
79
  if (QUERY_NODE_COLUMN == nodeType(pNode)) {
X
Xiaoyu Wang 已提交
80 81
    // *((bool*)pContext) = (COLUMN_TYPE_TAG != ((SColumnNode*)pNode)->colType);
    *((bool*)pContext) = true;
82 83 84 85 86
    return *((bool*)pContext) ? DEAL_RES_END : DEAL_RES_IGNORE_CHILD;
  }
  return DEAL_RES_CONTINUE;
}

87
static bool scanPathOptHaveNormalCol(SNodeList* pList) {
88
  bool res = false;
89
  nodesWalkExprsPostOrder(pList, scanPathOptHaveNormalColImpl, &res);
90 91 92
  return res;
}

93
static bool scanPathOptMayBeOptimized(SLogicNode* pNode) {
94
  if (OPTIMIZE_FLAG_TEST_MASK(pNode->optimizedFlag, OPTIMIZE_FLAG_SCAN_PATH)) {
95 96 97 98 99
    return false;
  }
  if (QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(pNode)) {
    return false;
  }
X
Xiaoyu Wang 已提交
100
  if (NULL == pNode->pParent || (QUERY_NODE_LOGIC_PLAN_WINDOW != nodeType(pNode->pParent) &&
101 102
                                 QUERY_NODE_LOGIC_PLAN_AGG != nodeType(pNode->pParent) &&
                                 QUERY_NODE_LOGIC_PLAN_PARTITION != nodeType(pNode->pParent))) {
103 104
    return false;
  }
105
  if (QUERY_NODE_LOGIC_PLAN_WINDOW == nodeType(pNode->pParent) ||
X
Xiaoyu Wang 已提交
106 107
      (QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pNode->pParent) && pNode->pParent->pParent &&
       QUERY_NODE_LOGIC_PLAN_WINDOW == nodeType(pNode->pParent->pParent))) {
5
54liuyao 已提交
108
    return true;
109
  }
110
  return !scanPathOptHaveNormalCol(((SAggLogicNode*)pNode->pParent)->pGroupKeys);
111 112
}

113
static SNodeList* scanPathOptGetAllFuncs(SLogicNode* pNode) {
114 115 116 117 118 119 120 121 122 123 124
  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;
}

125
static bool scanPathOptNeedOptimizeDataRequire(const SFunctionNode* pFunc) {
126 127 128 129 130 131 132 133 134 135 136 137
  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;
}

138
static bool scanPathOptNeedDynOptimize(const SFunctionNode* pFunc) {
139 140 141 142 143 144 145 146 147 148 149 150
  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;
}

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

182 183
static int32_t scanPathOptMatch(SOptimizeContext* pCxt, SLogicNode* pLogicNode, SOsdInfo* pInfo) {
  pInfo->pScan = (SScanLogicNode*)optFindPossibleNode(pLogicNode, scanPathOptMayBeOptimized);
184 185 186
  if (NULL == pInfo->pScan) {
    return TSDB_CODE_SUCCESS;
  }
187
  return scanPathOptGetRelatedFuncs(pInfo->pScan, &pInfo->pSdrFuncs, &pInfo->pDsoFuncs);
188 189
}

190
static EFuncDataRequired scanPathOptPromoteDataRequired(EFuncDataRequired l, EFuncDataRequired r) {
191
  switch (l) {
192
    case FUNC_DATA_REQUIRED_DATA_LOAD:
193
      return l;
194 195 196 197
    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;
198 199 200 201 202 203
    default:
      break;
  }
  return r;
}

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

216
static void scanPathOptSetScanWin(SScanLogicNode* pScan) {
217
  SLogicNode* pParent = pScan->node.pParent;
X
Xiaoyu Wang 已提交
218 219
  if (QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pParent) && pParent->pParent &&
      QUERY_NODE_LOGIC_PLAN_WINDOW == nodeType(pParent->pParent)) {
220 221 222 223 224 225 226 227 228 229 230 231
    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 已提交
232 233 234
  }
}

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

251
static int32_t pushDownCondOptMergeCond(SNode** pDst, SNode** pSrc) {
252
  SLogicConditionNode* pLogicCond = (SLogicConditionNode*)nodesMakeNode(QUERY_NODE_LOGIC_CONDITION);
253 254 255
  if (NULL == pLogicCond) {
    return TSDB_CODE_OUT_OF_MEMORY;
  }
D
dapan1121 已提交
256 257
  pLogicCond->node.resType.type = TSDB_DATA_TYPE_BOOL;
  pLogicCond->node.resType.bytes = tDataTypes[TSDB_DATA_TYPE_BOOL].bytes;
258 259 260 261 262 263 264 265 266
  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 {
267
    nodesDestroyNode((SNode*)pLogicCond);
268 269 270 271
  }
  return code;
}

272
static int32_t pushDownCondOptAppendCond(SNode** pCond, SNode** pAdditionalCond) {
273
  if (NULL == *pCond) {
wafwerar's avatar
wafwerar 已提交
274
    TSWAP(*pCond, *pAdditionalCond);
275 276 277 278 279 280 281 282 283 284
    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 {
285
    code = pushDownCondOptMergeCond(pCond, pAdditionalCond);
286 287 288 289
  }
  return code;
}

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

310 311 312
static int32_t pushDownCondOptDealScan(SOptimizeContext* pCxt, SScanLogicNode* pScan) {
  if (NULL == pScan->node.pConditions ||
      OPTIMIZE_FLAG_TEST_MASK(pScan->node.optimizedFlag, OPTIMIZE_FLAG_PUSH_DOWN_CONDE) ||
X
Xiaoyu Wang 已提交
313
      TSDB_SYSTEM_TABLE == pScan->tableType) {
314 315 316
    return TSDB_CODE_SUCCESS;
  }

X
Xiaoyu Wang 已提交
317 318
  SNode*  pPrimaryKeyCond = NULL;
  SNode*  pOtherCond = NULL;
X
Xiaoyu Wang 已提交
319 320
  int32_t code = nodesPartitionCond(&pScan->node.pConditions, &pPrimaryKeyCond, &pScan->pTagIndexCond, &pScan->pTagCond,
                                    &pOtherCond);
321
  if (TSDB_CODE_SUCCESS == code && NULL != pPrimaryKeyCond) {
322
    code = pushDownCondOptCalcTimeRange(pCxt, pScan, &pPrimaryKeyCond, &pOtherCond);
323 324 325 326 327
  }
  if (TSDB_CODE_SUCCESS == code) {
    pScan->node.pConditions = pOtherCond;
  }

X
Xiaoyu Wang 已提交
328
  if (TSDB_CODE_SUCCESS == code) {
329
    OPTIMIZE_FLAG_SET_MASK(pScan->node.optimizedFlag, OPTIMIZE_FLAG_PUSH_DOWN_CONDE);
X
Xiaoyu Wang 已提交
330 331
    pCxt->optimized = true;
  } else {
332 333 334 335 336 337 338
    nodesDestroyNode(pPrimaryKeyCond);
    nodesDestroyNode(pOtherCond);
  }

  return code;
}

339
static bool pushDownCondOptBelongThisTable(SNode* pCondCol, SNodeList* pTableCols) {
340 341 342 343 344 345 346
  SNode* pTableCol = NULL;
  FOREACH(pTableCol, pTableCols) {
    if (nodesEqualNode(pCondCol, pTableCol)) {
      return true;
    }
  }
  return false;
347 348
}

349
static EDealRes pushDownCondOptIsCrossTableCond(SNode* pNode, void* pContext) {
350 351
  SCpdIsMultiTableCondCxt* pCxt = pContext;
  if (QUERY_NODE_COLUMN == nodeType(pNode)) {
352
    if (pushDownCondOptBelongThisTable(pNode, pCxt->pLeftCols)) {
353
      pCxt->havaLeftCol = true;
354
    } else if (pushDownCondOptBelongThisTable(pNode, pCxt->pRightCols)) {
355 356 357 358 359
      pCxt->haveRightCol = true;
    }
    return pCxt->havaLeftCol && pCxt->haveRightCol ? DEAL_RES_END : DEAL_RES_CONTINUE;
  }
  return DEAL_RES_CONTINUE;
360 361
}

362 363
static ECondAction pushDownCondOptGetCondAction(EJoinType joinType, SNodeList* pLeftCols, SNodeList* pRightCols,
                                                SNode* pNode) {
X
Xiaoyu Wang 已提交
364 365
  SCpdIsMultiTableCondCxt cxt = {
      .pLeftCols = pLeftCols, .pRightCols = pRightCols, .havaLeftCol = false, .haveRightCol = false};
366
  nodesWalkExpr(pNode, pushDownCondOptIsCrossTableCond, &cxt);
X
Xiaoyu Wang 已提交
367 368 369 370 371
  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)));
372 373
}

374 375
static int32_t pushDownCondOptPartLogicCond(SJoinLogicNode* pJoin, SNode** pOnCond, SNode** pLeftChildCond,
                                            SNode** pRightChildCond) {
376 377 378 379 380 381 382
  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 已提交
383
  int32_t    code = TSDB_CODE_SUCCESS;
384 385 386 387 388

  SNodeList* pOnConds = NULL;
  SNodeList* pLeftChildConds = NULL;
  SNodeList* pRightChildConds = NULL;
  SNodeList* pRemainConds = NULL;
X
Xiaoyu Wang 已提交
389
  SNode*     pCond = NULL;
390
  FOREACH(pCond, pLogicCond->pParameterList) {
391
    ECondAction condAction = pushDownCondOptGetCondAction(pJoin->joinType, pLeftCols, pRightCols, pCond);
392 393 394 395 396 397 398 399
    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));
400
    }
401 402
    if (TSDB_CODE_SUCCESS != code) {
      break;
403 404
    }
  }
405 406 407 408 409 410

  SNode* pTempOnCond = NULL;
  SNode* pTempLeftChildCond = NULL;
  SNode* pTempRightChildCond = NULL;
  SNode* pTempRemainCond = NULL;
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
411
    code = nodesMergeConds(&pTempOnCond, &pOnConds);
412 413
  }
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
414
    code = nodesMergeConds(&pTempLeftChildCond, &pLeftChildConds);
415 416
  }
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
417
    code = nodesMergeConds(&pTempRightChildCond, &pRightChildConds);
418 419
  }
  if (TSDB_CODE_SUCCESS == code) {
X
Xiaoyu Wang 已提交
420
    code = nodesMergeConds(&pTempRemainCond, &pRemainConds);
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
  }

  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;
}

443 444
static int32_t pushDownCondOptPartOpCond(SJoinLogicNode* pJoin, SNode** pOnCond, SNode** pLeftChildCond,
                                         SNode** pRightChildCond) {
X
Xiaoyu Wang 已提交
445 446
  SNodeList*  pLeftCols = ((SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 0))->pTargets;
  SNodeList*  pRightCols = ((SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 1))->pTargets;
447 448
  ECondAction condAction =
      pushDownCondOptGetCondAction(pJoin->joinType, pLeftCols, pRightCols, pJoin->node.pConditions);
449 450 451 452 453 454 455 456 457 458
  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;
459 460 461
  return TSDB_CODE_SUCCESS;
}

462 463
static int32_t pushDownCondOptPartCond(SJoinLogicNode* pJoin, SNode** pOnCond, SNode** pLeftChildCond,
                                       SNode** pRightChildCond) {
464
  if (QUERY_NODE_LOGIC_CONDITION == nodeType(pJoin->node.pConditions)) {
465
    return pushDownCondOptPartLogicCond(pJoin, pOnCond, pLeftChildCond, pRightChildCond);
466
  } else {
467
    return pushDownCondOptPartOpCond(pJoin, pOnCond, pLeftChildCond, pRightChildCond);
468 469 470
  }
}

471 472
static int32_t pushDownCondOptPushCondToOnCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin, SNode** pCond) {
  return pushDownCondOptAppendCond(&pJoin->pOnConditions, pCond);
473 474
}

475 476
static int32_t pushDownCondOptPushCondToScan(SOptimizeContext* pCxt, SScanLogicNode* pScan, SNode** pCond) {
  return pushDownCondOptAppendCond(&pScan->node.pConditions, pCond);
477 478
}

479
static int32_t pushDownCondOptPushCondToChild(SOptimizeContext* pCxt, SLogicNode* pChild, SNode** pCond) {
480 481
  switch (nodeType(pChild)) {
    case QUERY_NODE_LOGIC_PLAN_SCAN:
482
      return pushDownCondOptPushCondToScan(pCxt, (SScanLogicNode*)pChild, pCond);
483 484 485
    default:
      break;
  }
486
  planError("pushDownCondOptPushCondToChild failed, invalid logic plan node %s", nodesNodeName(nodeType(pChild)));
487 488 489
  return TSDB_CODE_PLAN_INTERNAL_ERROR;
}

490
static bool pushDownCondOptIsPriKey(SNode* pNode, SNodeList* pTableCols) {
X
Xiaoyu Wang 已提交
491 492 493 494 495 496 497
  if (QUERY_NODE_COLUMN != nodeType(pNode)) {
    return false;
  }
  SColumnNode* pCol = (SColumnNode*)pNode;
  if (PRIMARYKEY_TIMESTAMP_COL_ID != pCol->colId) {
    return false;
  }
498
  return pushDownCondOptBelongThisTable(pNode, pTableCols);
X
Xiaoyu Wang 已提交
499 500
}

501
static bool pushDownCondOptIsPriKeyEqualCond(SJoinLogicNode* pJoin, SNode* pCond) {
X
Xiaoyu Wang 已提交
502 503 504
  if (QUERY_NODE_OPERATOR != nodeType(pCond)) {
    return false;
  }
505

506
  SOperatorNode* pOper = (SOperatorNode*)pCond;
507 508 509 510 511 512
  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;
513 514 515 516
  if (pushDownCondOptIsPriKey(pOper->pLeft, pLeftCols)) {
    return pushDownCondOptIsPriKey(pOper->pRight, pRightCols);
  } else if (pushDownCondOptIsPriKey(pOper->pLeft, pRightCols)) {
    return pushDownCondOptIsPriKey(pOper->pRight, pLeftCols);
X
Xiaoyu Wang 已提交
517 518 519 520
  }
  return false;
}

521
static bool pushDownCondOptContainPriKeyEqualCond(SJoinLogicNode* pJoin, SNode* pCond) {
522 523 524 525
  if (QUERY_NODE_LOGIC_CONDITION == nodeType(pCond)) {
    SLogicConditionNode* pLogicCond = (SLogicConditionNode*)pCond;
    if (LOGIC_COND_TYPE_AND != pLogicCond->condType) {
      return false;
X
Xiaoyu Wang 已提交
526
    }
527 528 529
    bool   hasPrimaryKeyEqualCond = false;
    SNode* pCond = NULL;
    FOREACH(pCond, pLogicCond->pParameterList) {
530
      if (pushDownCondOptContainPriKeyEqualCond(pJoin, pCond)) {
531 532 533 534 535 536
        hasPrimaryKeyEqualCond = true;
        break;
      }
    }
    return hasPrimaryKeyEqualCond;
  } else {
537
    return pushDownCondOptIsPriKeyEqualCond(pJoin, pCond);
538 539 540
  }
}

541
static int32_t pushDownCondOptCheckJoinOnCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) {
X
Xiaoyu Wang 已提交
542
  if (NULL == pJoin->pOnConditions) {
X
Xiaoyu Wang 已提交
543
    return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_NOT_SUPPORT_CROSS_JOIN);
X
Xiaoyu Wang 已提交
544
  }
545
  if (!pushDownCondOptContainPriKeyEqualCond(pJoin, pJoin->pOnConditions)) {
546
    return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_EXPECTED_TS_EQUAL);
X
Xiaoyu Wang 已提交
547
  }
548
  return TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
549 550
}

551 552
static int32_t pushDownCondOptDealJoin(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) {
  if (OPTIMIZE_FLAG_TEST_MASK(pJoin->node.optimizedFlag, OPTIMIZE_FLAG_PUSH_DOWN_CONDE)) {
553 554 555
    return TSDB_CODE_SUCCESS;
  }

X
Xiaoyu Wang 已提交
556
  if (NULL == pJoin->node.pConditions) {
557
    return pushDownCondOptCheckJoinOnCond(pCxt, pJoin);
X
Xiaoyu Wang 已提交
558 559
  }

X
Xiaoyu Wang 已提交
560 561 562
  SNode*  pOnCond = NULL;
  SNode*  pLeftChildCond = NULL;
  SNode*  pRightChildCond = NULL;
563
  int32_t code = pushDownCondOptPartCond(pJoin, &pOnCond, &pLeftChildCond, &pRightChildCond);
564
  if (TSDB_CODE_SUCCESS == code && NULL != pOnCond) {
565
    code = pushDownCondOptPushCondToOnCond(pCxt, pJoin, &pOnCond);
566 567
  }
  if (TSDB_CODE_SUCCESS == code && NULL != pLeftChildCond) {
568 569
    code =
        pushDownCondOptPushCondToChild(pCxt, (SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 0), &pLeftChildCond);
570 571
  }
  if (TSDB_CODE_SUCCESS == code && NULL != pRightChildCond) {
572 573
    code =
        pushDownCondOptPushCondToChild(pCxt, (SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 1), &pRightChildCond);
574 575
  }

X
Xiaoyu Wang 已提交
576
  if (TSDB_CODE_SUCCESS == code) {
577
    OPTIMIZE_FLAG_SET_MASK(pJoin->node.optimizedFlag, OPTIMIZE_FLAG_PUSH_DOWN_CONDE);
X
Xiaoyu Wang 已提交
578
    pCxt->optimized = true;
579
    code = pushDownCondOptCheckJoinOnCond(pCxt, pJoin);
X
Xiaoyu Wang 已提交
580
  } else {
581 582 583 584 585 586 587 588
    nodesDestroyNode(pOnCond);
    nodesDestroyNode(pLeftChildCond);
    nodesDestroyNode(pRightChildCond);
  }

  return code;
}

589
static int32_t pushDownCondOptDealAgg(SOptimizeContext* pCxt, SAggLogicNode* pAgg) {
590 591 592 593
  // todo
  return TSDB_CODE_SUCCESS;
}

594
static int32_t pushDownCondOptimizeImpl(SOptimizeContext* pCxt, SLogicNode* pLogicNode) {
595 596 597
  int32_t code = TSDB_CODE_SUCCESS;
  switch (nodeType(pLogicNode)) {
    case QUERY_NODE_LOGIC_PLAN_SCAN:
598
      code = pushDownCondOptDealScan(pCxt, (SScanLogicNode*)pLogicNode);
599 600
      break;
    case QUERY_NODE_LOGIC_PLAN_JOIN:
601
      code = pushDownCondOptDealJoin(pCxt, (SJoinLogicNode*)pLogicNode);
602 603
      break;
    case QUERY_NODE_LOGIC_PLAN_AGG:
604
      code = pushDownCondOptDealAgg(pCxt, (SAggLogicNode*)pLogicNode);
605 606 607 608 609 610 611
      break;
    default:
      break;
  }
  if (TSDB_CODE_SUCCESS == code) {
    SNode* pChild = NULL;
    FOREACH(pChild, pLogicNode->pChildren) {
612
      code = pushDownCondOptimizeImpl(pCxt, (SLogicNode*)pChild);
613 614 615 616 617 618 619 620
      if (TSDB_CODE_SUCCESS != code) {
        break;
      }
    }
  }
  return code;
}

621 622
static int32_t pushDownCondOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
  return pushDownCondOptimizeImpl(pCxt, pLogicSubplan->pNode);
623 624
}

625
static bool sortPriKeyOptIsPriKeyOrderBy(SNodeList* pSortKeys) {
X
Xiaoyu Wang 已提交
626 627 628
  if (1 != LIST_LENGTH(pSortKeys)) {
    return false;
  }
X
Xiaoyu Wang 已提交
629
  SNode* pNode = ((SOrderByExprNode*)nodesListGetNode(pSortKeys, 0))->pExpr;
X
Xiaoyu Wang 已提交
630 631 632
  return (QUERY_NODE_COLUMN == nodeType(pNode) ? (PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pNode)->colId) : false);
}

633
static bool sortPriKeyOptMayBeOptimized(SLogicNode* pNode) {
X
Xiaoyu Wang 已提交
634 635 636
  if (QUERY_NODE_LOGIC_PLAN_SORT != nodeType(pNode)) {
    return false;
  }
637 638 639
  SSortLogicNode* pSort = (SSortLogicNode*)pNode;
  if (pSort->groupSort || !sortPriKeyOptIsPriKeyOrderBy(pSort->pSortKeys) || 1 != LIST_LENGTH(pSort->node.pChildren)) {
    return TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
640 641 642 643
  }
  return true;
}

644
static int32_t sortPriKeyOptGetScanNodesImpl(SLogicNode* pNode, bool* pNotOptimize, SNodeList** pScanNodes) {
X
Xiaoyu Wang 已提交
645 646 647 648
  int32_t code = TSDB_CODE_SUCCESS;

  switch (nodeType(pNode)) {
    case QUERY_NODE_LOGIC_PLAN_SCAN:
X
Xiaoyu Wang 已提交
649
      if (TSDB_SUPER_TABLE != ((SScanLogicNode*)pNode)->tableType) {
650
        return nodesListMakeAppend(pScanNodes, (SNode*)pNode);
651 652
      }
      break;
X
Xiaoyu Wang 已提交
653
    case QUERY_NODE_LOGIC_PLAN_JOIN:
654 655
      code =
          sortPriKeyOptGetScanNodesImpl((SLogicNode*)nodesListGetNode(pNode->pChildren, 0), pNotOptimize, pScanNodes);
X
Xiaoyu Wang 已提交
656
      if (TSDB_CODE_SUCCESS == code) {
657 658
        code =
            sortPriKeyOptGetScanNodesImpl((SLogicNode*)nodesListGetNode(pNode->pChildren, 1), pNotOptimize, pScanNodes);
X
Xiaoyu Wang 已提交
659 660 661 662 663 664 665 666 667 668 669
      }
      return code;
    case QUERY_NODE_LOGIC_PLAN_AGG:
      *pNotOptimize = true;
      return code;
    default:
      break;
  }

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

673
  return sortPriKeyOptGetScanNodesImpl((SLogicNode*)nodesListGetNode(pNode->pChildren, 0), pNotOptimize, pScanNodes);
X
Xiaoyu Wang 已提交
674 675
}

676
static int32_t sortPriKeyOptGetScanNodes(SLogicNode* pNode, SNodeList** pScanNodes) {
X
Xiaoyu Wang 已提交
677
  bool    notOptimize = false;
678
  int32_t code = sortPriKeyOptGetScanNodesImpl(pNode, &notOptimize, pScanNodes);
X
Xiaoyu Wang 已提交
679 680 681 682 683 684
  if (TSDB_CODE_SUCCESS != code || notOptimize) {
    nodesClearList(*pScanNodes);
  }
  return code;
}

685
static EOrder sortPriKeyOptGetPriKeyOrder(SSortLogicNode* pSort) {
X
Xiaoyu Wang 已提交
686 687 688
  return ((SOrderByExprNode*)nodesListGetNode(pSort->pSortKeys, 0))->order;
}

689 690 691
static int32_t sortPriKeyOptApply(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan, SSortLogicNode* pSort,
                                  SNodeList* pScanNodes) {
  EOrder order = sortPriKeyOptGetPriKeyOrder(pSort);
X
Xiaoyu Wang 已提交
692 693
  if (ORDER_DESC == order) {
    SNode* pScan = NULL;
X
Xiaoyu Wang 已提交
694
    FOREACH(pScan, pScanNodes) { TSWAP(((SScanLogicNode*)pScan)->scanSeq[0], ((SScanLogicNode*)pScan)->scanSeq[1]); }
X
Xiaoyu Wang 已提交
695
  }
X
Xiaoyu Wang 已提交
696

697 698 699 700 701
  int32_t code =
      replaceLogicNode(pLogicSubplan, (SLogicNode*)pSort, (SLogicNode*)nodesListGetNode(pSort->node.pChildren, 0));
  if (TSDB_CODE_SUCCESS == code) {
    NODES_CLEAR_LIST(pSort->node.pChildren);
    nodesDestroyNode((SNode*)pSort);
X
Xiaoyu Wang 已提交
702
  }
703
  return code;
X
Xiaoyu Wang 已提交
704 705
}

706
static int32_t sortPrimaryKeyOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan, SSortLogicNode* pSort) {
X
Xiaoyu Wang 已提交
707
  SNodeList* pScanNodes = NULL;
708
  int32_t    code = sortPriKeyOptGetScanNodes((SLogicNode*)nodesListGetNode(pSort->node.pChildren, 0), &pScanNodes);
X
Xiaoyu Wang 已提交
709
  if (TSDB_CODE_SUCCESS == code && NULL != pScanNodes) {
710
    code = sortPriKeyOptApply(pCxt, pLogicSubplan, pSort, pScanNodes);
X
Xiaoyu Wang 已提交
711 712 713 714 715
  }
  nodesClearList(pScanNodes);
  return code;
}

716 717
static int32_t sortPrimaryKeyOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
  SSortLogicNode* pSort = (SSortLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, sortPriKeyOptMayBeOptimized);
X
Xiaoyu Wang 已提交
718 719 720
  if (NULL == pSort) {
    return TSDB_CODE_SUCCESS;
  }
721
  return sortPrimaryKeyOptimizeImpl(pCxt, pLogicSubplan, pSort);
X
Xiaoyu Wang 已提交
722 723
}

724
static bool smaIndexOptMayBeOptimized(SLogicNode* pNode) {
X
Xiaoyu Wang 已提交
725 726 727
  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 已提交
728 729 730 731
    return false;
  }

  SScanLogicNode* pScan = (SScanLogicNode*)pNode;
X
Xiaoyu Wang 已提交
732
  if (NULL == pScan->pSmaIndexes || NULL != pScan->node.pConditions) {
X
Xiaoyu Wang 已提交
733 734 735
    return false;
  }

X
Xiaoyu Wang 已提交
736
  return true;
X
Xiaoyu Wang 已提交
737 738
}

739 740
static int32_t smaIndexOptCreateMerge(SLogicNode* pChild, SNodeList* pMergeKeys, SNodeList* pTargets,
                                      SLogicNode** pOutput) {
741
  SMergeLogicNode* pMerge = (SMergeLogicNode*)nodesMakeNode(QUERY_NODE_LOGIC_PLAN_MERGE);
X
Xiaoyu Wang 已提交
742 743 744
  if (NULL == pMerge) {
    return TSDB_CODE_OUT_OF_MEMORY;
  }
X
Xiaoyu Wang 已提交
745
  pMerge->node.precision = pChild->precision;
X
Xiaoyu Wang 已提交
746
  pMerge->numOfChannels = 2;
X
Xiaoyu Wang 已提交
747
  pMerge->pMergeKeys = pMergeKeys;
X
Xiaoyu Wang 已提交
748
  pMerge->node.pTargets = pTargets;
X
Xiaoyu Wang 已提交
749
  pMerge->pInputs = nodesCloneList(pChild->pTargets);
X
Xiaoyu Wang 已提交
750
  if (NULL == pMerge->pInputs) {
751
    nodesDestroyNode((SNode*)pMerge);
X
Xiaoyu Wang 已提交
752
    return TSDB_CODE_OUT_OF_MEMORY;
X
Xiaoyu Wang 已提交
753
  }
X
Xiaoyu Wang 已提交
754 755 756 757 758

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

759 760
static int32_t smaIndexOptRecombinationNode(SLogicSubplan* pLogicSubplan, SLogicNode* pInterval, SLogicNode* pMerge,
                                            SLogicNode* pSmaScan) {
761
  int32_t code = nodesListMakeAppend(&pMerge->pChildren, (SNode*)pInterval);
X
Xiaoyu Wang 已提交
762
  if (TSDB_CODE_SUCCESS == code) {
763
    code = nodesListMakeAppend(&pMerge->pChildren, (SNode*)pSmaScan);
X
Xiaoyu Wang 已提交
764
  }
X
Xiaoyu Wang 已提交
765 766 767 768
  if (TSDB_CODE_SUCCESS == code) {
    code = replaceLogicNode(pLogicSubplan, pInterval, pMerge);
    pSmaScan->pParent = pMerge;
    pInterval->pParent = pMerge;
X
Xiaoyu Wang 已提交
769 770 771 772
  }
  return code;
}

773 774
static int32_t smaIndexOptCreateSmaScan(SScanLogicNode* pScan, STableIndexInfo* pIndex, SNodeList* pCols,
                                        SLogicNode** pOutput) {
775
  SScanLogicNode* pSmaScan = (SScanLogicNode*)nodesMakeNode(QUERY_NODE_LOGIC_PLAN_SCAN);
X
Xiaoyu Wang 已提交
776 777 778 779 780 781 782 783 784 785 786 787 788 789
  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 已提交
790 791
  pSmaScan->node.pTargets = nodesCloneList(pCols);
  if (NULL == pSmaScan->pVgroupList || NULL == pSmaScan->node.pTargets) {
792
    nodesDestroyNode((SNode*)pSmaScan);
X
Xiaoyu Wang 已提交
793 794 795 796 797 798
    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 已提交
799
  *pOutput = (SLogicNode*)pSmaScan;
X
Xiaoyu Wang 已提交
800 801 802
  return TSDB_CODE_SUCCESS;
}

803
static bool smaIndexOptEqualInterval(SScanLogicNode* pScan, SWindowLogicNode* pWindow, STableIndexInfo* pIndex) {
X
Xiaoyu Wang 已提交
804 805 806 807 808
  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 已提交
809 810 811 812 813 814 815 816 817 818 819
  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 已提交
820 821 822
  return true;
}

823
static SNode* smaIndexOptCreateSmaCol(SNode* pFunc, uint64_t tableId, int32_t colId) {
824
  SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN);
X
Xiaoyu Wang 已提交
825 826 827 828 829 830 831
  if (NULL == pCol) {
    return NULL;
  }
  pCol->tableId = tableId;
  pCol->tableType = TSDB_SUPER_TABLE;
  pCol->colId = colId;
  pCol->colType = COLUMN_TYPE_COLUMN;
X
Xiaoyu Wang 已提交
832
  strcpy(pCol->colName, ((SExprNode*)pFunc)->aliasName);
X
Xiaoyu Wang 已提交
833 834 835 836 837
  pCol->node.resType = ((SExprNode*)pFunc)->resType;
  strcpy(pCol->node.aliasName, ((SExprNode*)pFunc)->aliasName);
  return (SNode*)pCol;
}

838
static int32_t smaIndexOptFindSmaFunc(SNode* pQueryFunc, SNodeList* pSmaFuncs) {
X
Xiaoyu Wang 已提交
839 840 841 842 843 844 845 846 847 848 849
  int32_t index = 0;
  SNode*  pSmaFunc = NULL;
  FOREACH(pSmaFunc, pSmaFuncs) {
    if (nodesEqualNode(pQueryFunc, pSmaFunc)) {
      return index;
    }
    ++index;
  }
  return -1;
}

850 851
static int32_t smaIndexOptCreateSmaCols(SNodeList* pFuncs, uint64_t tableId, SNodeList* pSmaFuncs, SNodeList** pOutput,
                                        int32_t* pWStrartIndex) {
X
Xiaoyu Wang 已提交
852 853 854 855
  SNodeList* pCols = NULL;
  SNode*     pFunc = NULL;
  int32_t    code = TSDB_CODE_SUCCESS;
  int32_t    index = 0;
X
Xiaoyu Wang 已提交
856
  int32_t    smaFuncIndex = -1;
X
Xiaoyu Wang 已提交
857
  *pWStrartIndex = -1;
X
Xiaoyu Wang 已提交
858 859 860 861
  FOREACH(pFunc, pFuncs) {
    if (FUNCTION_TYPE_WSTARTTS == ((SFunctionNode*)pFunc)->funcType) {
      *pWStrartIndex = index;
    }
862
    smaFuncIndex = smaIndexOptFindSmaFunc(pFunc, pSmaFuncs);
X
Xiaoyu Wang 已提交
863 864 865
    if (smaFuncIndex < 0) {
      break;
    } else {
866
      code = nodesListMakeStrictAppend(&pCols, smaIndexOptCreateSmaCol(pFunc, tableId, smaFuncIndex + 2));
X
Xiaoyu Wang 已提交
867 868 869 870 871 872 873
      if (TSDB_CODE_SUCCESS != code) {
        break;
      }
    }
    ++index;
  }

X
Xiaoyu Wang 已提交
874
  if (TSDB_CODE_SUCCESS == code && smaFuncIndex >= 0) {
X
Xiaoyu Wang 已提交
875 876 877 878 879 880 881 882
    *pOutput = pCols;
  } else {
    nodesDestroyList(pCols);
  }

  return code;
}

883 884
static int32_t smaIndexOptCouldApplyIndex(SScanLogicNode* pScan, STableIndexInfo* pIndex, SNodeList** pCols,
                                          int32_t* pWStrartIndex) {
X
Xiaoyu Wang 已提交
885
  SWindowLogicNode* pWindow = (SWindowLogicNode*)pScan->node.pParent;
886
  if (!smaIndexOptEqualInterval(pScan, pWindow, pIndex)) {
X
Xiaoyu Wang 已提交
887 888 889 890 891
    return TSDB_CODE_SUCCESS;
  }
  SNodeList* pSmaFuncs = NULL;
  int32_t    code = nodesStringToList(pIndex->expr, &pSmaFuncs);
  if (TSDB_CODE_SUCCESS == code) {
892
    code = smaIndexOptCreateSmaCols(pWindow->pFuncs, pIndex->dstTbUid, pSmaFuncs, pCols, pWStrartIndex);
X
Xiaoyu Wang 已提交
893 894 895 896 897
  }
  nodesDestroyList(pSmaFuncs);
  return code;
}

898
static SNode* smaIndexOptCreateWStartTs() {
899
  SFunctionNode* pWStart = (SFunctionNode*)nodesMakeNode(QUERY_NODE_FUNCTION);
X
Xiaoyu Wang 已提交
900 901 902 903 904 905
  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)) {
906
    nodesDestroyNode((SNode*)pWStart);
X
Xiaoyu Wang 已提交
907 908 909 910 911
    return NULL;
  }
  return (SNode*)pWStart;
}

912
static int32_t smaIndexOptCreateMergeKey(SNode* pCol, SNodeList** pMergeKeys) {
913
  SOrderByExprNode* pMergeKey = (SOrderByExprNode*)nodesMakeNode(QUERY_NODE_ORDER_BY_EXPR);
X
Xiaoyu Wang 已提交
914 915 916 917 918
  if (NULL == pMergeKey) {
    return TSDB_CODE_OUT_OF_MEMORY;
  }
  pMergeKey->pExpr = nodesCloneNode(pCol);
  if (NULL == pMergeKey->pExpr) {
919
    nodesDestroyNode((SNode*)pMergeKey);
X
Xiaoyu Wang 已提交
920 921 922 923
    return TSDB_CODE_OUT_OF_MEMORY;
  }
  pMergeKey->order = ORDER_ASC;
  pMergeKey->nullOrder = NULL_ORDER_FIRST;
924
  return nodesListMakeStrictAppend(pMergeKeys, (SNode*)pMergeKey);
X
Xiaoyu Wang 已提交
925 926
}

927
static int32_t smaIndexOptRewriteInterval(SWindowLogicNode* pInterval, int32_t wstrartIndex, SNodeList** pMergeKeys) {
X
Xiaoyu Wang 已提交
928
  if (wstrartIndex < 0) {
929
    SNode* pWStart = smaIndexOptCreateWStartTs();
X
Xiaoyu Wang 已提交
930 931 932 933 934 935 936 937 938 939
    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;
  }
940
  return smaIndexOptCreateMergeKey(nodesListGetNode(pInterval->node.pTargets, wstrartIndex), pMergeKeys);
X
Xiaoyu Wang 已提交
941 942
}

943 944
static int32_t smaIndexOptApplyIndexExt(SLogicSubplan* pLogicSubplan, SScanLogicNode* pScan, STableIndexInfo* pIndex,
                                        SNodeList* pSmaCols, int32_t wstrartIndex) {
X
Xiaoyu Wang 已提交
945 946 947 948 949
  SWindowLogicNode* pInterval = (SWindowLogicNode*)pScan->node.pParent;
  SNodeList*        pMergeTargets = nodesCloneList(pInterval->node.pTargets);
  if (NULL == pMergeTargets) {
    return TSDB_CODE_OUT_OF_MEMORY;
  }
X
Xiaoyu Wang 已提交
950 951
  SLogicNode* pSmaScan = NULL;
  SLogicNode* pMerge = NULL;
X
Xiaoyu Wang 已提交
952
  SNodeList*  pMergeKeys = NULL;
953
  int32_t     code = smaIndexOptRewriteInterval(pInterval, wstrartIndex, &pMergeKeys);
X
Xiaoyu Wang 已提交
954
  if (TSDB_CODE_SUCCESS == code) {
955
    code = smaIndexOptCreateSmaScan(pScan, pIndex, pSmaCols, &pSmaScan);
X
Xiaoyu Wang 已提交
956 957
  }
  if (TSDB_CODE_SUCCESS == code) {
958
    code = smaIndexOptCreateMerge(pScan->node.pParent, pMergeKeys, pMergeTargets, &pMerge);
X
Xiaoyu Wang 已提交
959 960
  }
  if (TSDB_CODE_SUCCESS == code) {
961
    code = smaIndexOptRecombinationNode(pLogicSubplan, pScan->node.pParent, pMerge, pSmaScan);
X
Xiaoyu Wang 已提交
962 963 964 965
  }
  return code;
}

966 967
static int32_t smaIndexOptApplyIndex(SLogicSubplan* pLogicSubplan, SScanLogicNode* pScan, STableIndexInfo* pIndex,
                                     SNodeList* pSmaCols, int32_t wstrartIndex) {
X
Xiaoyu Wang 已提交
968
  SLogicNode* pSmaScan = NULL;
969
  int32_t     code = smaIndexOptCreateSmaScan(pScan, pIndex, pSmaCols, &pSmaScan);
X
Xiaoyu Wang 已提交
970 971 972 973 974 975
  if (TSDB_CODE_SUCCESS == code) {
    code = replaceLogicNode(pLogicSubplan, pScan->node.pParent, pSmaScan);
  }
  return code;
}

976
static void smaIndexOptDestroySmaIndex(void* p) { taosMemoryFree(((STableIndexInfo*)p)->expr); }
X
Xiaoyu Wang 已提交
977

978
static int32_t smaIndexOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan, SScanLogicNode* pScan) {
X
Xiaoyu Wang 已提交
979
  int32_t code = TSDB_CODE_SUCCESS;
X
Xiaoyu Wang 已提交
980 981 982 983 984
  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;
985
    code = smaIndexOptCouldApplyIndex(pScan, pIndex, &pSmaCols, &wstrartIndex);
X
Xiaoyu Wang 已提交
986
    if (TSDB_CODE_SUCCESS == code && NULL != pSmaCols) {
987 988
      code = smaIndexOptApplyIndex(pLogicSubplan, pScan, pIndex, pSmaCols, wstrartIndex);
      taosArrayDestroyEx(pScan->pSmaIndexes, smaIndexOptDestroySmaIndex);
X
Xiaoyu Wang 已提交
989
      pScan->pSmaIndexes = NULL;
990
      pCxt->optimized = true;
X
Xiaoyu Wang 已提交
991
      break;
X
Xiaoyu Wang 已提交
992 993
    }
  }
X
Xiaoyu Wang 已提交
994
  return code;
X
Xiaoyu Wang 已提交
995
}
X
Xiaoyu Wang 已提交
996

997 998
static int32_t smaIndexOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
  SScanLogicNode* pScan = (SScanLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, smaIndexOptMayBeOptimized);
X
Xiaoyu Wang 已提交
999 1000 1001
  if (NULL == pScan) {
    return TSDB_CODE_SUCCESS;
  }
1002
  return smaIndexOptimizeImpl(pCxt, pLogicSubplan, pScan);
X
Xiaoyu Wang 已提交
1003 1004
}

X
Xiaoyu Wang 已提交
1005 1006
static EDealRes partTagsOptHasColImpl(SNode* pNode, void* pContext) {
  if (QUERY_NODE_COLUMN == nodeType(pNode)) {
X
Xiaoyu Wang 已提交
1007
    if (COLUMN_TYPE_TAG != ((SColumnNode*)pNode)->colType && COLUMN_TYPE_TBNAME != ((SColumnNode*)pNode)->colType) {
X
Xiaoyu Wang 已提交
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
      *(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 已提交
1021
static bool partTagsIsOptimizableNode(SLogicNode* pNode) {
X
Xiaoyu Wang 已提交
1022
  return ((QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pNode) ||
X
Xiaoyu Wang 已提交
1023
           (QUERY_NODE_LOGIC_PLAN_AGG == nodeType(pNode) && NULL != ((SAggLogicNode*)pNode)->pGroupKeys &&
X
Xiaoyu Wang 已提交
1024
            NULL != ((SAggLogicNode*)pNode)->pAggFuncs)) &&
X
Xiaoyu Wang 已提交
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036
          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;
  }
}

1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054
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;
}

X
Xiaoyu Wang 已提交
1055
static bool partTagsOptMayBeOptimized(SLogicNode* pNode) {
X
Xiaoyu Wang 已提交
1056
  if (!partTagsIsOptimizableNode(pNode)) {
X
Xiaoyu Wang 已提交
1057 1058 1059
    return false;
  }

1060
  return !partTagsOptHasCol(partTagsGetPartKeys(pNode)) && partTagsOptAreSupportedFuncs(partTagsGetFuncs(pNode));
X
Xiaoyu Wang 已提交
1061 1062
}

X
Xiaoyu Wang 已提交
1063 1064 1065 1066 1067 1068 1069 1070 1071
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;
X
Xiaoyu Wang 已提交
1072
    pFunc->node.resType = ((SColumnNode*)*pNode)->node.resType;
X
Xiaoyu Wang 已提交
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085
    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;
}

1086
static SNode* partTagsCreateWrapperFunc(const char* pFuncName, SNode* pNode) {
1087 1088 1089 1090 1091
  SFunctionNode* pFunc = (SFunctionNode*)nodesMakeNode(QUERY_NODE_FUNCTION);
  if (NULL == pFunc) {
    return NULL;
  }

1092
  strcpy(pFunc->functionName, pFuncName);
1093 1094
  if (QUERY_NODE_COLUMN == nodeType(pNode)) {
    SColumnNode* pCol = (SColumnNode*)pNode;
1095
    sprintf(pFunc->node.aliasName, "%s.%s", pCol->tableAlias, pCol->colName);
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
  } 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;
}

1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125
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;
1126
  FOREACH(pNode, pGroupTags) {
1127 1128 1129 1130 1131
    if (hasIndefRowsSelectFunc) {
      code = nodesListStrictAppend(pAggFuncs, partTagsCreateWrapperFunc("_select_value", pNode));
    } else {
      code = nodesListStrictAppend(pAggFuncs, partTagsCreateWrapperFunc("_group_key", pNode));
    }
1132
    if (TSDB_CODE_SUCCESS != code) {
1133
      break;
1134 1135
    }
  }
1136
  return code;
1137 1138
}

X
Xiaoyu Wang 已提交
1139
static int32_t partTagsOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
X
Xiaoyu Wang 已提交
1140 1141
  SLogicNode* pNode = optFindPossibleNode(pLogicSubplan->pNode, partTagsOptMayBeOptimized);
  if (NULL == pNode) {
X
Xiaoyu Wang 已提交
1142 1143 1144
    return TSDB_CODE_SUCCESS;
  }

X
Xiaoyu Wang 已提交
1145 1146 1147
  int32_t         code = TSDB_CODE_SUCCESS;
  SScanLogicNode* pScan = (SScanLogicNode*)nodesListGetNode(pNode->pChildren, 0);
  if (QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pNode)) {
1148
    TSWAP(((SPartitionLogicNode*)pNode)->pPartitionKeys, pScan->pGroupTags);
X
Xiaoyu Wang 已提交
1149 1150 1151 1152 1153 1154
    int32_t code = replaceLogicNode(pLogicSubplan, pNode, (SLogicNode*)pScan);
    if (TSDB_CODE_SUCCESS == code) {
      NODES_CLEAR_LIST(pNode->pChildren);
      nodesDestroyNode((SNode*)pNode);
    }
  } else {
1155 1156 1157
    SAggLogicNode* pAgg = (SAggLogicNode*)pNode;
    SNode*         pGroupKey = NULL;
    FOREACH(pGroupKey, pAgg->pGroupKeys) {
X
Xiaoyu Wang 已提交
1158
      code = nodesListMakeStrictAppend(
1159
          &pScan->pGroupTags, nodesCloneNode(nodesListGetNode(((SGroupingSetNode*)pGroupKey)->pParameterList, 0)));
X
Xiaoyu Wang 已提交
1160 1161 1162 1163
      if (TSDB_CODE_SUCCESS != code) {
        break;
      }
    }
1164
    NODES_DESTORY_LIST(pAgg->pGroupKeys);
1165
    code = partTagsRewriteGroupTagsToFuncs(pScan->pGroupTags, pAgg->pAggFuncs);
X
Xiaoyu Wang 已提交
1166 1167
  }
  if (TSDB_CODE_SUCCESS == code) {
1168
    code = partTagsOptRebuildTbanme(pScan->pGroupTags);
X
Xiaoyu Wang 已提交
1169 1170 1171 1172
  }
  return code;
}

S
slzhou 已提交
1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
static bool eliminateProjOptCheckProjColumnNames(SProjectLogicNode* pProjectNode) {
  SHashObj* pProjColNameHash = taosHashInit(16, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
  SNode*    pProjection;
  FOREACH(pProjection, pProjectNode->pProjections) {
    char*    projColumnName = ((SColumnNode*)pProjection)->colName;
    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));
    }
  }
  taosHashCleanup(pProjColNameHash);
  return true;
}

1191
static bool eliminateProjOptMayBeOptimized(SLogicNode* pNode) {
X
Xiaoyu Wang 已提交
1192
  // TODO: enable this optimization after new mechanising that map projection and targets of project node
1193 1194 1195
  if (NULL != pNode->pParent) {
    return false;
  }
X
Xiaoyu Wang 已提交
1196

1197 1198 1199 1200 1201
  if (QUERY_NODE_LOGIC_PLAN_PROJECT != nodeType(pNode) || 1 != LIST_LENGTH(pNode->pChildren)) {
    return false;
  }

  SProjectLogicNode* pProjectNode = (SProjectLogicNode*)pNode;
1202 1203
  if (NULL != pProjectNode->node.pLimit || NULL != pProjectNode->node.pSlimit ||
      NULL != pProjectNode->node.pConditions) {
1204 1205 1206
    return false;
  }

X
Xiaoyu Wang 已提交
1207
  SNode* pProjection;
1208 1209 1210 1211 1212 1213
  FOREACH(pProjection, pProjectNode->pProjections) {
    SExprNode* pExprNode = (SExprNode*)pProjection;
    if (QUERY_NODE_COLUMN != nodeType(pExprNode)) {
      return false;
    }
  }
1214

S
slzhou 已提交
1215
  return eliminateProjOptCheckProjColumnNames(pProjectNode);
1216 1217
}

X
Xiaoyu Wang 已提交
1218 1219
static int32_t eliminateProjOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan,
                                         SProjectLogicNode* pProjectNode) {
1220
  SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pProjectNode->node.pChildren, 0);
X
Xiaoyu Wang 已提交
1221
  SNodeList*  pNewChildTargets = nodesMakeList();
1222 1223 1224 1225 1226

  SNode* pProjection = NULL;
  FOREACH(pProjection, pProjectNode->pProjections) {
    SNode* pChildTarget = NULL;
    FOREACH(pChildTarget, pChild->pTargets) {
1227
      if (strcmp(((SColumnNode*)pProjection)->colName, ((SColumnNode*)pChildTarget)->colName) == 0) {
1228
        nodesListAppend(pNewChildTargets, nodesCloneNode(pChildTarget));
1229
        break;
1230 1231 1232
      }
    }
  }
1233 1234
  nodesDestroyList(pChild->pTargets);
  pChild->pTargets = pNewChildTargets;
X
Xiaoyu Wang 已提交
1235

1236 1237 1238 1239 1240
  int32_t code = replaceLogicNode(pLogicSubplan, (SLogicNode*)pProjectNode, pChild);
  if (TSDB_CODE_SUCCESS == code) {
    NODES_CLEAR_LIST(pProjectNode->node.pChildren);
    nodesDestroyNode((SNode*)pProjectNode);
  }
1241
  pCxt->optimized = true;
1242 1243 1244 1245 1246
  return code;
}

static int32_t eliminateProjOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
  SProjectLogicNode* pProjectNode =
X
Xiaoyu Wang 已提交
1247
      (SProjectLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, eliminateProjOptMayBeOptimized);
1248 1249 1250 1251 1252 1253 1254 1255

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

  return eliminateProjOptimizeImpl(pCxt, pLogicSubplan, pProjectNode);
}

1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285
static bool rewriteTailOptMayBeOptimized(SLogicNode* pNode) {
  return QUERY_NODE_LOGIC_PLAN_INDEF_ROWS_FUNC == nodeType(pNode) && ((SIndefRowsFuncLogicNode*)pNode)->isTailFunc;
}

static SNode* rewriteTailOptCreateOrderByExpr(SNode* pSortKey) {
  SOrderByExprNode* pOrder = (SOrderByExprNode*)nodesMakeNode(QUERY_NODE_ORDER_BY_EXPR);
  if (NULL == pOrder) {
    return NULL;
  }
  pOrder->order = ORDER_DESC;
  pOrder->pExpr = nodesCloneNode(pSortKey);
  if (NULL == pOrder->pExpr) {
    nodesDestroyNode((SNode*)pOrder);
    return NULL;
  }
  return (SNode*)pOrder;
}

static int32_t rewriteTailOptCreateLimit(SNode* pLimit, SNode* pOffset, SNode** pOutput) {
  SLimitNode* pLimitNode = (SLimitNode*)nodesMakeNode(QUERY_NODE_LIMIT);
  if (NULL == pLimitNode) {
    return TSDB_CODE_OUT_OF_MEMORY;
  }
  pLimitNode->limit = NULL == pLimit ? -1 : ((SValueNode*)pLimit)->datum.i;
  pLimitNode->offset = NULL == pOffset ? -1 : ((SValueNode*)pOffset)->datum.i;
  *pOutput = (SNode*)pLimitNode;
  return TSDB_CODE_SUCCESS;
}

static bool rewriteTailOptNeedGroupSort(SIndefRowsFuncLogicNode* pIndef) {
1286 1287 1288 1289 1290
  if (1 != LIST_LENGTH(pIndef->node.pChildren)) {
    return false;
  }
  SNode* pChild = nodesListGetNode(pIndef->node.pChildren, 0);
  return QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pChild) ||
1291
         (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pChild) && NULL != ((SScanLogicNode*)pChild)->pGroupTags);
1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343
}

static int32_t rewriteTailOptCreateSort(SIndefRowsFuncLogicNode* pIndef, SLogicNode** pOutput) {
  SSortLogicNode* pSort = (SSortLogicNode*)nodesMakeNode(QUERY_NODE_LOGIC_PLAN_SORT);
  if (NULL == pSort) {
    return TSDB_CODE_OUT_OF_MEMORY;
  }

  pSort->groupSort = rewriteTailOptNeedGroupSort(pIndef);
  TSWAP(pSort->node.pChildren, pIndef->node.pChildren);
  pSort->node.precision = pIndef->node.precision;

  // tail(expr, [limit, offset,] _rowts)
  SFunctionNode* pTail = (SFunctionNode*)nodesListGetNode(pIndef->pFuncs, 0);
  int32_t        rowtsIndex = LIST_LENGTH(pTail->pParameterList) - 1;

  int32_t code = nodesListMakeStrictAppend(
      &pSort->pSortKeys, rewriteTailOptCreateOrderByExpr(nodesListGetNode(pTail->pParameterList, rowtsIndex)));
  if (TSDB_CODE_SUCCESS == code) {
    pSort->node.pTargets = nodesCloneList(((SLogicNode*)nodesListGetNode(pSort->node.pChildren, 0))->pTargets);
    if (NULL == pSort->node.pTargets) {
      code = TSDB_CODE_OUT_OF_MEMORY;
    }
  }

  if (TSDB_CODE_SUCCESS == code) {
    *pOutput = (SLogicNode*)pSort;
  } else {
    nodesDestroyNode((SNode*)pSort);
  }

  return code;
}

static SNode* rewriteTailOptCreateProjectExpr(SFunctionNode* pTail) {
  SNode* pExpr = nodesCloneNode(nodesListGetNode(pTail->pParameterList, 0));
  if (NULL == pExpr) {
    return NULL;
  }
  strcpy(((SExprNode*)pExpr)->aliasName, pTail->node.aliasName);
  return pExpr;
}

static int32_t rewriteTailOptCreateProject(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;

X
Xiaoyu Wang 已提交
1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354
  // tail(expr, [limit, offset,] _rowts)
  SFunctionNode* pTail = (SFunctionNode*)nodesListGetNode(pIndef->pFuncs, 0);
  int32_t        limitIndex = LIST_LENGTH(pTail->pParameterList) > 2 ? 1 : -1;
  int32_t        offsetIndex = LIST_LENGTH(pTail->pParameterList) > 3 ? 2 : -1;

  int32_t code = nodesListMakeStrictAppend(&pProject->pProjections, rewriteTailOptCreateProjectExpr(pTail));
  if (TSDB_CODE_SUCCESS == code) {
    code = rewriteTailOptCreateLimit(limitIndex < 0 ? NULL : nodesListGetNode(pTail->pParameterList, limitIndex),
                                     offsetIndex < 0 ? NULL : nodesListGetNode(pTail->pParameterList, offsetIndex),
                                     &pProject->node.pLimit);
  }
1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384
  if (TSDB_CODE_SUCCESS == code) {
    *pOutput = (SLogicNode*)pProject;
  } else {
    nodesDestroyNode((SNode*)pProject);
  }
  return code;
}

static int32_t rewriteTailOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan,
                                       SIndefRowsFuncLogicNode* pIndef) {
  SLogicNode* pSort = NULL;
  SLogicNode* pProject = NULL;
  int32_t     code = rewriteTailOptCreateSort(pIndef, &pSort);
  if (TSDB_CODE_SUCCESS == code) {
    code = rewriteTailOptCreateProject(pIndef, &pProject);
  }
  if (TSDB_CODE_SUCCESS == code) {
    code = nodesListMakeAppend(&pProject->pChildren, (SNode*)pSort);
    pSort->pParent = pProject;
    pSort = NULL;
  }
  if (TSDB_CODE_SUCCESS == code) {
    code = replaceLogicNode(pLogicSubplan, (SLogicNode*)pIndef, pProject);
  }
  if (TSDB_CODE_SUCCESS == code) {
    nodesDestroyNode((SNode*)pIndef);
  } else {
    nodesDestroyNode((SNode*)pSort);
    nodesDestroyNode((SNode*)pProject);
  }
1385
  pCxt->optimized = true;
1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399
  return code;
}

static int32_t rewriteTailOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
  SIndefRowsFuncLogicNode* pIndef =
      (SIndefRowsFuncLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, rewriteTailOptMayBeOptimized);

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

  return rewriteTailOptimizeImpl(pCxt, pLogicSubplan, pIndef);
}

S
slzhou 已提交
1400 1401 1402
static bool eliminateSetOpMayBeOptimized(SLogicNode* pNode) {
  SLogicNode* pParent = pNode->pParent;
  if (NULL == pParent ||
X
Xiaoyu Wang 已提交
1403
      QUERY_NODE_LOGIC_PLAN_AGG != nodeType(pParent) && QUERY_NODE_LOGIC_PLAN_PROJECT != nodeType(pParent) ||
S
slzhou 已提交
1404 1405 1406
      LIST_LENGTH(pParent->pChildren) < 2) {
    return false;
  }
X
Xiaoyu Wang 已提交
1407
  if (nodeType(pNode) != nodeType(pNode->pParent) || LIST_LENGTH(pNode->pChildren) < 2) {
S
slzhou 已提交
1408 1409 1410 1411 1412
    return false;
  }
  return true;
}

X
Xiaoyu Wang 已提交
1413 1414
static int32_t eliminateSetOpOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan,
                                          SLogicNode* pSetOpNode) {
S
slzhou 已提交
1415 1416 1417 1418
  SNode* pSibling;
  FOREACH(pSibling, pSetOpNode->pParent->pChildren) {
    if (nodesEqualNode(pSibling, (SNode*)pSetOpNode)) {
      SNode* pChild;
X
Xiaoyu Wang 已提交
1419
      FOREACH(pChild, pSetOpNode->pChildren) { ((SLogicNode*)pChild)->pParent = pSetOpNode->pParent; }
S
slzhou 已提交
1420 1421
      INSERT_LIST(pSetOpNode->pParent->pChildren, pSetOpNode->pChildren);

S
slzhou 已提交
1422 1423
      pSetOpNode->pChildren = NULL;
      ERASE_NODE(pSetOpNode->pParent->pChildren);
1424
      pCxt->optimized = true;
S
slzhou 已提交
1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440
      return TSDB_CODE_SUCCESS;
    }
  }

  return TSDB_CODE_PLAN_INTERNAL_ERROR;
}

static int32_t eliminateSetOpOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
  SLogicNode* pSetOpNode = optFindPossibleNode(pLogicSubplan->pNode, eliminateSetOpMayBeOptimized);
  if (NULL == pSetOpNode) {
    return TSDB_CODE_SUCCESS;
  }

  return eliminateSetOpOptimizeImpl(pCxt, pLogicSubplan, pSetOpNode);
}

1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466
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) {
1467
    sprintf(pFunc->node.aliasName, "%s", pSelectValue->node.aliasName);
1468
  } else {
1469
    sprintf(pFunc->node.aliasName, "%s.%p", pFunc->functionName, pFunc);
1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618
  }
  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);
}

S
slzhou 已提交
1619 1620 1621 1622 1623
// merge projects
static bool mergeProjectsMayBeOptimized(SLogicNode* pNode) {
  if (QUERY_NODE_LOGIC_PLAN_PROJECT != nodeType(pNode) || 1 != LIST_LENGTH(pNode->pChildren)) {
    return false;
  }
X
Xiaoyu Wang 已提交
1624
  SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pNode->pChildren, 0);
S
slzhou 已提交
1625
  if (QUERY_NODE_LOGIC_PLAN_PROJECT != nodeType(pChild) || 1 < LIST_LENGTH(pChild->pChildren) ||
1626
      NULL != pChild->pConditions || NULL != pChild->pLimit || NULL != pChild->pSlimit) {
S
slzhou 已提交
1627 1628 1629 1630 1631 1632
    return false;
  }
  return true;
}

typedef struct SMergeProjectionsContext {
1633
  SProjectLogicNode* pChildProj;
X
Xiaoyu Wang 已提交
1634
  int32_t            errCode;
S
slzhou 已提交
1635 1636 1637
} SMergeProjectionsContext;

static EDealRes mergeProjectionsExpr(SNode** pNode, void* pContext) {
1638
  SMergeProjectionsContext* pCxt = pContext;
X
Xiaoyu Wang 已提交
1639
  SProjectLogicNode*        pChildProj = pCxt->pChildProj;
1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659
  if (QUERY_NODE_COLUMN == nodeType(*pNode)) {
    SNode* pTarget;
    FOREACH(pTarget, ((SLogicNode*)pChildProj)->pTargets) {
      if (nodesEqualNode(pTarget, *pNode)) {
        SNode* pProjection;
        FOREACH(pProjection, pChildProj->pProjections) {
          if (0 == strcmp(((SColumnNode*)pTarget)->colName, ((SExprNode*)pProjection)->aliasName)) {
            SNode* pExpr = nodesCloneNode(pProjection);
            if (pExpr == NULL) {
              pCxt->errCode = terrno;
              return DEAL_RES_ERROR;
            }
            nodesDestroyNode(*pNode);
            *pNode = pExpr;
          }
        }
      }
    }
    return DEAL_RES_IGNORE_CHILD;
  }
S
slzhou 已提交
1660 1661 1662
  return DEAL_RES_CONTINUE;
}

1663
static int32_t mergeProjectsOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan, SLogicNode* pSelfNode) {
X
Xiaoyu Wang 已提交
1664
  SLogicNode*              pChild = (SLogicNode*)nodesListGetNode(pSelfNode->pChildren, 0);
1665
  SMergeProjectionsContext cxt = {.pChildProj = (SProjectLogicNode*)pChild, .errCode = TSDB_CODE_SUCCESS};
1666

1667
  nodesRewriteExprs(((SProjectLogicNode*)pSelfNode)->pProjections, mergeProjectionsExpr, &cxt);
1668
  int32_t code = cxt.errCode;
1669

1670 1671 1672 1673 1674
  if (TSDB_CODE_SUCCESS == code) {
    if (1 == LIST_LENGTH(pChild->pChildren)) {
      SLogicNode* pGrandChild = (SLogicNode*)nodesListGetNode(pChild->pChildren, 0);
      code = replaceLogicNode(pLogicSubplan, pChild, pGrandChild);
    } else {  // no grand child
1675
      NODES_CLEAR_LIST(pSelfNode->pChildren);
1676 1677 1678 1679 1680 1681 1682
    }
  }

  if (TSDB_CODE_SUCCESS == code) {
    NODES_CLEAR_LIST(pChild->pChildren);
  }
  nodesDestroyNode((SNode*)pChild);
1683
  pCxt->optimized = true;
1684
  return code;
S
slzhou 已提交
1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695
}

static int32_t mergeProjectsOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
  SLogicNode* pProjectNode = optFindPossibleNode(pLogicSubplan->pNode, mergeProjectsMayBeOptimized);
  if (NULL == pProjectNode) {
    return TSDB_CODE_SUCCESS;
  }

  return mergeProjectsOptimizeImpl(pCxt, pLogicSubplan, pProjectNode);
}

X
Xiaoyu Wang 已提交
1696 1697
// clang-format off
static const SOptimizeRule optimizeRuleSet[] = {
1698
  {.pName = "ScanPath",                   .optimizeFunc = scanPathOptimize},
1699 1700
  {.pName = "PushDownCondition",          .optimizeFunc = pushDownCondOptimize},
  {.pName = "SortPrimaryKey",             .optimizeFunc = sortPrimaryKeyOptimize},
1701
  {.pName = "SmaIndex",                   .optimizeFunc = smaIndexOptimize},
S
slzhou 已提交
1702
  {.pName = "PartitionTags",              .optimizeFunc = partTagsOptimize},
S
slzhou 已提交
1703
  {.pName = "MergeProjects",              .optimizeFunc = mergeProjectsOptimize},
S
slzhou 已提交
1704
  {.pName = "EliminateProject",           .optimizeFunc = eliminateProjOptimize},
X
Xiaoyu Wang 已提交
1705
  {.pName = "EliminateSetOperator",       .optimizeFunc = eliminateSetOpOptimize},
1706 1707
  {.pName = "RewriteTail",                .optimizeFunc = rewriteTailOptimize},
  {.pName = "RewriteUnique",              .optimizeFunc = rewriteUniqueOptimize}
X
Xiaoyu Wang 已提交
1708 1709
};
// clang-format on
1710 1711 1712

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

1713 1714 1715 1716 1717 1718 1719
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);
}

X
Xiaoyu Wang 已提交
1720
static int32_t applyOptimizeRule(SPlanContext* pCxt, SLogicSubplan* pLogicSubplan) {
X
Xiaoyu Wang 已提交
1721
  SOptimizeContext cxt = {.pPlanCxt = pCxt, .optimized = false};
1722
  bool             optimized = false;
1723
  do {
1724
    optimized = false;
1725
    for (int32_t i = 0; i < optimizeRuleNum; ++i) {
1726
      cxt.optimized = false;
X
Xiaoyu Wang 已提交
1727
      int32_t code = optimizeRuleSet[i].optimizeFunc(&cxt, pLogicSubplan);
1728 1729 1730
      if (TSDB_CODE_SUCCESS != code) {
        return code;
      }
1731 1732 1733 1734
      if (cxt.optimized) {
        optimized = true;
        dumpLogicSubplan(optimizeRuleSet[i].pName, pLogicSubplan);
      }
1735
    }
1736
  } while (optimized);
X
Xiaoyu Wang 已提交
1737 1738
  return TSDB_CODE_SUCCESS;
}
1739

X
Xiaoyu Wang 已提交
1740
int32_t optimizeLogicPlan(SPlanContext* pCxt, SLogicSubplan* pLogicSubplan) {
X
Xiaoyu Wang 已提交
1741
  return applyOptimizeRule(pCxt, pLogicSubplan);
X
Xiaoyu Wang 已提交
1742
}