planOptimizer.c 52.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 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 990
      pScan->pSmaIndexes = NULL;
      break;
X
Xiaoyu Wang 已提交
991 992
    }
  }
X
Xiaoyu Wang 已提交
993
  return code;
X
Xiaoyu Wang 已提交
994
}
X
Xiaoyu Wang 已提交
995

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

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

X
Xiaoyu Wang 已提交
1041
  return !partTagsOptHasCol(partTagsGetPartKeys(pNode));
X
Xiaoyu Wang 已提交
1042 1043
}

X
Xiaoyu Wang 已提交
1044 1045 1046 1047 1048 1049 1050 1051 1052
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 已提交
1053
    pFunc->node.resType = ((SColumnNode*)*pNode)->node.resType;
X
Xiaoyu Wang 已提交
1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
    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 已提交
1067
static int32_t partTagsOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
X
Xiaoyu Wang 已提交
1068 1069
  SLogicNode* pNode = optFindPossibleNode(pLogicSubplan->pNode, partTagsOptMayBeOptimized);
  if (NULL == pNode) {
X
Xiaoyu Wang 已提交
1070 1071 1072
    return TSDB_CODE_SUCCESS;
  }

X
Xiaoyu Wang 已提交
1073 1074 1075
  int32_t         code = TSDB_CODE_SUCCESS;
  SScanLogicNode* pScan = (SScanLogicNode*)nodesListGetNode(pNode->pChildren, 0);
  if (QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pNode)) {
1076
    TSWAP(((SPartitionLogicNode*)pNode)->pPartitionKeys, pScan->pGroupTags);
X
Xiaoyu Wang 已提交
1077 1078 1079 1080 1081 1082
    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 已提交
1083 1084 1085
    SNode* pGroupKey = NULL;
    FOREACH(pGroupKey, ((SAggLogicNode*)pNode)->pGroupKeys) {
      code = nodesListMakeStrictAppend(
1086
          &pScan->pGroupTags, nodesCloneNode(nodesListGetNode(((SGroupingSetNode*)pGroupKey)->pParameterList, 0)));
X
Xiaoyu Wang 已提交
1087 1088 1089 1090
      if (TSDB_CODE_SUCCESS != code) {
        break;
      }
    }
X
Xiaoyu Wang 已提交
1091
    NODES_DESTORY_LIST(((SAggLogicNode*)pNode)->pGroupKeys);
X
Xiaoyu Wang 已提交
1092 1093
  }
  if (TSDB_CODE_SUCCESS == code) {
1094
    code = partTagsOptRebuildTbanme(pScan->pGroupTags);
X
Xiaoyu Wang 已提交
1095 1096 1097 1098
  }
  return code;
}

S
slzhou 已提交
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116
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;
}

1117
static bool eliminateProjOptMayBeOptimized(SLogicNode* pNode) {
X
Xiaoyu Wang 已提交
1118
  // TODO: enable this optimization after new mechanising that map projection and targets of project node
1119 1120 1121
  if (NULL != pNode->pParent) {
    return false;
  }
X
Xiaoyu Wang 已提交
1122

1123 1124 1125 1126 1127
  if (QUERY_NODE_LOGIC_PLAN_PROJECT != nodeType(pNode) || 1 != LIST_LENGTH(pNode->pChildren)) {
    return false;
  }

  SProjectLogicNode* pProjectNode = (SProjectLogicNode*)pNode;
1128
  if (NULL != pProjectNode->node.pLimit || NULL != pProjectNode->node.pSlimit) {
1129 1130 1131
    return false;
  }

X
Xiaoyu Wang 已提交
1132
  SNode* pProjection;
1133 1134 1135 1136 1137 1138
  FOREACH(pProjection, pProjectNode->pProjections) {
    SExprNode* pExprNode = (SExprNode*)pProjection;
    if (QUERY_NODE_COLUMN != nodeType(pExprNode)) {
      return false;
    }
  }
1139

S
slzhou 已提交
1140
  return eliminateProjOptCheckProjColumnNames(pProjectNode);
1141 1142
}

X
Xiaoyu Wang 已提交
1143 1144
static int32_t eliminateProjOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan,
                                         SProjectLogicNode* pProjectNode) {
1145
  SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pProjectNode->node.pChildren, 0);
X
Xiaoyu Wang 已提交
1146
  SNodeList*  pNewChildTargets = nodesMakeList();
1147 1148 1149 1150 1151

  SNode* pProjection = NULL;
  FOREACH(pProjection, pProjectNode->pProjections) {
    SNode* pChildTarget = NULL;
    FOREACH(pChildTarget, pChild->pTargets) {
1152
      if (strcmp(((SColumnNode*)pProjection)->colName, ((SColumnNode*)pChildTarget)->colName) == 0) {
1153
        nodesListAppend(pNewChildTargets, nodesCloneNode(pChildTarget));
1154
        break;
1155 1156 1157
      }
    }
  }
1158 1159
  nodesDestroyList(pChild->pTargets);
  pChild->pTargets = pNewChildTargets;
X
Xiaoyu Wang 已提交
1160

1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
  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 已提交
1171
      (SProjectLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, eliminateProjOptMayBeOptimized);
1172 1173 1174 1175 1176 1177 1178 1179

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

  return eliminateProjOptimizeImpl(pCxt, pLogicSubplan, pProjectNode);
}

1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209
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) {
1210 1211 1212 1213 1214
  if (1 != LIST_LENGTH(pIndef->node.pChildren)) {
    return false;
  }
  SNode* pChild = nodesListGetNode(pIndef->node.pChildren, 0);
  return QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pChild) ||
1215
         (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pChild) && NULL != ((SScanLogicNode*)pChild)->pGroupTags);
1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267
}

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 已提交
1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278
  // 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);
  }
1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 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
  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);
  }
  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 已提交
1322 1323 1324 1325

static bool eliminateSetOpMayBeOptimized(SLogicNode* pNode) {
  SLogicNode* pParent = pNode->pParent;
  if (NULL == pParent ||
X
Xiaoyu Wang 已提交
1326
      QUERY_NODE_LOGIC_PLAN_AGG != nodeType(pParent) && QUERY_NODE_LOGIC_PLAN_PROJECT != nodeType(pParent) ||
S
slzhou 已提交
1327 1328 1329
      LIST_LENGTH(pParent->pChildren) < 2) {
    return false;
  }
X
Xiaoyu Wang 已提交
1330
  if (nodeType(pNode) != nodeType(pNode->pParent) || LIST_LENGTH(pNode->pChildren) < 2) {
S
slzhou 已提交
1331 1332 1333 1334 1335
    return false;
  }
  return true;
}

X
Xiaoyu Wang 已提交
1336 1337
static int32_t eliminateSetOpOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan,
                                          SLogicNode* pSetOpNode) {
S
slzhou 已提交
1338 1339 1340 1341
  SNode* pSibling;
  FOREACH(pSibling, pSetOpNode->pParent->pChildren) {
    if (nodesEqualNode(pSibling, (SNode*)pSetOpNode)) {
      SNode* pChild;
X
Xiaoyu Wang 已提交
1342
      FOREACH(pChild, pSetOpNode->pChildren) { ((SLogicNode*)pChild)->pParent = pSetOpNode->pParent; }
S
slzhou 已提交
1343 1344
      INSERT_LIST(pSetOpNode->pParent->pChildren, pSetOpNode->pChildren);

S
slzhou 已提交
1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362
      pSetOpNode->pChildren = NULL;
      ERASE_NODE(pSetOpNode->pParent->pChildren);
      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);
}

S
slzhou 已提交
1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377
//===================================================================================================================
// merge projects
static bool mergeProjectsMayBeOptimized(SLogicNode* pNode) {
  if (QUERY_NODE_LOGIC_PLAN_PROJECT != nodeType(pNode) || 1 != LIST_LENGTH(pNode->pChildren)) {
    return false;
  }
  SLogicNode *pChild = (SLogicNode*)nodesListGetNode(pNode->pChildren, 0);
  if (QUERY_NODE_LOGIC_PLAN_PROJECT != nodeType(pChild) || 1 < LIST_LENGTH(pChild->pChildren) ||
      NULL != pChild->pConditions || NULL != pNode->pLimit || NULL != pNode->pSlimit) {
    return false;
  }
  return true;
}

typedef struct SMergeProjectionsContext {
1378 1379
  SProjectLogicNode* pChildProj;
  int32_t errCode;
S
slzhou 已提交
1380 1381 1382
} SMergeProjectionsContext;

static EDealRes mergeProjectionsExpr(SNode** pNode, void* pContext) {
1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404
  SMergeProjectionsContext* pCxt = pContext;
  SProjectLogicNode* pChildProj = pCxt->pChildProj;
  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 已提交
1405 1406 1407 1408 1409
  return DEAL_RES_CONTINUE;
}

static int32_t mergeProjectsOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan, SLogicNode* pProjectNode) {
  SProjectLogicNode* pProject = (SProjectLogicNode*)pProjectNode;
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428
  SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pProjectNode->pChildren, 0);
  SMergeProjectionsContext cxt = {.pChildProj = (SProjectLogicNode*)pChild};

  nodesRewriteExprs(pProject->pProjections, mergeProjectionsExpr, &cxt);
  int32_t code = cxt.errCode;
  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
      NODES_CLEAR_LIST(pProjectNode->pChildren);
    }
  }

  if (TSDB_CODE_SUCCESS == code) {
    NODES_CLEAR_LIST(pChild->pChildren);
  }
  nodesDestroyNode((SNode*)pChild);
  return code;
S
slzhou 已提交
1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439
}

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 已提交
1440 1441
// clang-format off
static const SOptimizeRule optimizeRuleSet[] = {
1442
  {.pName = "ScanPath",                   .optimizeFunc = scanPathOptimize},
1443 1444
  {.pName = "PushDownCondition",          .optimizeFunc = pushDownCondOptimize},
  {.pName = "SortPrimaryKey",             .optimizeFunc = sortPrimaryKeyOptimize},
1445
  {.pName = "SmaIndex",                   .optimizeFunc = smaIndexOptimize},
S
slzhou 已提交
1446
  {.pName = "PartitionTags",              .optimizeFunc = partTagsOptimize},
S
slzhou 已提交
1447
  {.pName = "MergeProjects",              .optimizeFunc = mergeProjectsOptimize},
S
slzhou 已提交
1448
  {.pName = "EliminateProject",           .optimizeFunc = eliminateProjOptimize},
S
slzhou 已提交
1449
  {.pName = "EliminateSetOperator",       .optimizeFunc = eliminateSetOpOptimize},
1450
  {.pName = "RewriteTail",                .optimizeFunc = rewriteTailOptimize}
X
Xiaoyu Wang 已提交
1451 1452
};
// clang-format on
1453 1454 1455

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

X
Xiaoyu Wang 已提交
1456
static int32_t applyOptimizeRule(SPlanContext* pCxt, SLogicSubplan* pLogicSubplan) {
X
Xiaoyu Wang 已提交
1457
  SOptimizeContext cxt = {.pPlanCxt = pCxt, .optimized = false};
1458 1459 1460
  do {
    cxt.optimized = false;
    for (int32_t i = 0; i < optimizeRuleNum; ++i) {
X
Xiaoyu Wang 已提交
1461
      int32_t code = optimizeRuleSet[i].optimizeFunc(&cxt, pLogicSubplan);
1462 1463 1464 1465 1466
      if (TSDB_CODE_SUCCESS != code) {
        return code;
      }
    }
  } while (cxt.optimized);
X
Xiaoyu Wang 已提交
1467 1468
  return TSDB_CODE_SUCCESS;
}
1469

X
Xiaoyu Wang 已提交
1470
int32_t optimizeLogicPlan(SPlanContext* pCxt, SLogicSubplan* pLogicSubplan) {
X
Xiaoyu Wang 已提交
1471
  return applyOptimizeRule(pCxt, pLogicSubplan);
X
Xiaoyu Wang 已提交
1472
}