• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

taosdata / TDengine / #3531

19 Nov 2024 10:42AM UTC coverage: 60.213% (-0.006%) from 60.219%
#3531

push

travis-ci

web-flow
Merge pull request #28777 from taosdata/fix/3.0/TD-32366

fix:TD-32366/stmt add geometry datatype check

118529 of 252344 branches covered (46.97%)

Branch coverage included in aggregate %.

7 of 48 new or added lines in 3 files covered. (14.58%)

2282 existing lines in 115 files now uncovered.

199096 of 275161 relevant lines covered (72.36%)

6067577.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

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

16
#include "filter.h"
17
#include "functionMgt.h"
18
#include "planInt.h"
19
#include "systable.h"
20
#include "tglobal.h"
21
#include "ttime.h"
22
#include "parser.h"
23

24
#define OPTIMIZE_FLAG_MASK(n) (1 << n)
25

26
#define OPTIMIZE_FLAG_SCAN_PATH       OPTIMIZE_FLAG_MASK(0)
27
#define OPTIMIZE_FLAG_PUSH_DOWN_CONDE OPTIMIZE_FLAG_MASK(1)
28
#define OPTIMIZE_FLAG_STB_JOIN        OPTIMIZE_FLAG_MASK(2)
29
#define OPTIMIZE_FLAG_ELIMINATE_PROJ  OPTIMIZE_FLAG_MASK(3)
30
#define OPTIMIZE_FLAG_JOIN_COND       OPTIMIZE_FLAG_MASK(4)
31

32
#define OPTIMIZE_FLAG_SET_MASK(val, mask)  (val) |= (mask)
33
#define OPTIMIZE_FLAG_CLEAR_MASK(val, mask)  (val) &= (~(mask))
34
#define OPTIMIZE_FLAG_TEST_MASK(val, mask) (((val) & (mask)) != 0)
35

36
typedef struct SOptimizeContext {
37
  SPlanContext* pPlanCxt;
38
  bool          optimized;
39
} SOptimizeContext;
40

41
typedef int32_t (*FOptimize)(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan);
42

43
typedef struct SOptimizeRule {
44
  char*     pName;
45
  FOptimize optimizeFunc;
46
} SOptimizeRule;
47

48
typedef struct SOptimizePKCtx {
49
  SNodeList* pList;
50
  int32_t    code;
51
} SOptimizePKCtx;
52

53
typedef enum EScanOrder { SCAN_ORDER_ASC = 1, SCAN_ORDER_DESC, SCAN_ORDER_BOTH } EScanOrder;
54

55
typedef struct SOsdInfo {
56
  SScanLogicNode* pScan;
57
  SNodeList*      pSdrFuncs;
58
  SNodeList*      pDsoFuncs;
59
  EScanOrder      scanOrder;
60
} SOsdInfo;
61

62
typedef struct SCpdIsMultiTableCondCxt {
63
  SSHashObj* pLeftTbls;
64
  SSHashObj* pRightTbls;
65
  bool       havaLeftCol;
66
  bool       haveRightCol;
67
  bool       condIsNull;
68
} SCpdIsMultiTableCondCxt;
69

70
typedef struct SCpdIsMultiTableResCxt {
71
  SSHashObj* pLeftTbls;
72
  SSHashObj* pRightTbls;
73
  bool       haveLeftCol;
74
  bool       haveRightCol;
75
  bool       leftColOp;
76
  bool       rightColOp;
77
  bool       leftColNonNull;
78
  bool       rightColNonNull;
79
} SCpdIsMultiTableResCxt;
80

81
typedef struct SCpdCollRewriteTableColsCxt {
82
  int32_t    code;
83
  SSHashObj* pLeftTbls;
84
  SSHashObj* pRightTbls;
85
  SSHashObj* pLeftCols;
86
  SSHashObj* pRightCols;
87
} SCpdCollRewriteTableColsCxt;
88

89

90
typedef struct SCpdCollectTableColCxt {
91
  SSHashObj* pTables;
92
  SNodeList* pResCols;
93
  SHashObj*  pColHash;
94
  int32_t    errCode;
95
} SCpdCollectTableColCxt;
96

97

98
typedef enum ECondAction {
99
  COND_ACTION_STAY = 1,
100
  COND_ACTION_PUSH_JOIN,
101
  COND_ACTION_PUSH_LEFT_CHILD,
102
  COND_ACTION_PUSH_RIGHT_CHILD
103
  // after supporting outer join, there are other possibilities
104
} ECondAction;
105

106
#define PUSH_DOWN_LEFT_FLT  (1 << 0)
107
#define PUSH_DOWN_RIGHT_FLT (1 << 1)
108
#define PUSH_DOWN_ON_COND   (1 << 2)
109
#define PUSH_DONW_FLT_COND  (PUSH_DOWN_LEFT_FLT | PUSH_DOWN_RIGHT_FLT)
110
#define PUSH_DOWN_ALL_COND  (PUSH_DOWN_LEFT_FLT | PUSH_DOWN_RIGHT_FLT | PUSH_DOWN_ON_COND)
111

112
typedef struct SJoinOptimizeOpt {
113
  int8_t pushDownFlag;
114
} SJoinOptimizeOpt;
115

116
typedef bool (*FMayBeOptimized)(SLogicNode* pNode, void* pCtx);
117
typedef bool (*FShouldBeOptimized)(SLogicNode* pNode, void* pInfo);
118

119
#if 0
120
static SJoinOptimizeOpt gJoinOpt[JOIN_TYPE_MAX_VALUE][JOIN_STYPE_MAX_VALUE] = {
121
           /* NONE                OUTER                  SEMI                  ANTI                   ANY                    ASOF                   WINDOW */
122
/*INNER*/  {{PUSH_DOWN_ALL_COND}, {0},                   {0},                  {0},                   {PUSH_DOWN_ALL_COND},  {0},                   {0}},
123
/*LEFT*/   {{0},                  {PUSH_DOWN_LEFT_FLT},  {PUSH_DOWN_ALL_COND}, {PUSH_DOWN_LEFT_FLT},  {PUSH_DOWN_LEFT_FLT},  {PUSH_DOWN_LEFT_FLT},  {PUSH_DOWN_LEFT_FLT}},
124
/*RIGHT*/  {{0},                  {PUSH_DOWN_RIGHT_FLT}, {PUSH_DOWN_ALL_COND}, {PUSH_DOWN_RIGHT_FLT}, {PUSH_DOWN_RIGHT_FLT}, {PUSH_DOWN_RIGHT_FLT}, {PUSH_DOWN_RIGHT_FLT}},
125
/*FULL*/   {{0},                  {0},                   {0},                  {0},                   {0},                   {0},                   {0}},
126
};
127
#else
128
static SJoinOptimizeOpt gJoinWhereOpt[JOIN_TYPE_MAX_VALUE][JOIN_STYPE_MAX_VALUE] = {
129
           /* NONE                OUTER                  SEMI                  ANTI                   ASOF                   WINDOW */
130
/*INNER*/  {{PUSH_DOWN_ALL_COND}, {0},                   {0},                  {0},                   {0},                   {0}},
131
/*LEFT*/   {{0},                  {PUSH_DOWN_LEFT_FLT},  {PUSH_DOWN_LEFT_FLT}, {PUSH_DOWN_LEFT_FLT},  {PUSH_DOWN_LEFT_FLT},  {PUSH_DOWN_LEFT_FLT}},
132
/*RIGHT*/  {{0},                  {PUSH_DOWN_RIGHT_FLT}, {PUSH_DOWN_RIGHT_FLT},{PUSH_DOWN_RIGHT_FLT}, {PUSH_DOWN_RIGHT_FLT}, {PUSH_DOWN_RIGHT_FLT}},
133
/*FULL*/   {{0},                  {0},                   {0},                  {0},                   {0},                   {0}},
134
};
135

136
static SJoinOptimizeOpt gJoinOnOpt[JOIN_TYPE_MAX_VALUE][JOIN_STYPE_MAX_VALUE] = {
137
           /* NONE                OUTER                  SEMI                  ANTI                   ASOF                   WINDOW */
138
/*INNER*/  {{PUSH_DONW_FLT_COND}, {0},                   {0},                  {0},                   {0},                   {0}},
139
/*LEFT*/   {{0},                  {PUSH_DOWN_RIGHT_FLT}, {PUSH_DONW_FLT_COND}, {PUSH_DOWN_RIGHT_FLT}, {0},                   {0}},
140
/*RIGHT*/  {{0},                  {PUSH_DOWN_LEFT_FLT},  {PUSH_DONW_FLT_COND}, {PUSH_DOWN_LEFT_FLT},  {0},                   {0}},
141
/*FULL*/   {{0},                  {0},                   {0},                  {0},                   {0},                   {0}},
142
};
143

144

145
#endif
146

147
static SLogicNode* optFindPossibleNode(SLogicNode* pNode, FMayBeOptimized func, void* pCtx) {
123,052,387✔
148
  if (func(pNode, pCtx)) {
123,052,387✔
149
    return pNode;
2,070,726✔
150
  }
151
  SNode* pChild;
152
  FOREACH(pChild, pNode->pChildren) {
209,681,574✔
153
    SLogicNode* pScanNode = optFindPossibleNode((SLogicNode*)pChild, func, pCtx);
93,090,425✔
154
    if (NULL != pScanNode) {
93,090,773✔
155
      return pScanNode;
4,391,255✔
156
    }
157
  }
158
  return NULL;
116,591,149✔
159
}
160

161
static bool optFindEligibleNode(SLogicNode* pNode, FShouldBeOptimized func, void* pInfo) {
11,884,527✔
162
  if (func(pNode, pInfo)) {
11,884,527✔
163
    return true;
25✔
164
  }
165
  SNode* pChild;
166
  FOREACH(pChild, pNode->pChildren) {
20,943,295✔
167
    if (optFindEligibleNode((SLogicNode*)pChild, func, pInfo)) {
9,058,812✔
168
      return true;
33✔
169
    }
170
  }
171
  return false;
11,884,483✔
172
}
173

174
static void optResetParent(SLogicNode* pNode) {
21,938✔
175
  SNode* pChild = NULL;
21,938✔
176
  FOREACH(pChild, pNode->pChildren) { ((SLogicNode*)pChild)->pParent = pNode; }
43,876!
177
}
21,938✔
178

179
static EDealRes optRebuildTbanme(SNode** pNode, void* pContext) {
513,336✔
180
  if (QUERY_NODE_COLUMN == nodeType(*pNode) && COLUMN_TYPE_TBNAME == ((SColumnNode*)*pNode)->colType) {
513,336✔
181
    SFunctionNode* pFunc = NULL;
133,276✔
182
    int32_t code = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&pFunc);
133,276✔
183
    if (NULL == pFunc) {
133,276!
184
      *(int32_t*)pContext = code;
×
185
      return DEAL_RES_ERROR;
×
186
    }
187
    strcpy(pFunc->functionName, "tbname");
133,276✔
188
    pFunc->funcType = FUNCTION_TYPE_TBNAME;
133,276✔
189
    pFunc->node.resType = ((SColumnNode*)*pNode)->node.resType;
133,276✔
190
    nodesDestroyNode(*pNode);
133,276✔
191
    *pNode = (SNode*)pFunc;
133,276✔
192
    return DEAL_RES_IGNORE_CHILD;
133,276✔
193
  }
194
  return DEAL_RES_CONTINUE;
380,060✔
195
}
196

197
static void optSetParentOrder(SLogicNode* pNode, EOrder order, SLogicNode* pNodeForcePropagate) {
2,556,871✔
198
  if (NULL == pNode) {
2,556,871✔
199
    return;
399,680✔
200
  }
201
  pNode->inputTsOrder = order;
2,157,191✔
202
  switch (nodeType(pNode)) {
2,157,191✔
203
    // for those nodes that will change the order, stop propagating
204
    // case QUERY_NODE_LOGIC_PLAN_WINDOW:
205
    case QUERY_NODE_LOGIC_PLAN_AGG:
877,931✔
206
    case QUERY_NODE_LOGIC_PLAN_SORT:
207
      if (pNode == pNodeForcePropagate) {
877,931✔
208
        pNode->outputTsOrder = order;
137,698✔
209
        break;
137,698✔
210
      } else
211
        return;
740,233✔
212
    case QUERY_NODE_LOGIC_PLAN_JOIN:
275,796✔
213
      pNode->outputTsOrder = order;
275,796✔
214
      break;
275,796✔
215
    case QUERY_NODE_LOGIC_PLAN_WINDOW:
47,745✔
216
      // Window output ts order default to be asc, and changed when doing sort by primary key optimization.
217
      // We stop propagate the original order to parents.
218
      // Use window output ts order instead.
219
      order = pNode->outputTsOrder;
47,745✔
220
      break;
47,745✔
221
    default:
955,719✔
222
      pNode->outputTsOrder = order;
955,719✔
223
      break;
955,719✔
224
  }
225
  optSetParentOrder(pNode->pParent, order, pNodeForcePropagate);
1,416,958✔
226
}
227

228
EDealRes scanPathOptHaveNormalColImpl(SNode* pNode, void* pContext) {
736,340✔
229
  if (QUERY_NODE_COLUMN == nodeType(pNode)) {
736,340✔
230
    *((bool*)pContext) =
525,640✔
231
        (COLUMN_TYPE_TAG != ((SColumnNode*)pNode)->colType && COLUMN_TYPE_TBNAME != ((SColumnNode*)pNode)->colType);
525,640✔
232
    return *((bool*)pContext) ? DEAL_RES_END : DEAL_RES_IGNORE_CHILD;
525,640✔
233
  }
234
  return DEAL_RES_CONTINUE;
210,700✔
235
}
236

237
static bool scanPathOptHaveNormalCol(SNodeList* pList) {
647,547✔
238
  bool res = false;
647,547✔
239
  nodesWalkExprsPostOrder(pList, scanPathOptHaveNormalColImpl, &res);
647,547✔
240
  return res;
647,551✔
241
}
242

243
static bool scanPathOptMayBeOptimized(SLogicNode* pNode, void* pCtx) {
14,291,716✔
244
  if (OPTIMIZE_FLAG_TEST_MASK(pNode->optimizedFlag, OPTIMIZE_FLAG_SCAN_PATH)) {
14,291,716✔
245
    return false;
3,090,541✔
246
  }
247
  if (QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(pNode)) {
11,201,175✔
248
    return false;
10,246,775✔
249
  }
250
  return true;
954,400✔
251
}
252

253
static bool scanPathOptShouldGetFuncs(SLogicNode* pNode) {
1,908,825✔
254
  if (QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pNode)) {
1,908,825✔
255
    if (!pNode->pParent || QUERY_NODE_LOGIC_PLAN_WINDOW != nodeType(pNode->pParent) ||
161,042!
256
        WINDOW_TYPE_INTERVAL == ((SWindowLogicNode*)pNode->pParent)->winType)
30,968✔
257
      return !scanPathOptHaveNormalCol(((SPartitionLogicNode*)pNode)->pPartitionKeys);
152,424✔
258
    return false;
8,618✔
259
  }
260

261
  if ((QUERY_NODE_LOGIC_PLAN_WINDOW == nodeType(pNode) &&
1,747,783✔
262
       WINDOW_TYPE_INTERVAL == ((SWindowLogicNode*)pNode)->winType)) {
41,903✔
263
    return true;
28,177✔
264
  }
265
  if (QUERY_NODE_LOGIC_PLAN_AGG == nodeType(pNode)) {
1,719,606✔
266
    return !scanPathOptHaveNormalCol(((SAggLogicNode*)pNode)->pGroupKeys);
495,121✔
267
  }
268
  return false;
1,224,485✔
269
}
270

271
static SNodeList* scanPathOptGetAllFuncs(SLogicNode* pNode) {
1,908,825✔
272
  if (!scanPathOptShouldGetFuncs(pNode)) return NULL;
1,908,825✔
273
  switch (nodeType(pNode)) {
528,358!
274
    case QUERY_NODE_LOGIC_PLAN_WINDOW:
28,178✔
275
      return ((SWindowLogicNode*)pNode)->pFuncs;
28,178✔
276
    case QUERY_NODE_LOGIC_PLAN_AGG:
352,609✔
277
      return ((SAggLogicNode*)pNode)->pAggFuncs;
352,609✔
278
    case QUERY_NODE_LOGIC_PLAN_PARTITION:
147,574✔
279
      return ((SPartitionLogicNode*)pNode)->pAggFuncs;
147,574✔
280
    default:
×
281
      break;
×
282
  }
283
  return NULL;
×
284
}
285

286
static bool scanPathOptIsSpecifiedFuncType(const SFunctionNode* pFunc, bool (*typeCheckFn)(int32_t)) {
1,002,223✔
287
  if (!typeCheckFn(pFunc->funcId)) return false;
1,002,223✔
288
  SNode* pPara;
289
  FOREACH(pPara, pFunc->pParameterList) {
874,629✔
290
    if (QUERY_NODE_COLUMN != nodeType(pPara) && QUERY_NODE_VALUE != nodeType(pPara)) {
443,022✔
291
      return false;
18,417✔
292
    }
293
  }
294
  return true;
431,607✔
295
}
296

297
static int32_t scanPathOptGetRelatedFuncs(SScanLogicNode* pScan, SNodeList** pSdrFuncs, SNodeList** pDsoFuncs) {
954,409✔
298
  SNodeList* pAllFuncs = scanPathOptGetAllFuncs(pScan->node.pParent);
954,409✔
299
  SNodeList* pTmpSdrFuncs = NULL;
954,416✔
300
  SNodeList* pTmpDsoFuncs = NULL;
954,416✔
301
  SNode*     pNode = NULL;
954,416✔
302
  bool       otherFunc = false;
954,416✔
303
  FOREACH(pNode, pAllFuncs) {
1,386,026✔
304
    SFunctionNode* pFunc = (SFunctionNode*)pNode;
571,110✔
305
    int32_t        code = TSDB_CODE_SUCCESS;
571,110✔
306
    if (scanPathOptIsSpecifiedFuncType(pFunc, fmIsSpecialDataRequiredFunc)) {
571,110✔
307
      SNode* pNew = NULL;
355,551✔
308
      code = nodesCloneNode(pNode, &pNew);
355,551✔
309
      if (TSDB_CODE_SUCCESS == code) {
355,551!
310
        code = nodesListMakeStrictAppend(&pTmpSdrFuncs, pNew);
355,551✔
311
      }
312
    } else if (scanPathOptIsSpecifiedFuncType(pFunc, fmIsDynamicScanOptimizedFunc)) {
215,559!
313
      SNode* pNew = NULL;
×
314
      code = nodesCloneNode(pNode, &pNew);
×
315
      if (TSDB_CODE_SUCCESS == code) {
×
316
        code = nodesListMakeStrictAppend(&pTmpDsoFuncs, pNew);
×
317
      }
318
    } else if (scanPathOptIsSpecifiedFuncType(pFunc, fmIsSkipScanCheckFunc)) {
215,560✔
319
      continue;
76,059✔
320
    } else {
321
      otherFunc = true;
139,502✔
322
      break;
139,502✔
323
    }
324
    if (TSDB_CODE_SUCCESS != code) {
355,551!
325
      nodesDestroyList(pTmpSdrFuncs);
×
326
      nodesDestroyList(pTmpDsoFuncs);
×
UNCOV
327
      return code;
×
328
    }
329
  }
330
  if (otherFunc) {
954,418✔
331
    nodesDestroyList(pTmpSdrFuncs);
139,502✔
332
    nodesDestroyList(pTmpDsoFuncs);
139,499✔
333
  } else {
334
    *pSdrFuncs = pTmpSdrFuncs;
814,916✔
335
    *pDsoFuncs = pTmpDsoFuncs;
814,916✔
336
  }
337
  return TSDB_CODE_SUCCESS;
954,417✔
338
}
339

340
static int32_t scanPathOptGetScanOrder(SScanLogicNode* pScan, EScanOrder* pScanOrder) {
954,415✔
341
  SNodeList* pAllFuncs = scanPathOptGetAllFuncs(pScan->node.pParent);
954,415✔
342
  SNode*     pNode = NULL;
954,417✔
343
  bool       hasFirst = false;
954,417✔
344
  bool       hasLast = false;
954,417✔
345
  bool       otherFunc = false;
954,417✔
346
  FOREACH(pNode, pAllFuncs) {
1,780,150✔
347
    SFunctionNode* pFunc = (SFunctionNode*)pNode;
825,733✔
348
    if (FUNCTION_TYPE_FIRST == pFunc->funcType) {
825,733✔
349
      hasFirst = true;
26,084✔
350
    } else if (FUNCTION_TYPE_LAST == pFunc->funcType || FUNCTION_TYPE_LAST_ROW == pFunc->funcType) {
799,649✔
351
      hasLast = true;
147,569✔
352
    } else if (FUNCTION_TYPE_SELECT_VALUE != pFunc->funcType) {
652,080✔
353
      otherFunc = true;
628,420✔
354
    }
355
  }
356
  if (hasFirst && hasLast && !otherFunc) {
954,417✔
357
    *pScanOrder = SCAN_ORDER_BOTH;
40✔
358
  } else if (hasLast) {
954,377✔
359
    *pScanOrder = SCAN_ORDER_DESC;
40,888✔
360
  } else {
361
    *pScanOrder = SCAN_ORDER_ASC;
913,489✔
362
  }
363
  return TSDB_CODE_SUCCESS;
954,417✔
364
}
365

366
static int32_t scanPathOptSetOsdInfo(SOsdInfo* pInfo) {
954,412✔
367
  int32_t code = scanPathOptGetRelatedFuncs(pInfo->pScan, &pInfo->pSdrFuncs, &pInfo->pDsoFuncs);
954,412✔
368
  if (TSDB_CODE_SUCCESS == code) {
954,417!
369
    code = scanPathOptGetScanOrder(pInfo->pScan, &pInfo->scanOrder);
954,417✔
370
  }
371
  return code;
954,416✔
372
}
373

374
static int32_t scanPathOptMatch(SOptimizeContext* pCxt, SLogicNode* pLogicNode, SOsdInfo* pInfo) {
3,033,960✔
375
  pInfo->pScan = (SScanLogicNode*)optFindPossibleNode(pLogicNode, scanPathOptMayBeOptimized, NULL);
3,033,960✔
376
  if (NULL == pInfo->pScan) {
3,033,964✔
377
    return TSDB_CODE_SUCCESS;
2,079,551✔
378
  }
379
  return scanPathOptSetOsdInfo(pInfo);
954,413✔
380
}
381

382
static EFuncDataRequired scanPathOptPromoteDataRequired(EFuncDataRequired l, EFuncDataRequired r) {
273,531✔
383
  switch (l) {
273,531!
384
    case FUNC_DATA_REQUIRED_DATA_LOAD:
×
385
      return l;
×
386
    case FUNC_DATA_REQUIRED_SMA_LOAD:
147,691✔
387
      return FUNC_DATA_REQUIRED_DATA_LOAD == r ? r : l;
147,691!
388
    case FUNC_DATA_REQUIRED_NOT_LOAD:
13,942✔
389
      return FUNC_DATA_REQUIRED_FILTEROUT == r ? l : r;
13,942!
390
    default:
111,898✔
391
      break;
111,898✔
392
  }
393
  return r;
111,898✔
394
}
395

396
static int32_t scanPathOptGetDataRequired(SNodeList* pFuncs) {
111,898✔
397
  if (NULL == pFuncs) {
111,898!
398
    return FUNC_DATA_REQUIRED_DATA_LOAD;
×
399
  }
400
  EFuncDataRequired dataRequired = FUNC_DATA_REQUIRED_FILTEROUT;
111,898✔
401
  SNode*            pFunc = NULL;
111,898✔
402
  FOREACH(pFunc, pFuncs) {
385,429!
403
    dataRequired = scanPathOptPromoteDataRequired(dataRequired, fmFuncDataRequired((SFunctionNode*)pFunc, NULL));
273,531✔
404
  }
405
  return dataRequired;
111,898✔
406
}
407

408
static void scanPathOptSetScanWin(SScanLogicNode* pScan) {
954,409✔
409
  SLogicNode* pParent = pScan->node.pParent;
954,409✔
410
  if (QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pParent) && pParent->pParent &&
954,409!
411
      QUERY_NODE_LOGIC_PLAN_WINDOW == nodeType(pParent->pParent)) {
80,521✔
412
    pParent = pParent->pParent;
15,484✔
413
  }
414
  if (QUERY_NODE_LOGIC_PLAN_WINDOW == nodeType(pParent)) {
954,409✔
415
    pScan->interval = ((SWindowLogicNode*)pParent)->interval;
36,436✔
416
    pScan->offset = ((SWindowLogicNode*)pParent)->offset;
36,436✔
417
    pScan->sliding = ((SWindowLogicNode*)pParent)->sliding;
36,436✔
418
    pScan->intervalUnit = ((SWindowLogicNode*)pParent)->intervalUnit;
36,436✔
419
    pScan->slidingUnit = ((SWindowLogicNode*)pParent)->slidingUnit;
36,436✔
420
  }
421
}
954,409✔
422

423
static void scanPathOptSetScanOrder(EScanOrder scanOrder, SScanLogicNode* pScan) {
953,384✔
424
  if (pScan->sortPrimaryKey || pScan->scanSeq[0] > 1 || pScan->scanSeq[1] > 1) {
953,384!
425
    return;
753✔
426
  }
427
  pScan->node.outputTsOrder = (SCAN_ORDER_ASC == scanOrder) ? ORDER_ASC : ORDER_DESC;
952,631✔
428
  switch (scanOrder) {
952,631!
429
    case SCAN_ORDER_ASC:
911,930✔
430
      pScan->scanSeq[0] = 1;
911,930✔
431
      pScan->scanSeq[1] = 0;
911,930✔
432
      optSetParentOrder(pScan->node.pParent, ORDER_ASC, NULL);
911,930✔
433
      break;
911,930✔
434
    case SCAN_ORDER_DESC:
40,661✔
435
      pScan->scanSeq[0] = 0;
40,661✔
436
      pScan->scanSeq[1] = 1;
40,661✔
437
      optSetParentOrder(pScan->node.pParent, ORDER_DESC, NULL);
40,661✔
438
      break;
40,661✔
439
    case SCAN_ORDER_BOTH:
40✔
440
      pScan->scanSeq[0] = 1;
40✔
441
      pScan->scanSeq[1] = 1;
40✔
442
      break;
40✔
UNCOV
443
    default:
×
UNCOV
444
      break;
×
445
  }
446
}
447

448
static void scanPathOptSetGroupOrderScan(SScanLogicNode* pScan) {
1,006,220✔
449
  if (pScan->tableType != TSDB_SUPER_TABLE) return;
1,006,220✔
450

451
  if (pScan->node.pParent && nodeType(pScan->node.pParent) == QUERY_NODE_LOGIC_PLAN_AGG) {
477,585!
452
    SAggLogicNode* pAgg = (SAggLogicNode*)pScan->node.pParent;
163,916✔
453
    bool           withSlimit = pAgg->node.pSlimit != NULL;
163,916✔
454
    if (withSlimit && (isPartTableAgg(pAgg) || isPartTagAgg(pAgg))) {
163,916!
455
      pScan->groupOrderScan = pAgg->node.forceCreateNonBlockingOptr = true;
83✔
456
    }
457
  }
458
}
459

460
static int32_t scanPathOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
3,033,960✔
461
  SOsdInfo info = {.scanOrder = SCAN_ORDER_ASC};
3,033,960✔
462
  int32_t  code = scanPathOptMatch(pCxt, pLogicSubplan->pNode, &info);
3,033,960✔
463
  if (TSDB_CODE_SUCCESS == code && info.pScan) {
3,033,958!
464
    scanPathOptSetScanWin(info.pScan);
954,416✔
465
    if (!pCxt->pPlanCxt->streamQuery) {
954,412✔
466
      scanPathOptSetScanOrder(info.scanOrder, info.pScan);
953,387✔
467
    }
468
    scanPathOptSetGroupOrderScan(info.pScan);
954,409✔
469
  }
470
  if (TSDB_CODE_SUCCESS == code && (NULL != info.pDsoFuncs || NULL != info.pSdrFuncs)) {
3,033,954!
471
    if (pCxt->pPlanCxt->streamQuery) {
112,125✔
472
      info.pScan->dataRequired = FUNC_DATA_REQUIRED_DATA_LOAD; // always load all data for stream query
227✔
473
    } else {
474
      info.pScan->dataRequired = scanPathOptGetDataRequired(info.pSdrFuncs);
111,898✔
475
    }
476

477
    info.pScan->pDynamicScanFuncs = info.pDsoFuncs;
112,125✔
478
  }
479
  if (TSDB_CODE_SUCCESS == code && info.pScan) {
3,033,954!
480
    OPTIMIZE_FLAG_SET_MASK(info.pScan->node.optimizedFlag, OPTIMIZE_FLAG_SCAN_PATH);
954,413✔
481
    pCxt->optimized = true;
954,413✔
482
  }
483
  nodesDestroyList(info.pSdrFuncs);
3,033,954✔
484
  return code;
3,033,963✔
485
}
486

487
static int32_t pdcMergeCondsToLogic(SNode** pDst, SNode** pSrc) {
29,601✔
488
  SLogicConditionNode* pLogicCond = NULL;
29,601✔
489
  int32_t code = nodesMakeNode(QUERY_NODE_LOGIC_CONDITION, (SNode**)&pLogicCond);
29,601✔
490
  if (NULL == pLogicCond) {
29,601!
491
    return code;
×
492
  }
493
  pLogicCond->node.resType.type = TSDB_DATA_TYPE_BOOL;
29,601✔
494
  pLogicCond->node.resType.bytes = tDataTypes[TSDB_DATA_TYPE_BOOL].bytes;
29,601✔
495
  pLogicCond->condType = LOGIC_COND_TYPE_AND;
29,601✔
496
  code = nodesListMakeAppend(&pLogicCond->pParameterList, *pSrc);
29,601✔
497
  if (TSDB_CODE_SUCCESS == code) {
29,601!
498
    *pSrc = NULL;
29,601✔
499
    code = nodesListMakeAppend(&pLogicCond->pParameterList, *pDst);
29,601✔
500
  }
501
  if (TSDB_CODE_SUCCESS == code) {
29,601!
502
    *pDst = (SNode*)pLogicCond;
29,601✔
503
  } else {
504
    nodesDestroyNode((SNode*)pLogicCond);
×
505
  }
506
  return code;
29,601✔
507
}
508

509
static int32_t pdcMergeConds(SNode** pCond, SNode** pAdditionalCond) {
309,634✔
510
  if (NULL == *pCond) {
309,634✔
511
    TSWAP(*pCond, *pAdditionalCond);
279,986✔
512
    return TSDB_CODE_SUCCESS;
279,986✔
513
  }
514

515
  int32_t code = TSDB_CODE_SUCCESS;
29,648✔
516
  if (QUERY_NODE_LOGIC_CONDITION == nodeType(*pCond) &&
29,648✔
517
      LOGIC_COND_TYPE_AND == ((SLogicConditionNode*)*pCond)->condType) {
49✔
518
    code = nodesListAppend(((SLogicConditionNode*)*pCond)->pParameterList, *pAdditionalCond);
47✔
519
    if (TSDB_CODE_SUCCESS == code) {
47!
520
      *pAdditionalCond = NULL;
47✔
521
    }
522
  } else {
523
    code = pdcMergeCondsToLogic(pCond, pAdditionalCond);
29,601✔
524
  }
525
  return code;
29,648✔
526
}
527

528
static int32_t pushDownCondOptCalcTimeRange(SOptimizeContext* pCxt, SScanLogicNode* pScan, SNode** pPrimaryKeyCond,
56,208✔
529
                                            SNode** pOtherCond) {
530
  int32_t code = TSDB_CODE_SUCCESS;
56,208✔
531
  if (pCxt->pPlanCxt->topicQuery || pCxt->pPlanCxt->streamQuery) {
56,208✔
532
    code = pdcMergeConds(pOtherCond, pPrimaryKeyCond);
79✔
533
  } else {
534
    bool isStrict = false;
56,129✔
535
    code = filterGetTimeRange(*pPrimaryKeyCond, &pScan->scanRange, &isStrict);
56,129✔
536
    if (TSDB_CODE_SUCCESS == code) {
56,129!
537
      if (isStrict) {
56,129✔
538
        nodesDestroyNode(*pPrimaryKeyCond);
54,969✔
539
      } else {
540
        code = pdcMergeConds(pOtherCond, pPrimaryKeyCond);
1,160✔
541
      }
542
      *pPrimaryKeyCond = NULL;
56,129✔
543
    }
544
  }
545
  return code;
56,209✔
546
}
547

548
static int32_t pushDownCondOptRebuildTbanme(SNode** pTagCond) {
57,865✔
549
  int32_t code = TSDB_CODE_SUCCESS;
57,865✔
550
  nodesRewriteExpr(pTagCond, optRebuildTbanme, &code);
57,865✔
551
  return code;
57,865✔
552
}
553

554
static int32_t pdcDealScan(SOptimizeContext* pCxt, SScanLogicNode* pScan) {
2,854,732✔
555
  if (NULL == pScan->node.pConditions ||
2,854,732✔
556
      OPTIMIZE_FLAG_TEST_MASK(pScan->node.optimizedFlag, OPTIMIZE_FLAG_PUSH_DOWN_CONDE) ||
1,216,134✔
557
      TSDB_SYSTEM_TABLE == pScan->tableType) {
430,500✔
558
    return TSDB_CODE_SUCCESS;
2,451,876✔
559
  }
560

561
  SNode*  pPrimaryKeyCond = NULL;
402,856✔
562
  SNode*  pOtherCond = NULL;
402,856✔
563
  int32_t code = filterPartitionCond(&pScan->node.pConditions, &pPrimaryKeyCond, &pScan->pTagIndexCond,
402,856✔
564
                                     &pScan->pTagCond, &pOtherCond);
565
  if (TSDB_CODE_SUCCESS == code && NULL != pScan->pTagCond) {
402,856!
566
    code = pushDownCondOptRebuildTbanme(&pScan->pTagCond);
57,865✔
567
  }
568
  if (TSDB_CODE_SUCCESS == code && NULL != pPrimaryKeyCond) {
402,856!
569
    code = pushDownCondOptCalcTimeRange(pCxt, pScan, &pPrimaryKeyCond, &pOtherCond);
56,209✔
570
  }
571
  if (TSDB_CODE_SUCCESS == code) {
402,857!
572
    pScan->node.pConditions = pOtherCond;
402,857✔
573
  }
574

575
  if (TSDB_CODE_SUCCESS == code) {
402,857!
576
    OPTIMIZE_FLAG_SET_MASK(pScan->node.optimizedFlag, OPTIMIZE_FLAG_PUSH_DOWN_CONDE);
402,857✔
577
    pCxt->optimized = true;
402,857✔
578
  } else {
579
    nodesDestroyNode(pPrimaryKeyCond);
×
580
    nodesDestroyNode(pOtherCond);
×
581
  }
582

583
  return code;
402,857✔
584
}
585

586
static bool pdcColBelongThisTable(SNode* pCondCol, SNodeList* pTableCols) {
39,811✔
587
  SNode* pTableCol = NULL;
39,811✔
588
  FOREACH(pTableCol, pTableCols) {
114,632!
589
    if (QUERY_NODE_COLUMN == nodeType(pCondCol) && QUERY_NODE_COLUMN == nodeType(pTableCol)) {
114,411!
590
      SColumnNode* pCondColNode = (SColumnNode*)pCondCol;
114,411✔
591
      SColumnNode* pTblColNode = (SColumnNode*)pTableCol;
114,411✔
592
      if (0 == strcmp(pCondColNode->tableAlias, pTblColNode->tableAlias) && 0 == strcmp(pCondColNode->colName, pTblColNode->colName)) {
114,411✔
593
        return true;
39,590✔
594
      }
595
    }
596
    
597
    if (nodesEqualNode(pCondCol, pTableCol)) {
74,821!
598
      return true;
×
599
    }
600
  }
601
  return false;
221✔
602
}
603

604
static bool pdcJoinColInTableColList(SNode* pNode, SNodeList* pTableCols) {
39,811✔
605
  if (QUERY_NODE_COLUMN != nodeType(pNode)) {
39,811!
606
    return false;
×
607
  }
608
  SColumnNode* pCol = (SColumnNode*)pNode;
39,811✔
609
  return pdcColBelongThisTable(pNode, pTableCols);
39,811✔
610
}
611

612
static bool pdcJoinColInTableList(SNode* pCondCol, SSHashObj* pTables) {
1,955,612✔
613
  SColumnNode* pTableCol = (SColumnNode*)pCondCol;
1,955,612✔
614
  if (NULL == tSimpleHashGet(pTables, pTableCol->tableAlias, strlen(pTableCol->tableAlias))) {
1,955,612✔
615
    return false;
463,624✔
616
  }
617
  return true;
1,491,988✔
618
}
619

620
static EDealRes pdcJoinIsCrossTableCond(SNode* pNode, void* pContext) {
2,529,714✔
621
  SCpdIsMultiTableCondCxt* pCxt = pContext;
2,529,714✔
622
  if (QUERY_NODE_COLUMN == nodeType(pNode)) {
2,529,714✔
623
    if (pdcJoinColInTableList(pNode, pCxt->pLeftTbls)) {
1,035,630✔
624
      pCxt->havaLeftCol = true;
573,738✔
625
    } else if (pdcJoinColInTableList(pNode, pCxt->pRightTbls)) {
461,892!
626
      pCxt->haveRightCol = true;
461,892✔
627
    }
628
    return pCxt->havaLeftCol && pCxt->haveRightCol ? DEAL_RES_END : DEAL_RES_CONTINUE;
1,035,630✔
629
  }
630
  return DEAL_RES_CONTINUE;
1,494,084✔
631
}
632

633
static ECondAction pdcJoinGetCondAction(SJoinLogicNode* pJoin, SSHashObj* pLeftTbls, SSHashObj* pRightTbls,
538,613✔
634
                                                SNode* pNode, bool whereCond) {
635
  EJoinType t = pJoin->joinType;   
538,613✔
636
  EJoinSubType s = pJoin->subType;
538,613✔
637
  SCpdIsMultiTableCondCxt cxt = {
538,613✔
638
      .pLeftTbls = pLeftTbls, .pRightTbls = pRightTbls, .havaLeftCol = false, .haveRightCol = false};
639
  nodesWalkExpr(pNode, pdcJoinIsCrossTableCond, &cxt);
538,613✔
640

641
  if (cxt.havaLeftCol) {
538,613✔
642
    if (cxt.haveRightCol) {
444,667✔
643
      if (whereCond && gJoinWhereOpt[t][s].pushDownFlag & PUSH_DOWN_ON_COND) {
341,362✔
644
        return COND_ACTION_PUSH_JOIN;
148,012✔
645
      }
646
      return COND_ACTION_STAY;
193,350✔
647
    }
648
    if ((whereCond && gJoinWhereOpt[t][s].pushDownFlag & PUSH_DOWN_LEFT_FLT) || (!whereCond && gJoinOnOpt[t][s].pushDownFlag & PUSH_DOWN_LEFT_FLT)) {
103,305✔
649
      return COND_ACTION_PUSH_LEFT_CHILD;
102,993✔
650
    }
651
    return COND_ACTION_STAY;
312✔
652
  }
653

654
  if (cxt.haveRightCol) {
93,946!
655
    if ((whereCond && gJoinWhereOpt[t][s].pushDownFlag & PUSH_DOWN_RIGHT_FLT) || (!whereCond && gJoinOnOpt[t][s].pushDownFlag & PUSH_DOWN_RIGHT_FLT)) {
93,946✔
656
      return COND_ACTION_PUSH_RIGHT_CHILD;
93,623✔
657
    }
658
    return COND_ACTION_STAY;
323✔
659
  }
660

661
  return COND_ACTION_STAY;
×
662
}
663

664
static int32_t pdcJoinSplitLogicCond(SJoinLogicNode* pJoin, SNode** pSrcCond, SNode** pOnCond, SNode** pLeftChildCond,
151,988✔
665
                                            SNode** pRightChildCond, bool whereCond) {
666
  SLogicConditionNode* pLogicCond = (SLogicConditionNode*)*pSrcCond;
151,988✔
667
  if (LOGIC_COND_TYPE_AND != pLogicCond->condType) {
151,988✔
668
    if (whereCond) {
201!
669
      return TSDB_CODE_SUCCESS;
201✔
670
    }
671
    return TSDB_CODE_PLAN_NOT_SUPPORT_JOIN_COND;
×
672
  }
673

674
  int32_t    code = TSDB_CODE_SUCCESS;
151,787✔
675
  SSHashObj* pLeftTables = NULL;
151,787✔
676
  SSHashObj* pRightTables = NULL;
151,787✔
677
  code = collectTableAliasFromNodes(nodesListGetNode(pJoin->node.pChildren, 0), &pLeftTables);
151,787✔
678
  if (TSDB_CODE_SUCCESS != code) {
151,787!
679
    return code;
×
680
  }
681
  code = collectTableAliasFromNodes(nodesListGetNode(pJoin->node.pChildren, 1), &pRightTables);
151,787✔
682
  if (TSDB_CODE_SUCCESS != code) {
151,787!
683
    tSimpleHashCleanup(pLeftTables);
×
684
    return code;
×
685
  }
686

687
  SNodeList* pOnConds = NULL;
151,787✔
688
  SNodeList* pLeftChildConds = NULL;
151,787✔
689
  SNodeList* pRightChildConds = NULL;
151,787✔
690
  SNodeList* pRemainConds = NULL;
151,787✔
691
  SNode*     pCond = NULL;
151,787✔
692
  FOREACH(pCond, pLogicCond->pParameterList) {
622,144!
693
    ECondAction condAction = pdcJoinGetCondAction(pJoin, pLeftTables, pRightTables, pCond, whereCond);
470,357✔
694
    SNode* pNew = NULL;
470,357✔
695
    code = nodesCloneNode(pCond, &pNew);
470,357✔
696
    if (TSDB_CODE_SUCCESS != code) { break; }
470,357!
697
    if (COND_ACTION_PUSH_JOIN == condAction && NULL != pOnCond) {
470,357!
698
      code = nodesListMakeAppend(&pOnConds, pNew);
142,492✔
699
    } else if (COND_ACTION_PUSH_LEFT_CHILD == condAction) {
327,865✔
700
      code = nodesListMakeAppend(&pLeftChildConds, pNew);
96,958✔
701
    } else if (COND_ACTION_PUSH_RIGHT_CHILD == condAction) {
230,907✔
702
      code = nodesListMakeAppend(&pRightChildConds, pNew);
90,761✔
703
    } else {
704
      code = nodesListMakeAppend(&pRemainConds, pNew);
140,146✔
705
    }
706
    if (TSDB_CODE_SUCCESS != code) {
470,357!
707
      break;
×
708
    }
709
  }
710

711
  tSimpleHashCleanup(pLeftTables);
151,787✔
712
  tSimpleHashCleanup(pRightTables);
151,787✔
713

714
  SNode* pTempOnCond = NULL;
151,787✔
715
  SNode* pTempLeftChildCond = NULL;
151,787✔
716
  SNode* pTempRightChildCond = NULL;
151,787✔
717
  SNode* pTempRemainCond = NULL;
151,787✔
718
  if (TSDB_CODE_SUCCESS == code) {
151,787!
719
    code = nodesMergeConds(&pTempOnCond, &pOnConds);
151,787✔
720
  }
721
  if (TSDB_CODE_SUCCESS == code) {
151,787!
722
    code = nodesMergeConds(&pTempLeftChildCond, &pLeftChildConds);
151,787✔
723
  }
724
  if (TSDB_CODE_SUCCESS == code) {
151,787!
725
    code = nodesMergeConds(&pTempRightChildCond, &pRightChildConds);
151,787✔
726
  }
727
  if (TSDB_CODE_SUCCESS == code) {
151,787!
728
    code = nodesMergeConds(&pTempRemainCond, &pRemainConds);
151,787✔
729
  }
730

731
  if (TSDB_CODE_SUCCESS == code) {
151,787!
732
    if (pOnCond) {
151,787✔
733
      *pOnCond = pTempOnCond;
92,293✔
734
    }
735
    *pLeftChildCond = pTempLeftChildCond;
151,787✔
736
    *pRightChildCond = pTempRightChildCond;
151,787✔
737
    nodesDestroyNode(*pSrcCond);
151,787✔
738
    *pSrcCond = pTempRemainCond;
151,787✔
739
  } else {
740
    nodesDestroyList(pOnConds);
×
741
    nodesDestroyList(pLeftChildConds);
×
742
    nodesDestroyList(pRightChildConds);
×
743
    nodesDestroyList(pRemainConds);
×
744
    nodesDestroyNode(pTempOnCond);
×
745
    nodesDestroyNode(pTempLeftChildCond);
×
746
    nodesDestroyNode(pTempRightChildCond);
×
747
    nodesDestroyNode(pTempRemainCond);
×
748
  }
749

750
  return code;
151,787✔
751
}
752

753
static int32_t pdcJoinSplitOpCond(SJoinLogicNode* pJoin, SNode** pSrcCond, SNode** pOnCond, SNode** pLeftChildCond,
68,256✔
754
                                         SNode** pRightChildCond, bool whereCond) {
755
  SSHashObj* pLeftTables = NULL;
68,256✔
756
  SSHashObj* pRightTables = NULL;
68,256✔
757
  int32_t code = collectTableAliasFromNodes(nodesListGetNode(pJoin->node.pChildren, 0), &pLeftTables);
68,256✔
758
  if (TSDB_CODE_SUCCESS != code) {
68,256!
759
    return code;
×
760
  }
761
  code = collectTableAliasFromNodes(nodesListGetNode(pJoin->node.pChildren, 1), &pRightTables);
68,256✔
762
  if (TSDB_CODE_SUCCESS != code) {
68,256!
763
    tSimpleHashCleanup(pLeftTables);
×
764
    return code;
×
765
  }
766
  
767
  ECondAction condAction = pdcJoinGetCondAction(pJoin, pLeftTables, pRightTables, *pSrcCond, whereCond);
68,256✔
768

769
  tSimpleHashCleanup(pLeftTables);
68,256✔
770
  tSimpleHashCleanup(pRightTables);
68,256✔
771

772
  if (COND_ACTION_STAY == condAction || (COND_ACTION_PUSH_JOIN == condAction && NULL == pOnCond)) {
68,256!
773
    return TSDB_CODE_SUCCESS;
53,839✔
774
  }
775

776
  if (COND_ACTION_PUSH_JOIN == condAction) {
14,417✔
777
    *pOnCond = *pSrcCond;
5,520✔
778
  } else if (COND_ACTION_PUSH_LEFT_CHILD == condAction) {
8,897✔
779
    *pLeftChildCond = *pSrcCond;
6,035✔
780
  } else if (COND_ACTION_PUSH_RIGHT_CHILD == condAction) {
2,862!
781
    *pRightChildCond = *pSrcCond;
2,862✔
782
  }
783
  *pSrcCond = NULL;
14,417✔
784
  return TSDB_CODE_SUCCESS;
14,417✔
785
}
786

787
static int32_t pdcJoinSplitCond(SJoinLogicNode* pJoin, SNode** pSrcCond, SNode** pOnCond, SNode** pLeftChildCond,
220,244✔
788
                                       SNode** pRightChildCond, bool whereCond) {
789
  if (QUERY_NODE_LOGIC_CONDITION == nodeType(*pSrcCond)) {
220,244✔
790
    return pdcJoinSplitLogicCond(pJoin, pSrcCond, pOnCond, pLeftChildCond, pRightChildCond, whereCond);
151,988✔
791
  } else {
792
    return pdcJoinSplitOpCond(pJoin, pSrcCond, pOnCond, pLeftChildCond, pRightChildCond, whereCond);
68,256✔
793
  }
794
}
795

796
static int32_t pdcJoinPushDownOnCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin, SNode** pCond) {
69,137✔
797
  return pdcMergeConds(&pJoin->pFullOnCond, pCond);
69,137✔
798
}
799

800
static int32_t pdcPushDownCondToChild(SOptimizeContext* pCxt, SLogicNode* pChild, SNode** pCond) {
194,005✔
801
  return pdcMergeConds(&pChild->pConditions, pCond);
194,005✔
802
}
803

804
static bool pdcJoinIsPrim(SNode* pNode, SSHashObj* pTables) {
496,854✔
805
  if (QUERY_NODE_COLUMN != nodeType(pNode) && QUERY_NODE_FUNCTION != nodeType(pNode)) {
496,854✔
806
    return false;
244✔
807
  }
808

809
  if (QUERY_NODE_FUNCTION == nodeType(pNode)) {
496,610✔
810
    SFunctionNode* pFunc = (SFunctionNode*)pNode;
2,252✔
811
    if (FUNCTION_TYPE_TIMETRUNCATE != pFunc->funcType) {
2,252✔
812
      return false;
56✔
813
    }
814
    SListCell* pCell = nodesListGetCell(pFunc->pParameterList, 0);
2,196✔
815
    if (NULL == pCell || NULL == pCell->pNode || QUERY_NODE_COLUMN != nodeType(pCell->pNode)) {
2,196!
816
      return false;
×
817
    }
818
    pNode = pCell->pNode;
2,196✔
819
  }
820

821
  SColumnNode* pCol = (SColumnNode*)pNode;
496,554✔
822
  if (PRIMARYKEY_TIMESTAMP_COL_ID != pCol->colId || TSDB_SYSTEM_TABLE == pCol->tableType) {
496,554!
823
    return false;
41,035✔
824
  }
825
  return pdcJoinColInTableList(pNode, pTables);
455,519✔
826
}
827

828
static bool pdcJoinIsPrimEqualCond(SJoinLogicNode* pJoin, SNode* pCond) {
309,813✔
829
  if (QUERY_NODE_OPERATOR != nodeType(pCond)) {
309,813✔
830
    return false;
60,321✔
831
  }
832

833
  SOperatorNode* pOper = (SOperatorNode*)pCond;
249,492✔
834
  if (OP_TYPE_EQUAL != pOper->opType) {
249,492✔
835
    if (JOIN_STYPE_ASOF != pJoin->subType) {
1,840✔
836
      return false;
1,330✔
837
    }
838
    if (OP_TYPE_GREATER_THAN != pOper->opType && OP_TYPE_GREATER_EQUAL != pOper->opType &&
510✔
839
        OP_TYPE_LOWER_THAN != pOper->opType && OP_TYPE_LOWER_EQUAL != pOper->opType) {
184!
840
      return false;
×
841
    }
842
  }
843

844
  SSHashObj* pLeftTables = NULL;
248,162✔
845
  SSHashObj* pRightTables = NULL;
248,162✔
846
  int32_t code = collectTableAliasFromNodes(nodesListGetNode(pJoin->node.pChildren, 0), &pLeftTables);
248,162✔
847
  if (TSDB_CODE_SUCCESS != code) {
248,162!
848
    return code;
×
849
  }
850
  code = collectTableAliasFromNodes(nodesListGetNode(pJoin->node.pChildren, 1), &pRightTables);
248,162✔
851
  if (TSDB_CODE_SUCCESS != code) {
248,162!
852
    tSimpleHashCleanup(pLeftTables);
×
853
    return code;
×
854
  }
855

856
  bool res = false;
248,162✔
857
  if (pdcJoinIsPrim(pOper->pLeft, pLeftTables)) {
248,162✔
858
    res = pdcJoinIsPrim(pOper->pRight, pRightTables);
226,989✔
859
  } else if (pdcJoinIsPrim(pOper->pLeft, pRightTables)) {
21,173✔
860
    res = pdcJoinIsPrim(pOper->pRight, pLeftTables);
530✔
861
  }
862

863
  tSimpleHashCleanup(pLeftTables);
248,162✔
864
  tSimpleHashCleanup(pRightTables);
248,162✔
865

866
  return res;
248,162✔
867
}
868

869
static bool pdcJoinHasPrimEqualCond(SJoinLogicNode* pJoin, SNode* pCond, bool* errCond) {
180,915✔
870
  if (QUERY_NODE_LOGIC_CONDITION == nodeType(pCond)) {
180,915✔
871
    SLogicConditionNode* pLogicCond = (SLogicConditionNode*)pCond;
65,052✔
872
    if (LOGIC_COND_TYPE_AND != pLogicCond->condType) {
65,052✔
873
      if (errCond) {
252✔
874
        *errCond = true;
124✔
875
      }
876
      return false;
252✔
877
    }
878
    bool   hasPrimaryKeyEqualCond = false;
64,800✔
879
    SNode* pCond = NULL;
64,800✔
880
    FOREACH(pCond, pLogicCond->pParameterList) {
66,351!
881
      if (pdcJoinHasPrimEqualCond(pJoin, pCond, NULL)) {
66,261✔
882
        hasPrimaryKeyEqualCond = true;
64,710✔
883
        break;
64,710✔
884
      }
885
    }
886
    return hasPrimaryKeyEqualCond;
64,800✔
887
  } else {
888
    return pdcJoinIsPrimEqualCond(pJoin, pCond);
115,863✔
889
  }
890
}
891

892
static int32_t pdcJoinSplitPrimInLogicCond(SJoinLogicNode* pJoin, SNode** ppPrimEqCond, SNode** ppOnCond) {
59,515✔
893
  SLogicConditionNode* pLogicCond = (SLogicConditionNode*)(pJoin->pFullOnCond);
59,515✔
894

895
  int32_t    code = TSDB_CODE_SUCCESS;
59,515✔
896
  SNodeList* pOnConds = NULL;
59,515✔
897
  SNode*     pCond = NULL;
59,515✔
898
  WHERE_EACH(pCond, pLogicCond->pParameterList) {
199,345!
899
    SNode* pNew = NULL;
139,830✔
900
    code = nodesCloneNode(pCond, &pNew);
139,830✔
901
    if (TSDB_CODE_SUCCESS != code) break;
139,830!
902
    if (pdcJoinIsPrimEqualCond(pJoin, pCond) && (NULL == *ppPrimEqCond)) {
139,830✔
903
      *ppPrimEqCond = pNew;
59,515✔
904
      ERASE_NODE(pLogicCond->pParameterList);
59,515✔
905
    } else {
906
      code = nodesListMakeAppend(&pOnConds, pNew);
80,315✔
907
      if (TSDB_CODE_SUCCESS != code) break;
80,315!
908
      WHERE_NEXT;
80,315✔
909
    }
910
  }
911

912
  SNode* pTempOnCond = NULL;
59,515✔
913
  if (TSDB_CODE_SUCCESS == code) {
59,515!
914
    code = nodesMergeConds(&pTempOnCond, &pOnConds);
59,515✔
915
  }
916

917
  if (TSDB_CODE_SUCCESS == code) {
59,515!
918
    if (NULL != *ppPrimEqCond) {
59,515!
919
      *ppOnCond = pTempOnCond;
59,515✔
920
      nodesDestroyNode(pJoin->pFullOnCond);
59,515✔
921
      pJoin->pFullOnCond = NULL;
59,515✔
922
      return TSDB_CODE_SUCCESS;
59,515✔
923
    }
924
    planError("no primary key equal cond found, condListNum:%d", pLogicCond->pParameterList->length);
×
925
    return TSDB_CODE_PLAN_INTERNAL_ERROR;
×
926
  } else {
927
    nodesDestroyList(pOnConds);
×
928
    nodesDestroyNode(pTempOnCond);
×
929
    return code;
×
930
  }
931
}
932

933
static int32_t pdcJoinSplitPrimEqCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) {
113,635✔
934
  int32_t code = TSDB_CODE_SUCCESS;
113,635✔
935
  SNode*  pPrimKeyEqCond = NULL;
113,635✔
936
  SNode*  pJoinOnCond = NULL;
113,635✔
937

938
  if (QUERY_NODE_LOGIC_CONDITION == nodeType(pJoin->pFullOnCond) &&
113,635✔
939
      LOGIC_COND_TYPE_AND == ((SLogicConditionNode*)(pJoin->pFullOnCond))->condType) {
59,515!
940
    code = pdcJoinSplitPrimInLogicCond(pJoin, &pPrimKeyEqCond, &pJoinOnCond);
59,515✔
941
  } else if (pdcJoinIsPrimEqualCond(pJoin, pJoin->pFullOnCond)) {
54,120!
942
    pPrimKeyEqCond = pJoin->pFullOnCond;
54,120✔
943
    pJoinOnCond = NULL;
54,120✔
944
  } else {
945
    return TSDB_CODE_SUCCESS;
×
946
  }
947

948
  if (TSDB_CODE_SUCCESS == code) {
113,635!
949
    pJoin->pPrimKeyEqCond = pPrimKeyEqCond;
113,635✔
950
    pJoin->pFullOnCond = pJoinOnCond;
113,635✔
951
  } else {
952
    nodesDestroyNode(pPrimKeyEqCond);
×
953
    nodesDestroyNode(pJoinOnCond);
×
954
  }
955
  return code;
113,635✔
956
}
957

958
static int32_t pdcJoinIsEqualOnCond(SJoinLogicNode* pJoin, SNode* pCond, bool* allTags, bool* pRes) {
80,810✔
959
  *pRes = false;
80,810✔
960
  int32_t code = 0;
80,810✔
961
  if (QUERY_NODE_OPERATOR != nodeType(pCond)) {
80,810✔
962
    return code;
60,321✔
963
  }
964
  SOperatorNode* pOper = (SOperatorNode*)pCond;
20,489✔
965
  if ((QUERY_NODE_COLUMN != nodeType(pOper->pLeft) && !(QUERY_NODE_OPERATOR == nodeType(pOper->pLeft) && OP_TYPE_JSON_GET_VALUE ==((SOperatorNode*)pOper->pLeft)->opType)) 
20,489✔
966
      || NULL == pOper->pRight || 
20,390✔
967
      (QUERY_NODE_COLUMN != nodeType(pOper->pRight) && !(QUERY_NODE_OPERATOR == nodeType(pOper->pRight) && OP_TYPE_JSON_GET_VALUE ==((SOperatorNode*)pOper->pRight)->opType))) {
20,340✔
968
    return code;
394✔
969
  }
970
  
971
  if (OP_TYPE_EQUAL != pOper->opType) {
20,095✔
972
    return code;
180✔
973
  }
974

975
  if ((QUERY_NODE_OPERATOR == nodeType(pOper->pLeft) || QUERY_NODE_OPERATOR == nodeType(pOper->pRight)) &&
19,915!
976
      !(IS_ASOF_JOIN(pJoin->subType) || IS_WINDOW_JOIN(pJoin->subType))) {
32✔
977
    return code;
24✔
978
  }
979
  
980
  SColumnNode* pLeft = (SColumnNode*)(pOper->pLeft);
19,891✔
981
  SColumnNode* pRight = (SColumnNode*)(pOper->pRight);
19,891✔
982

983
  if (QUERY_NODE_OPERATOR == nodeType(pOper->pLeft)) {
19,891✔
984
    pLeft = (SColumnNode*)((SOperatorNode*)pOper->pLeft)->pLeft;
8✔
985
  }
986

987
  if (QUERY_NODE_OPERATOR == nodeType(pOper->pRight)) {
19,891✔
988
    pRight = (SColumnNode*)((SOperatorNode*)pOper->pRight)->pLeft;
8✔
989
  }
990
  
991
  *allTags = (COLUMN_TYPE_TAG == pLeft->colType) && (COLUMN_TYPE_TAG == pRight->colType);
19,891!
992

993
  if (pLeft->node.resType.type != pRight->node.resType.type ||
19,891✔
994
      pLeft->node.resType.bytes != pRight->node.resType.bytes) {
19,801!
995
    return code;
90✔
996
  }
997
  SNodeList* pLeftCols = ((SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 0))->pTargets;
19,801✔
998
  SNodeList* pRightCols = ((SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 1))->pTargets;
19,801✔
999
  bool isEqual = false;
19,801✔
1000
  if (pdcJoinColInTableColList((SNode*)pLeft, pLeftCols)) {
19,801✔
1001
    isEqual = pdcJoinColInTableColList((SNode*)pRight, pRightCols);
19,588✔
1002
    if (isEqual) {
19,588✔
1003
      SNode* pNewLeft = NULL;
19,584✔
1004
      code = nodesCloneNode(pOper->pLeft, &pNewLeft);
19,584✔
1005
      if (TSDB_CODE_SUCCESS != code) return code;
19,584!
1006
      SNode* pNewRight = NULL;
19,584✔
1007
      code = nodesCloneNode(pOper->pRight, &pNewRight);
19,584✔
1008
      if (TSDB_CODE_SUCCESS != code) {
19,584!
1009
        nodesDestroyNode(pNewLeft);
×
1010
        return code;
×
1011
      }
1012
      code = nodesListMakeStrictAppend(&pJoin->pLeftEqNodes, pNewLeft);
19,584✔
1013
      if (TSDB_CODE_SUCCESS != code) {
19,584!
1014
        nodesDestroyNode(pNewRight);
×
1015
        return code;
×
1016
      }
1017
      code = nodesListMakeStrictAppend(&pJoin->pRightEqNodes, pNewRight);
19,584✔
1018
    }
1019
  } else if (pdcJoinColInTableColList((SNode*)pLeft, pRightCols)) {
213✔
1020
    isEqual = pdcJoinColInTableColList((SNode*)pRight, pLeftCols);
209✔
1021
    if (isEqual) {
209!
1022
      SNode* pNewLeft = NULL;
209✔
1023
      code = nodesCloneNode(pOper->pLeft, &pNewLeft);
209✔
1024
      if (TSDB_CODE_SUCCESS != code) return code;
209!
1025
      SNode* pNewRight = NULL;
209✔
1026
      code = nodesCloneNode(pOper->pRight, &pNewRight);
209✔
1027
      if (TSDB_CODE_SUCCESS != code) {
209!
1028
        nodesDestroyNode(pNewLeft);
×
1029
        return code;
×
1030
      }
1031
      code = nodesListMakeStrictAppend(&pJoin->pLeftEqNodes, pNewRight);
209✔
1032
      if (TSDB_CODE_SUCCESS != code) {
209!
1033
        nodesDestroyNode(pNewLeft);
×
1034
        return code;
×
1035
      }
1036
      code = nodesListMakeStrictAppend(&pJoin->pRightEqNodes, pNewLeft);
209✔
1037
    }
1038
  }
1039
  if (TSDB_CODE_SUCCESS == code) {
19,801!
1040
    *pRes = isEqual;
19,801✔
1041
  }
1042
  return code;
19,801✔
1043
}
1044

1045
static int32_t pdcJoinPartLogicEqualOnCond(SJoinLogicNode* pJoin) {
19,091✔
1046
  SLogicConditionNode* pLogicCond = (SLogicConditionNode*)(pJoin->pFullOnCond);
19,091✔
1047

1048
  int32_t    code = TSDB_CODE_SUCCESS;
19,091✔
1049
  SNodeList* pColEqOnConds = NULL;
19,091✔
1050
  SNodeList* pTagEqOnConds = NULL;
19,091✔
1051
  SNodeList* pTagOnConds = NULL;
19,091✔
1052
  SNodeList* pColOnConds = NULL;
19,091✔
1053
  SNode*     pCond = NULL;
19,091✔
1054
  bool       allTags = false;
19,091✔
1055
  FOREACH(pCond, pLogicCond->pParameterList) {
59,036!
1056
    allTags = false;
39,945✔
1057
    bool   eqOnCond = false;
39,945✔
1058
    SNode* pNew = NULL;
39,945✔
1059
    code = pdcJoinIsEqualOnCond(pJoin, pCond, &allTags, &eqOnCond);
39,945✔
1060
    if (TSDB_CODE_SUCCESS != code) break;
39,945!
1061
    code = nodesCloneNode(pCond, &pNew);
39,945✔
1062
    if (TSDB_CODE_SUCCESS != code) break;
39,945!
1063

1064
    if (eqOnCond) {
39,945✔
1065
      if (allTags) {
17,070✔
1066
        code = nodesListMakeStrictAppend(&pTagEqOnConds, pNew);
16,971✔
1067
      } else {
1068
        code = nodesListMakeStrictAppend(&pColEqOnConds, pNew);
99✔
1069
        pJoin->allEqTags = false;  
99✔
1070
      }
1071
    } else if (allTags) {
22,875!
1072
      code = nodesListMakeStrictAppend(&pTagOnConds, pNew);
×
1073
    } else {
1074
      code = nodesListMakeStrictAppend(&pColOnConds, pNew);
22,875✔
1075
      pJoin->allEqTags = false;  
22,875✔
1076
    }
1077
    
1078
    if (code) {
39,945!
1079
      break;
×
1080
    }
1081
  }
1082

1083
  SNode* pTempTagEqCond = NULL;
19,091✔
1084
  SNode* pTempColEqCond = NULL;
19,091✔
1085
  SNode* pTempTagOnCond = NULL;
19,091✔
1086
  SNode* pTempColOnCond = NULL;
19,091✔
1087
  if (TSDB_CODE_SUCCESS == code) {
19,091!
1088
    code = nodesMergeConds(&pTempColEqCond, &pColEqOnConds);
19,091✔
1089
  }
1090
  if (TSDB_CODE_SUCCESS == code) {
19,091!
1091
    code = nodesMergeConds(&pTempTagEqCond, &pTagEqOnConds);
19,091✔
1092
  }
1093
  if (TSDB_CODE_SUCCESS == code) {
19,091!
1094
    code = nodesMergeConds(&pTempTagOnCond, &pTagOnConds);
19,091✔
1095
  }
1096
  if (TSDB_CODE_SUCCESS == code) {
19,091!
1097
    code = nodesMergeConds(&pTempColOnCond, &pColOnConds);
19,091✔
1098
  }
1099

1100
  if (TSDB_CODE_SUCCESS == code) {
19,091!
1101
    pJoin->pColEqCond = pTempColEqCond;
19,091✔
1102
    pJoin->pColOnCond = pTempColOnCond;
19,091✔
1103
    pJoin->pTagEqCond = pTempTagEqCond;
19,091✔
1104
    pJoin->pTagOnCond = pTempTagOnCond;
19,091✔
1105
  } else {
1106
    nodesDestroyList(pColEqOnConds);
×
1107
    nodesDestroyList(pTagEqOnConds);
×
1108
    nodesDestroyList(pColOnConds);
×
1109
    nodesDestroyList(pTagOnConds);
×
1110
    nodesDestroyNode(pTempTagEqCond);
×
1111
    nodesDestroyNode(pTempColEqCond);
×
1112
    nodesDestroyNode(pTempTagOnCond);
×
1113
    nodesDestroyNode(pTempColOnCond);
×
1114
  }
1115
  
1116
  return code;
19,091✔
1117
}
1118

1119
static int32_t pdcJoinPartEqualOnCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) {
114,792✔
1120
  if (NULL == pJoin->pFullOnCond) {
114,792✔
1121
    pJoin->pColEqCond = NULL;
54,836✔
1122
    pJoin->pTagEqCond = NULL;
54,836✔
1123
    return TSDB_CODE_SUCCESS;
54,836✔
1124
  }
1125

1126
  pJoin->allEqTags = true;  
59,956✔
1127

1128
  if (QUERY_NODE_LOGIC_CONDITION == nodeType(pJoin->pFullOnCond) &&
59,956✔
1129
      LOGIC_COND_TYPE_AND == ((SLogicConditionNode*)(pJoin->pFullOnCond))->condType) {
56,791✔
1130
    return pdcJoinPartLogicEqualOnCond(pJoin);
19,091✔
1131
  }
1132

1133
  bool allTags = false;
40,865✔
1134
  bool eqOnCond = false;
40,865✔
1135
  int32_t code = pdcJoinIsEqualOnCond(pJoin, pJoin->pFullOnCond, &allTags, &eqOnCond);
40,865✔
1136
  if (TSDB_CODE_SUCCESS != code) {
40,865!
1137
    return code;
×
1138
  }
1139
  SNode* pNew = NULL;
40,865✔
1140
  code = nodesCloneNode(pJoin->pFullOnCond, &pNew);
40,865✔
1141
  if (TSDB_CODE_SUCCESS != code) {
40,865!
1142
    return code;
×
1143
  }
1144
  if (eqOnCond) {
40,865✔
1145
    if (allTags) {
2,723✔
1146
      pJoin->pTagEqCond = pNew;
2,466✔
1147
    } else {
1148
      pJoin->pColEqCond = pNew;
257✔
1149
      pJoin->allEqTags = false;  
257✔
1150
    }
1151
  } else if (allTags) {
38,142✔
1152
    pJoin->pTagOnCond = pNew;
12✔
1153
  } else {
1154
    pJoin->pColOnCond = pNew;
38,130✔
1155
    pJoin->allEqTags = false;  
38,130✔
1156
  }
1157

1158
  return TSDB_CODE_SUCCESS;
40,865✔
1159
}
1160

1161
static EDealRes pdcJoinCollectCondCol(SNode* pNode, void* pContext) {
1,044✔
1162
  SCpdCollectTableColCxt* pCxt = pContext;
1,044✔
1163
  if (QUERY_NODE_COLUMN == nodeType(pNode)) {
1,044✔
1164
    if (pdcJoinColInTableList(pNode, pCxt->pTables)) {
696✔
1165
      SColumnNode* pCol = (SColumnNode*)pNode;
224✔
1166
      char    name[TSDB_TABLE_NAME_LEN + TSDB_COL_NAME_LEN];
1167
      int32_t len = 0;
224✔
1168
      if ('\0' == pCol->tableAlias[0]) {
224!
1169
        len = tsnprintf(name, sizeof(name), "%s", pCol->colName);
×
1170
      } else {
1171
        len = tsnprintf(name, sizeof(name), "%s.%s", pCol->tableAlias, pCol->colName);
224✔
1172
      }
1173
      if (NULL == taosHashGet(pCxt->pColHash, name, len)) {
224!
1174
        pCxt->errCode = taosHashPut(pCxt->pColHash, name, len, NULL, 0);
224✔
1175
        if (TSDB_CODE_SUCCESS == pCxt->errCode) {
224!
1176
          SNode* pNew = NULL;
224✔
1177
          pCxt->errCode = nodesCloneNode(pNode, &pNew);
224✔
1178
          if (TSDB_CODE_SUCCESS == pCxt->errCode) {
224!
1179
            pCxt->errCode = nodesListStrictAppend(pCxt->pResCols, pNew);
224✔
1180
          }
1181
        }
1182
      }
1183
    }
1184
  }
1185
  
1186
  return (TSDB_CODE_SUCCESS == pCxt->errCode ? DEAL_RES_CONTINUE : DEAL_RES_ERROR);
1,044!
1187
}
1188

1189
static int32_t pdcJoinCollectColsFromParent(SJoinLogicNode* pJoin, SSHashObj* pTables, SNodeList* pCondCols) {
233✔
1190
  SCpdCollectTableColCxt cxt = {
466✔
1191
    .errCode = TSDB_CODE_SUCCESS,
1192
    .pTables = pTables, 
1193
    .pResCols = pCondCols, 
1194
    .pColHash = taosHashInit(128, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK)
233✔
1195
  };
1196
  if (NULL == cxt.pColHash) {
233!
1197
    return terrno;
×
1198
  }
1199
  
1200
  nodesWalkExpr(pJoin->pPrimKeyEqCond, pdcJoinCollectCondCol, &cxt);
233✔
1201
  nodesWalkExpr(pJoin->node.pConditions, pdcJoinCollectCondCol, &cxt);
233✔
1202
  if (TSDB_CODE_SUCCESS == cxt.errCode) {
233!
1203
    nodesWalkExpr(pJoin->pFullOnCond, pdcJoinCollectCondCol, &cxt);
233✔
1204
  }
1205
  
1206
  taosHashCleanup(cxt.pColHash);
233✔
1207
  return cxt.errCode;
233✔
1208
}
1209

1210
static int32_t pdcJoinAddParentOnColsToTarget(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) {
114,755✔
1211
  if (NULL == pJoin->node.pParent || QUERY_NODE_LOGIC_PLAN_JOIN != nodeType(pJoin->node.pParent)) {
114,755!
1212
    return TSDB_CODE_SUCCESS;
114,678✔
1213
  }
1214

1215
  SNodeList* pTargets = NULL;
77✔
1216
  int32_t code = TSDB_CODE_SUCCESS;
77✔
1217
  SNodeList* pCondCols = NULL;
77✔
1218
  code = nodesMakeList(&pCondCols);
77✔
1219
  if (NULL == pCondCols) {
77!
1220
    return code;
×
1221
  }
1222

1223
  SSHashObj* pTables = NULL;
77✔
1224
  code = collectTableAliasFromNodes(nodesListGetNode(pJoin->node.pChildren, 0), &pTables);
77✔
1225
  if (TSDB_CODE_SUCCESS != code) {
77!
1226
    return code;
×
1227
  }
1228
  code = collectTableAliasFromNodes(nodesListGetNode(pJoin->node.pChildren, 1), &pTables);
77✔
1229
  if (TSDB_CODE_SUCCESS != code) {
77!
1230
    tSimpleHashCleanup(pTables);
×
1231
    return code;
×
1232
  }
1233
  
1234
  SJoinLogicNode* pTmp = (SJoinLogicNode*)pJoin->node.pParent;
77✔
1235
  do {
1236
    code = pdcJoinCollectColsFromParent(pTmp, pTables, pCondCols);
233✔
1237
    if (TSDB_CODE_SUCCESS != code) {
233!
1238
      break;
×
1239
    }
1240
    if (NULL == pTmp->node.pParent || QUERY_NODE_LOGIC_PLAN_JOIN != nodeType(pTmp->node.pParent)) {
233!
1241
      break;
1242
    }
1243
    pTmp = (SJoinLogicNode*)pTmp->node.pParent;
156✔
1244
  } while (true);
1245

1246
  tSimpleHashCleanup(pTables);
77✔
1247
  
1248
  if (TSDB_CODE_SUCCESS == code) {
77!
1249
    code = createColumnByRewriteExprs(pCondCols, &pTargets);
77✔
1250
  }
1251
  
1252
  nodesDestroyList(pCondCols);
77✔
1253
  
1254
  if (TSDB_CODE_SUCCESS == code) {
77!
1255
    SNode* pNode = NULL;
77✔
1256
    FOREACH(pNode, pTargets) {
301!
1257
      SNode* pTmp = NULL;
224✔
1258
      bool found = false;
224✔
1259
      FOREACH(pTmp, pJoin->node.pTargets) {
2,664!
1260
        if (nodesEqualNode(pTmp, pNode)) {
2,635✔
1261
          found = true;
195✔
1262
          break;
195✔
1263
        }
1264
      }
1265
      if (!found) {
224✔
1266
        SNode* pNew = NULL;
29✔
1267
        code = nodesCloneNode(pNode, &pNew);
29✔
1268
        if (TSDB_CODE_SUCCESS == code) {
29!
1269
          code = nodesListStrictAppend(pJoin->node.pTargets, pNew);
29✔
1270
        }
1271
        if (TSDB_CODE_SUCCESS != code) {
29!
1272
          break;
×
1273
        }
1274
      }
1275
    }
1276
  }    
1277

1278
  nodesDestroyList(pTargets);
77✔
1279

1280
  return code;
77✔
1281
}
1282

1283

1284
static int32_t pdcJoinAddPreFilterColsToTarget(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) {
×
1285
  if (NULL == pJoin->pFullOnCond) {
×
1286
    return TSDB_CODE_SUCCESS;
×
1287
  }
1288

1289
  int32_t code = TSDB_CODE_SUCCESS;
×
1290
  SNodeList* pCondCols = NULL;
×
1291
  code = nodesMakeList(&pCondCols);
×
1292
  SNodeList* pTargets = NULL;
×
1293
  if (NULL == pCondCols) {
×
1294
    code = code;
×
1295
  } else {
1296
    code = nodesCollectColumnsFromNode(pJoin->pColOnCond, NULL, COLLECT_COL_TYPE_ALL, &pCondCols);
×
1297
  }
1298
  if (TSDB_CODE_SUCCESS == code) {
×
1299
    code = nodesCollectColumnsFromNode(pJoin->pTagOnCond, NULL, COLLECT_COL_TYPE_ALL, &pCondCols);
×
1300
  }
1301
  if (TSDB_CODE_SUCCESS == code) {
×
1302
    code = createColumnByRewriteExprs(pCondCols, &pTargets);
×
1303
  }
1304

1305
  nodesDestroyList(pCondCols);
×
1306

1307
  if (TSDB_CODE_SUCCESS == code) {
×
1308
    SNode* pNode = NULL;
×
1309
    FOREACH(pNode, pTargets) {
×
1310
      SNode* pTmp = NULL;
×
1311
      bool   found = false;
×
1312
      FOREACH(pTmp, pJoin->node.pTargets) {
×
1313
        if (nodesEqualNode(pTmp, pNode)) {
×
1314
          found = true;
×
1315
          break;
×
1316
        }
1317
      }
1318
      if (!found) {
×
1319
        SNode* pNew = NULL;
×
1320
        code = nodesCloneNode(pNode, &pNew);
×
1321
        if (TSDB_CODE_SUCCESS == code) {
×
1322
          code = nodesListStrictAppend(pJoin->node.pTargets, pNew);
×
1323
        }
1324
        if (TSDB_CODE_SUCCESS != code) {
×
1325
          break;
×
1326
        }
1327
      }
1328
    }
1329
  }
1330

1331
  nodesDestroyList(pTargets);
×
1332

1333
  return code;
×
1334
}
1335

1336
static int32_t pdcJoinAddFilterColsToTarget(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) {
114,755✔
1337
  if (NULL == pJoin->node.pConditions && NULL == pJoin->pFullOnCond) {
114,755✔
1338
    return TSDB_CODE_SUCCESS;
54,679✔
1339
  }
1340

1341
  int32_t code = TSDB_CODE_SUCCESS;
60,076✔
1342
  SNodeList* pCondCols = NULL;
60,076✔
1343
  code = nodesMakeList(&pCondCols);
60,076✔
1344
  SNodeList* pTargets = NULL;
60,076✔
1345
  if (NULL == pCondCols) {
60,076!
1346
    return code;
×
1347
  }
1348

1349
  if (NULL != pJoin->node.pConditions) {
60,076✔
1350
    code = nodesCollectColumnsFromNode(pJoin->node.pConditions, NULL, COLLECT_COL_TYPE_ALL, &pCondCols);
761✔
1351
  }
1352
  if (TSDB_CODE_SUCCESS == code && NULL != pJoin->pFullOnCond) {
60,076!
1353
    code = nodesCollectColumnsFromNode(pJoin->pFullOnCond, NULL, COLLECT_COL_TYPE_ALL, &pCondCols);
59,394✔
1354
  }
1355
  if (TSDB_CODE_SUCCESS == code) {
60,076!
1356
    code = createColumnByRewriteExprs(pCondCols, &pTargets);
60,076✔
1357
  }
1358
  
1359
  nodesDestroyList(pCondCols);
60,076✔
1360
  
1361
  if (TSDB_CODE_SUCCESS == code) {
60,076!
1362
    SNode* pNode = NULL;
60,076✔
1363
    FOREACH(pNode, pTargets) {
218,406!
1364
      SNode* pTmp = NULL;
158,330✔
1365
      bool found = false;
158,330✔
1366
      FOREACH(pTmp, pJoin->node.pTargets) {
792,389!
1367
        if (nodesEqualNode(pTmp, pNode)) {
639,225✔
1368
          found = true;
5,166✔
1369
          break;
5,166✔
1370
        }
1371
      }
1372
      if (!found) {
158,330✔
1373
        SNode* pNew = NULL;
153,164✔
1374
        code = nodesCloneNode(pNode, &pNew);
153,164✔
1375
        if (TSDB_CODE_SUCCESS == code) {
153,164!
1376
          code = nodesListStrictAppend(pJoin->node.pTargets, pNew);
153,164✔
1377
        }
1378
        if (TSDB_CODE_SUCCESS != code) {
153,164!
1379
          break;
×
1380
        }
1381
      }
1382
    }
1383
  }    
1384

1385
  nodesDestroyList(pTargets);
60,076✔
1386

1387
  return code;
60,076✔
1388
}
1389

1390

1391
static int32_t pdcJoinCheckAllCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) {
115,651✔
1392
  if (NULL == pJoin->pFullOnCond) {
115,651✔
1393
    if (IS_WINDOW_JOIN(pJoin->subType) || IS_ASOF_JOIN(pJoin->subType)) {
70,005✔
1394
      return TSDB_CODE_SUCCESS;
716✔
1395
    }
1396

1397
    if (NULL == pJoin->node.pConditions) {      
69,289✔
1398
      return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_NOT_SUPPORT_CROSS_JOIN);
43✔
1399
    }
1400
    
1401
    if (!IS_INNER_NONE_JOIN(pJoin->joinType, pJoin->subType)) {
69,246!
1402
      return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_NOT_SUPPORT_CROSS_JOIN);
266✔
1403
    }
1404
  }
1405

1406
  SNode* pCond = pJoin->pFullOnCond ? pJoin->pFullOnCond : pJoin->node.pConditions;
114,626✔
1407
  bool errCond = false;
114,626✔
1408
  if (!pdcJoinHasPrimEqualCond(pJoin, pCond, &errCond)) {
114,626✔
1409
    if (errCond && !(IS_INNER_NONE_JOIN(pJoin->joinType, pJoin->subType) && NULL != pJoin->pFullOnCond && NULL != pJoin->node.pConditions)) {
955!
1410
      return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_NOT_SUPPORT_JOIN_COND);
118✔
1411
    }
1412
    
1413
    if (IS_INNER_NONE_JOIN(pJoin->joinType, pJoin->subType) && NULL != pJoin->pFullOnCond && NULL != pJoin->node.pConditions) {
837!
1414
      if (pdcJoinHasPrimEqualCond(pJoin, pJoin->node.pConditions, &errCond)) {
28✔
1415
        return TSDB_CODE_SUCCESS;
20✔
1416
      }
1417
      if (errCond) {
8✔
1418
        return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_NOT_SUPPORT_JOIN_COND);
4✔
1419
      }
1420
    }
1421
    
1422
    if (IS_WINDOW_JOIN(pJoin->subType) || IS_ASOF_JOIN(pJoin->subType)) {
813✔
1423
      return TSDB_CODE_SUCCESS;
441✔
1424
    }
1425
    
1426
    return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_EXPECTED_TS_EQUAL);
372✔
1427
  }
1428

1429
  if (IS_ASOF_JOIN(pJoin->subType)) {
113,671✔
1430
    nodesDestroyNode(pJoin->addPrimEqCond);
505✔
1431
    pJoin->addPrimEqCond = NULL;
505✔
1432
  } 
1433

1434
  if (IS_WINDOW_JOIN(pJoin->subType)) {
113,671✔
1435
    return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_NOT_SUPPORT_JOIN_COND);
56✔
1436
  } 
1437

1438
  return TSDB_CODE_SUCCESS;
113,615✔
1439
}
1440

1441
static int32_t pdcJoinHandleGrpJoinCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) {
114,792✔
1442
  switch (pJoin->subType) {
114,792✔
1443
    case JOIN_STYPE_ASOF:
1,662✔
1444
    case JOIN_STYPE_WIN:
1445
      if (NULL != pJoin->pColOnCond || NULL != pJoin->pTagOnCond) {
1,662!
1446
        return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_NOT_SUPPORT_JOIN_COND);
23✔
1447
      }
1448
      nodesDestroyNode(pJoin->pColEqCond);
1,639✔
1449
      pJoin->pColEqCond = NULL;
1,639✔
1450
      nodesDestroyNode(pJoin->pTagEqCond);
1,639✔
1451
      pJoin->pTagEqCond = NULL;
1,639✔
1452
      nodesDestroyNode(pJoin->pFullOnCond);
1,639✔
1453
      pJoin->pFullOnCond = NULL;
1,639✔
1454
      if (!pJoin->allEqTags) {
1,639✔
1455
        SNode* pNode = NULL;
1,387✔
1456
        FOREACH(pNode, pJoin->pLeftEqNodes) {
1,730✔
1457
          SColumnNode* pCol = (SColumnNode*)pNode;
357✔
1458
          if (COLUMN_TYPE_TAG != pCol->colType && PRIMARYKEY_TIMESTAMP_COL_ID == pCol->colId) {
357✔
1459
            return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_NOT_SUPPORT_JOIN_COND);
14✔
1460
          }
1461
        }
1462
        FOREACH(pNode, pJoin->pRightEqNodes) {
1,716✔
1463
          SColumnNode* pCol = (SColumnNode*)pNode;
343✔
1464
          if (COLUMN_TYPE_TAG != pCol->colType && PRIMARYKEY_TIMESTAMP_COL_ID == pCol->colId) {
343!
1465
            return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_NOT_SUPPORT_JOIN_COND);
×
1466
          }
1467
        }
1468
      }
1469
      break;
1,625✔
1470
    default:
113,130✔
1471
      break;
113,130✔
1472
  }
1473

1474
  return TSDB_CODE_SUCCESS;
114,755✔
1475
}
1476

1477
static EDealRes pdcCheckTableCondType(SNode* pNode, void* pContext) {
1,916✔
1478
  SCpdIsMultiTableCondCxt* pCxt = pContext;
1,916✔
1479
  switch (nodeType(pNode)) {
1,916✔
1480
    case QUERY_NODE_COLUMN: {
1,063✔
1481
      if (pdcJoinColInTableList(pNode, pCxt->pLeftTbls)) {
1,063✔
1482
        pCxt->havaLeftCol = true;
527✔
1483
      } else if (pdcJoinColInTableList(pNode, pCxt->pRightTbls)) {
536!
1484
        pCxt->haveRightCol = true;
536✔
1485
      }
1486
      
1487
      break;
1,063✔
1488
    }
1489
    case QUERY_NODE_OPERATOR: {
690✔
1490
      SOperatorNode* pOp = (SOperatorNode*)pNode;
690✔
1491
      if (OP_TYPE_IS_NULL == pOp->opType) {
690✔
1492
        pCxt->condIsNull = true;
90✔
1493
      }
1494
      break;
690✔
1495
    }
1496
    default:
163✔
1497
      break;
163✔
1498
  }
1499
  
1500
  return DEAL_RES_CONTINUE;
1,916✔
1501
}
1502

1503
static int32_t pdcJoinGetOpTableCondTypes(SNode* pCond, SSHashObj* pLeftTables, SSHashObj* pRightTables, bool* tableCondTypes) {
631✔
1504
  SCpdIsMultiTableCondCxt cxt = {
631✔
1505
      .pLeftTbls = pLeftTables, .pRightTbls = pRightTables, .havaLeftCol = false, .haveRightCol = false, .condIsNull = false};
1506
  nodesWalkExpr(pCond, pdcCheckTableCondType, &cxt);
631✔
1507

1508
  if (cxt.havaLeftCol) {
631✔
1509
    if (cxt.haveRightCol) {
527✔
1510
      if (cxt.condIsNull) {
432✔
1511
        tableCondTypes[1] = true;
17✔
1512
        tableCondTypes[3] = true;
17✔
1513
      } else {
1514
        tableCondTypes[0] = true;
415✔
1515
        tableCondTypes[2] = true;
415✔
1516
      }      
1517
      return TSDB_CODE_SUCCESS;
432✔
1518
    }
1519

1520
    if (cxt.condIsNull) {
95✔
1521
      tableCondTypes[1] = true;
42✔
1522
    } else {
1523
      tableCondTypes[0] = true;
53✔
1524
    }
1525

1526
    return TSDB_CODE_SUCCESS;
95✔
1527
  }
1528

1529
  if (cxt.haveRightCol) {
104!
1530
    if (cxt.condIsNull) {
104✔
1531
      tableCondTypes[3] = true;
31✔
1532
    } else {
1533
      tableCondTypes[2] = true;
73✔
1534
    }
1535
  }
1536

1537
  return TSDB_CODE_SUCCESS;
104✔
1538
}
1539

1540

1541

1542
static int32_t pdcJoinGetLogicTableCondTypes(SNode* pCond, SSHashObj* pLeftTables, SSHashObj* pRightTables, bool* tableCondTypes) {
136✔
1543
  SLogicConditionNode* pLogicCond = (SLogicConditionNode*)pCond;
136✔
1544
  int32_t code = 0;
136✔
1545
  SNode* pSCond = NULL;
136✔
1546
  FOREACH(pSCond, pLogicCond->pParameterList) {
562!
1547
    if (QUERY_NODE_LOGIC_CONDITION == nodeType(pSCond)) {
426✔
1548
      code = pdcJoinGetLogicTableCondTypes(pSCond, pLeftTables, pRightTables, tableCondTypes);
18✔
1549
    } else {
1550
      code = pdcJoinGetOpTableCondTypes(pSCond, pLeftTables, pRightTables, tableCondTypes);
408✔
1551
    }
1552

1553
    if (TSDB_CODE_SUCCESS != code) {
426!
1554
      break;
×
1555
    }
1556
  }
1557

1558
  return code;
136✔
1559
}
1560

1561
static int32_t pdcGetTableCondTypes(SNode* pCond, SSHashObj* pLeftTables, SSHashObj* pRightTables, bool* tableCondTypes) {
341✔
1562
  if (QUERY_NODE_LOGIC_CONDITION == nodeType(pCond)) {
341✔
1563
    return pdcJoinGetLogicTableCondTypes(pCond, pLeftTables, pRightTables, tableCondTypes);
118✔
1564
  } else {
1565
    return pdcJoinGetOpTableCondTypes(pCond, pLeftTables, pRightTables, tableCondTypes);
223✔
1566
  }
1567
}
1568

1569
static int32_t pdcRewriteTypeBasedOnConds(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) {
1,024✔
1570
  if (JOIN_TYPE_INNER == pJoin->joinType || JOIN_STYPE_OUTER != pJoin->subType) {
1,024✔
1571
    return TSDB_CODE_SUCCESS;
683✔
1572
  }
1573

1574
  SSHashObj* pLeftTables = NULL;
341✔
1575
  SSHashObj* pRightTables = NULL;
341✔
1576
  int32_t code = collectTableAliasFromNodes(nodesListGetNode(pJoin->node.pChildren, 0), &pLeftTables);
341✔
1577
  if (TSDB_CODE_SUCCESS != code) {
341!
1578
    return code;
×
1579
  }
1580

1581
  code = collectTableAliasFromNodes(nodesListGetNode(pJoin->node.pChildren, 1), &pRightTables);
341✔
1582
  if (TSDB_CODE_SUCCESS != code) {
341!
1583
    tSimpleHashCleanup(pLeftTables);
×
1584
    return code;
×
1585
  }
1586
  
1587
  bool tableCondTypes[4] = {0};
341✔
1588
  code = pdcGetTableCondTypes(pJoin->node.pConditions, pLeftTables, pRightTables, tableCondTypes);
341✔
1589
  tSimpleHashCleanup(pLeftTables);
341✔
1590
  tSimpleHashCleanup(pRightTables);
341✔
1591

1592
  if (TSDB_CODE_SUCCESS != code) return code;
341!
1593

1594
  switch (pJoin->joinType) {
341!
1595
    case JOIN_TYPE_LEFT:
240✔
1596
      if (tableCondTypes[2] && !tableCondTypes[3]) {
240✔
1597
        pJoin->joinType = JOIN_TYPE_INNER;
209✔
1598
        pJoin->subType = JOIN_STYPE_NONE;
209✔
1599
      }
1600
      break;
240✔
1601
    case JOIN_TYPE_RIGHT:
48✔
1602
      if (tableCondTypes[0] && !tableCondTypes[1]) {
48✔
1603
        pJoin->joinType = JOIN_TYPE_INNER;
9✔
1604
        pJoin->subType = JOIN_STYPE_NONE;
9✔
1605
      }
1606
      break;
48✔
1607
    case JOIN_TYPE_FULL:
53✔
1608
      if (tableCondTypes[0] && !tableCondTypes[1]) {
53✔
1609
        if (tableCondTypes[2] && !tableCondTypes[3]) {
32!
1610
          pJoin->joinType = JOIN_TYPE_INNER;
30✔
1611
          pJoin->subType = JOIN_STYPE_NONE;
30✔
1612
        } else {
1613
          pJoin->joinType = JOIN_TYPE_LEFT;
2✔
1614
        }
1615
      } else if (tableCondTypes[2] && !tableCondTypes[3]) {
21!
1616
        pJoin->joinType = JOIN_TYPE_RIGHT;
13✔
1617
      }
1618
      break;
53✔
1619
    default:
×
1620
      break;
×
1621
  }
1622

1623
  return code;
341✔
1624
}
1625

1626
static EDealRes pdcCheckTableResType(SNode* pNode, void* pContext) {
274✔
1627
  SCpdIsMultiTableResCxt* pCxt = pContext;
274✔
1628
  switch (nodeType(pNode)) {
274!
1629
    case QUERY_NODE_COLUMN: {
188✔
1630
      if (pdcJoinColInTableList(pNode, pCxt->pLeftTbls)) {
188✔
1631
        pCxt->haveLeftCol = true;
100✔
1632
      } else if (pdcJoinColInTableList(pNode, pCxt->pRightTbls)) {
88!
1633
        pCxt->haveRightCol = true;
88✔
1634
      }
1635
      break;
188✔
1636
    }
1637
    case QUERY_NODE_VALUE:
2✔
1638
    case QUERY_NODE_GROUPING_SET:
1639
      break;
2✔
1640
    case QUERY_NODE_FUNCTION: {
84✔
1641
      SFunctionNode* pFunc = (SFunctionNode*)pNode;
84✔
1642
      SCpdIsMultiTableResCxt cxt = {.pLeftTbls = pCxt->pLeftTbls, .pRightTbls = pCxt->pRightTbls, 
84✔
1643
        .haveLeftCol = false, .haveRightCol = false, .leftColNonNull = true, .rightColNonNull = true};
1644
      
1645
      nodesWalkExprs(pFunc->pParameterList, pdcCheckTableResType, &cxt);
84✔
1646
      if (!cxt.leftColNonNull) {
84!
1647
        pCxt->leftColNonNull = false;
×
1648
      }
1649
      if (!cxt.rightColNonNull) {
84!
1650
        pCxt->rightColNonNull = false;
×
1651
      }
1652
      if (cxt.leftColOp) {
84!
1653
        pCxt->leftColOp = true;
×
1654
      }
1655
      if (cxt.rightColOp) {
84!
1656
        pCxt->rightColOp = true;
×
1657
      }
1658
      if (!cxt.haveLeftCol && !cxt.haveRightCol) {
84✔
1659
        pCxt->leftColNonNull = false;
2✔
1660
        pCxt->rightColNonNull = false;
2✔
1661
        return DEAL_RES_END;
2✔
1662
      } else if (!fmIsIgnoreNullFunc(pFunc->funcId)) {
82!
1663
        if (cxt.haveLeftCol) {
×
1664
          pCxt->leftColNonNull = false;
×
1665
        }
1666
        if (cxt.haveRightCol) {
×
1667
          pCxt->rightColNonNull = false;
×
1668
        }
1669
      } else {
1670
        if (cxt.haveLeftCol) {
82✔
1671
          pCxt->leftColOp = true;
46✔
1672
        } else if (cxt.haveRightCol) {
36!
1673
          pCxt->rightColOp = true;
36✔
1674
        }
1675
      }
1676
      if (!pCxt->leftColNonNull && !pCxt->rightColNonNull) {
82!
1677
        return DEAL_RES_END;
×
1678
      }
1679
      break;
82✔
1680
    }
1681
    default:
×
1682
      pCxt->leftColNonNull = false;
×
1683
      pCxt->rightColNonNull = false;
×
1684
      return DEAL_RES_END;
×
1685
  }
1686
  
1687
  return DEAL_RES_CONTINUE;
272✔
1688
}
1689

1690
static int32_t pdcRewriteTypeBasedOnJoinRes(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) {
115,097✔
1691
  if (JOIN_TYPE_INNER == pJoin->joinType || JOIN_STYPE_OUTER != pJoin->subType) {
115,097✔
1692
    return TSDB_CODE_SUCCESS;
114,369✔
1693
  }
1694

1695
  int32_t code = 0;
728✔
1696
  SSHashObj* pLeftTables = NULL;
728✔
1697
  SSHashObj* pRightTables = NULL;
728✔
1698
  code = collectTableAliasFromNodes(nodesListGetNode(pJoin->node.pChildren, 0), &pLeftTables);
728✔
1699
  if (TSDB_CODE_SUCCESS != code) {
728!
1700
    return code;
×
1701
  }
1702
  code = collectTableAliasFromNodes(nodesListGetNode(pJoin->node.pChildren, 1), &pRightTables);
728✔
1703
  if (TSDB_CODE_SUCCESS != code) {
728!
1704
    tSimpleHashCleanup(pLeftTables);
×
1705
    return code;
×
1706
  }
1707

1708
  SLogicNode* pParent = pJoin->node.pParent;
728✔
1709
  bool tableResNonNull[2] = {true, true};
728✔
1710
  bool tableResOp[2] = {false, false};
728✔
1711
  if (QUERY_NODE_LOGIC_PLAN_AGG == nodeType(pParent)) {
728✔
1712
    SAggLogicNode* pAgg = (SAggLogicNode*)pParent;
69✔
1713
    if (NULL != pAgg->pGroupKeys) {
69✔
1714
      tableResNonNull[0] = false;
1✔
1715
      tableResNonNull[1] = false;
1✔
1716
    } else {
1717
      SCpdIsMultiTableResCxt cxt = {.pLeftTbls = pLeftTables, .pRightTbls = pRightTables, 
68✔
1718
        .haveLeftCol = false, .haveRightCol = false, .leftColNonNull = true, .rightColNonNull = true, .leftColOp = false, .rightColOp = false};
1719
      
1720
      nodesWalkExprs(pAgg->pAggFuncs, pdcCheckTableResType, &cxt);
68✔
1721
      if (!cxt.leftColNonNull) {
68✔
1722
        tableResNonNull[0] = false;
2✔
1723
      }
1724
      if (!cxt.rightColNonNull) {
68✔
1725
        tableResNonNull[1] = false;
2✔
1726
      }
1727
      if (cxt.leftColOp) {
68✔
1728
        tableResOp[0] = true;
38✔
1729
      }
1730
      if (cxt.rightColOp) {
68✔
1731
        tableResOp[1] = true;
32✔
1732
      }
1733
    }
1734
  } else {
1735
    tableResNonNull[0] = false;
659✔
1736
    tableResNonNull[1] = false;
659✔
1737
  }
1738

1739
  tSimpleHashCleanup(pLeftTables);
728✔
1740
  tSimpleHashCleanup(pRightTables);
728✔
1741

1742
  switch (pJoin->joinType) {
728!
1743
    case JOIN_TYPE_LEFT:
286✔
1744
      if (tableResNonNull[1] && !tableResOp[0]) {
286✔
1745
        pJoin->joinType = JOIN_TYPE_INNER;
18✔
1746
        pJoin->subType = JOIN_STYPE_NONE;
18✔
1747
      }
1748
      break;
286✔
1749
    case JOIN_TYPE_RIGHT:
249✔
1750
      if (tableResNonNull[0] && !tableResOp[1]) {
249✔
1751
        pJoin->joinType = JOIN_TYPE_INNER;
18✔
1752
        pJoin->subType = JOIN_STYPE_NONE;
18✔
1753
      }
1754
      break;
249✔
1755
    case JOIN_TYPE_FULL:
193✔
1756
      if (tableResNonNull[1] && !tableResOp[0]) {
193✔
1757
        if (tableResNonNull[0] && !tableResOp[1]) {
2!
1758
          pJoin->joinType = JOIN_TYPE_INNER;
×
1759
          pJoin->subType = JOIN_STYPE_NONE;
×
1760
        } else {
1761
          pJoin->joinType = JOIN_TYPE_RIGHT;
2✔
1762
        }
1763
      } else if (tableResNonNull[0] && !tableResOp[1]) {
191!
1764
        pJoin->joinType = JOIN_TYPE_LEFT;
4✔
1765
      }
1766
      break;
193✔
1767
    default:
×
1768
      break;
×
1769
  }
1770

1771
  return TSDB_CODE_SUCCESS;
728✔
1772
}
1773

1774
static int32_t pdcDealJoin(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) {
414,285✔
1775
  if (OPTIMIZE_FLAG_TEST_MASK(pJoin->node.optimizedFlag, OPTIMIZE_FLAG_PUSH_DOWN_CONDE)) {
414,285✔
1776
    return TSDB_CODE_SUCCESS;
246,174✔
1777
  }
1778
  if (pJoin->joinAlgo != JOIN_ALGO_UNKNOWN) {
168,111✔
1779
    return TSDB_CODE_SUCCESS;
52,460✔
1780
  }
1781

1782
  EJoinType t = pJoin->joinType;
115,651✔
1783
  EJoinSubType s = pJoin->subType;
115,651✔
1784
  SNode*  pOnCond = NULL;
115,651✔
1785
  SNode*  pLeftChildCond = NULL;
115,651✔
1786
  SNode*  pRightChildCond = NULL;
115,651✔
1787
  int32_t code = pdcJoinCheckAllCond(pCxt, pJoin);
115,651✔
1788
  while (true) {
1789
    if (TSDB_CODE_SUCCESS == code && NULL != pJoin->node.pConditions) {
115,956✔
1790
      if (0 != gJoinWhereOpt[t][s].pushDownFlag) {
107,354✔
1791
        code = pdcJoinSplitCond(pJoin, &pJoin->node.pConditions, &pOnCond, &pLeftChildCond, &pRightChildCond, true);
107,301✔
1792
        if (TSDB_CODE_SUCCESS == code && NULL != pOnCond) {
107,301!
1793
          code = pdcJoinPushDownOnCond(pCxt, pJoin, &pOnCond);
69,137✔
1794
        }
1795
        if (TSDB_CODE_SUCCESS == code && NULL != pLeftChildCond) {
107,301!
1796
          code = pdcPushDownCondToChild(pCxt, (SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 0), &pLeftChildCond);
62,818✔
1797
        }
1798
        if (TSDB_CODE_SUCCESS == code && NULL != pRightChildCond) {
107,301!
1799
          code = pdcPushDownCondToChild(pCxt, (SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 1), &pRightChildCond);
56,520✔
1800
        }
1801
      }
1802
      if (TSDB_CODE_SUCCESS == code && NULL != pJoin->node.pConditions) {
107,354!
1803
        code = pdcRewriteTypeBasedOnConds(pCxt, pJoin);
1,024✔
1804
      }
1805
    }
1806

1807
    if (TSDB_CODE_SUCCESS == code) {
115,956✔
1808
      code = pdcRewriteTypeBasedOnJoinRes(pCxt, pJoin);
115,097✔
1809
    }
1810
    
1811
    if (TSDB_CODE_SUCCESS != code || t == pJoin->joinType) {
115,956✔
1812
      break;
1813
    }
1814
    
1815
    t = pJoin->joinType;
305✔
1816
    s = pJoin->subType;
305✔
1817
  }
1818

1819
  if (TSDB_CODE_SUCCESS == code && NULL != pJoin->pFullOnCond && 0 != gJoinOnOpt[t][s].pushDownFlag) {
115,651✔
1820
    code = pdcJoinSplitCond(pJoin, &pJoin->pFullOnCond, NULL, &pLeftChildCond, &pRightChildCond, false);
112,943✔
1821
    if (TSDB_CODE_SUCCESS == code && NULL != pLeftChildCond) {
112,943!
1822
      code = pdcPushDownCondToChild(pCxt, (SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 0), &pLeftChildCond);
317✔
1823
    }
1824
    if (TSDB_CODE_SUCCESS == code && NULL != pRightChildCond) {
112,943!
1825
      code = pdcPushDownCondToChild(pCxt, (SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 1), &pRightChildCond);
249✔
1826
    }
1827
  }
1828

1829
  if (TSDB_CODE_SUCCESS == code && NULL != pJoin->pFullOnCond && !IS_WINDOW_JOIN(pJoin->subType) && NULL == pJoin->addPrimEqCond) {
115,651✔
1830
    code = pdcJoinSplitPrimEqCond(pCxt, pJoin);
113,635✔
1831
  }
1832

1833
  if (TSDB_CODE_SUCCESS == code) {
115,651✔
1834
    code = pdcJoinPartEqualOnCond(pCxt, pJoin);
114,792✔
1835
  }
1836

1837
  if (TSDB_CODE_SUCCESS == code) {
115,651✔
1838
    code = pdcJoinHandleGrpJoinCond(pCxt, pJoin);
114,792✔
1839
  }
1840

1841
  if (TSDB_CODE_SUCCESS == code) {
115,651✔
1842
    code = pdcJoinAddParentOnColsToTarget(pCxt, pJoin);
114,755✔
1843
  }
1844

1845
  //if (TSDB_CODE_SUCCESS == code) {
1846
  //  code = pdcJoinAddPreFilterColsToTarget(pCxt, pJoin);
1847
  //}
1848

1849
  if (TSDB_CODE_SUCCESS == code) {
115,651✔
1850
    code = pdcJoinAddFilterColsToTarget(pCxt, pJoin);
114,755✔
1851
  }
1852

1853
  if (TSDB_CODE_SUCCESS == code) {
115,651✔
1854
    OPTIMIZE_FLAG_SET_MASK(pJoin->node.optimizedFlag, OPTIMIZE_FLAG_PUSH_DOWN_CONDE);
114,755✔
1855
    pCxt->optimized = true;
114,755✔
1856
  } else {
1857
    nodesDestroyNode(pOnCond);
896✔
1858
    nodesDestroyNode(pLeftChildCond);
896✔
1859
    nodesDestroyNode(pRightChildCond);
896✔
1860
  }
1861

1862
  return code;
115,651✔
1863
}
1864

1865
typedef struct SPartAggCondContext {
1866
  SAggLogicNode* pAgg;
1867
  bool           hasAggFunc;
1868
} SPartAggCondContext;
1869

1870
static EDealRes partAggCondHasAggFuncImpl(SNode* pNode, void* pContext) {
213,153✔
1871
  SPartAggCondContext* pCxt = pContext;
213,153✔
1872
  if (QUERY_NODE_COLUMN == nodeType(pNode)) {
213,153✔
1873
    SNode* pAggFunc = NULL;
106,463✔
1874
    FOREACH(pAggFunc, pCxt->pAgg->pAggFuncs) {
107,122✔
1875
      if (strcmp(((SColumnNode*)pNode)->colName, ((SFunctionNode*)pAggFunc)->node.aliasName) == 0) {
45,943✔
1876
        pCxt->hasAggFunc = true;
45,284✔
1877
        return DEAL_RES_END;
45,284✔
1878
      }
1879
    }
1880
  }
1881
  return DEAL_RES_CONTINUE;
167,869✔
1882
}
1883

1884
static int32_t partitionAggCondHasAggFunc(SAggLogicNode* pAgg, SNode* pCond) {
106,463✔
1885
  SPartAggCondContext cxt = {.pAgg = pAgg, .hasAggFunc = false};
106,463✔
1886
  nodesWalkExpr(pCond, partAggCondHasAggFuncImpl, &cxt);
106,463✔
1887
  return cxt.hasAggFunc;
106,463✔
1888
}
1889

1890
static int32_t partitionAggCondConj(SAggLogicNode* pAgg, SNode** ppAggFuncCond, SNode** ppGroupKeyCond) {
82✔
1891
  SLogicConditionNode* pLogicCond = (SLogicConditionNode*)pAgg->node.pConditions;
82✔
1892
  int32_t              code = TSDB_CODE_SUCCESS;
82✔
1893

1894
  SNodeList* pAggFuncConds = NULL;
82✔
1895
  SNodeList* pGroupKeyConds = NULL;
82✔
1896
  SNode*     pCond = NULL;
82✔
1897
  FOREACH(pCond, pLogicCond->pParameterList) {
246!
1898
    SNode* pNew = NULL;
164✔
1899
    code = nodesCloneNode(pCond, &pNew);
164✔
1900
    if (TSDB_CODE_SUCCESS != code) {
164!
1901
      break;
×
1902
    }
1903
    if (partitionAggCondHasAggFunc(pAgg, pCond)) {
164✔
1904
      code = nodesListMakeStrictAppend(&pAggFuncConds, pNew);
114✔
1905
    } else {
1906
      code = nodesListMakeStrictAppend(&pGroupKeyConds, pNew);
50✔
1907
    }
1908
    if (TSDB_CODE_SUCCESS != code) {
164!
1909
      break;
×
1910
    }
1911
  }
1912

1913
  SNode* pTempAggFuncCond = NULL;
82✔
1914
  SNode* pTempGroupKeyCond = NULL;
82✔
1915
  if (TSDB_CODE_SUCCESS == code) {
82!
1916
    code = nodesMergeConds(&pTempAggFuncCond, &pAggFuncConds);
82✔
1917
  }
1918
  if (TSDB_CODE_SUCCESS == code) {
82!
1919
    code = nodesMergeConds(&pTempGroupKeyCond, &pGroupKeyConds);
82✔
1920
  }
1921

1922
  if (TSDB_CODE_SUCCESS == code) {
82!
1923
    *ppAggFuncCond = pTempAggFuncCond;
82✔
1924
    *ppGroupKeyCond = pTempGroupKeyCond;
82✔
1925
  } else {
1926
    nodesDestroyList(pAggFuncConds);
×
1927
    nodesDestroyList(pGroupKeyConds);
×
1928
    nodesDestroyNode(pTempAggFuncCond);
×
1929
    nodesDestroyNode(pTempGroupKeyCond);
×
1930
  }
1931
  nodesDestroyNode(pAgg->node.pConditions);
82✔
1932
  pAgg->node.pConditions = NULL;
82✔
1933
  return code;
82✔
1934
}
1935

1936
static int32_t partitionAggCond(SAggLogicNode* pAgg, SNode** ppAggFunCond, SNode** ppGroupKeyCond) {
106,381✔
1937
  SNode* pAggNodeCond = pAgg->node.pConditions;
106,381✔
1938
  if (QUERY_NODE_LOGIC_CONDITION == nodeType(pAggNodeCond) &&
106,381✔
1939
      LOGIC_COND_TYPE_AND == ((SLogicConditionNode*)(pAggNodeCond))->condType) {
88✔
1940
    return partitionAggCondConj(pAgg, ppAggFunCond, ppGroupKeyCond);
82✔
1941
  }
1942
  if (partitionAggCondHasAggFunc(pAgg, pAggNodeCond)) {
106,299✔
1943
    *ppAggFunCond = pAggNodeCond;
45,170✔
1944
  } else {
1945
    *ppGroupKeyCond = pAggNodeCond;
61,129✔
1946
  }
1947
  pAgg->node.pConditions = NULL;
106,299✔
1948
  return TSDB_CODE_SUCCESS;
106,299✔
1949
}
1950

1951
static int32_t pushCondToAggCond(SOptimizeContext* pCxt, SAggLogicNode* pAgg, SNode** pAggFuncCond) {
45,252✔
1952
  return pdcMergeConds(&pAgg->node.pConditions, pAggFuncCond);
45,252✔
1953
}
1954

1955
typedef struct SRewriteAggGroupKeyCondContext {
1956
  SAggLogicNode* pAgg;
1957
  int32_t        errCode;
1958
} SRewriteAggGroupKeyCondContext;
1959

1960
static EDealRes rewriteAggGroupKeyCondForPushDownImpl(SNode** pNode, void* pContext) {
122,561✔
1961
  SRewriteAggGroupKeyCondContext* pCxt = pContext;
122,561✔
1962
  SAggLogicNode*                  pAgg = pCxt->pAgg;
122,561✔
1963
  if (QUERY_NODE_COLUMN == nodeType(*pNode)) {
122,561✔
1964
    SNode* pGroupKey = NULL;
61,179✔
1965
    FOREACH(pGroupKey, pAgg->pGroupKeys) {
61,179!
1966
      SNode* pGroup = NULL;
61,179✔
1967
      FOREACH(pGroup, ((SGroupingSetNode*)pGroupKey)->pParameterList) {
61,179!
1968
        if (0 == strcmp(((SExprNode*)pGroup)->aliasName, ((SColumnNode*)(*pNode))->colName)) {
61,179!
1969
          SNode* pExpr = NULL;
61,179✔
1970
          pCxt->errCode = nodesCloneNode(pGroup, &pExpr);
61,179✔
1971
          if (pExpr == NULL) {
61,179!
1972
            return DEAL_RES_ERROR;
×
1973
          }
1974
          nodesDestroyNode(*pNode);
61,179✔
1975
          *pNode = pExpr;
61,179✔
1976
          return DEAL_RES_IGNORE_CHILD;
61,179✔
1977
        }
1978
      }
1979
    }
1980
  }
1981
  return DEAL_RES_CONTINUE;
61,382✔
1982
}
1983

1984
static int32_t rewriteAggGroupKeyCondForPushDown(SOptimizeContext* pCxt, SAggLogicNode* pAgg, SNode* pGroupKeyCond) {
61,179✔
1985
  SRewriteAggGroupKeyCondContext cxt = {.pAgg = pAgg, .errCode = TSDB_CODE_SUCCESS};
61,179✔
1986
  nodesRewriteExpr(&pGroupKeyCond, rewriteAggGroupKeyCondForPushDownImpl, &cxt);
61,179✔
1987
  return cxt.errCode;
61,179✔
1988
}
1989

1990
static int32_t pdcDealAgg(SOptimizeContext* pCxt, SAggLogicNode* pAgg) {
1,528,975✔
1991
  if (NULL == pAgg->node.pConditions ||
1,528,975✔
1992
      OPTIMIZE_FLAG_TEST_MASK(pAgg->node.optimizedFlag, OPTIMIZE_FLAG_PUSH_DOWN_CONDE)) {
249,608✔
1993
    return TSDB_CODE_SUCCESS;
1,422,594✔
1994
  }
1995
  // TODO: remove it after full implementation of pushing down to child
1996
  if (1 != LIST_LENGTH(pAgg->node.pChildren)) {
106,381!
1997
    return TSDB_CODE_SUCCESS;
×
1998
  }
1999

2000
  SNode*  pAggFuncCond = NULL;
106,381✔
2001
  SNode*  pGroupKeyCond = NULL;
106,381✔
2002
  int32_t code = partitionAggCond(pAgg, &pAggFuncCond, &pGroupKeyCond);
106,381✔
2003
  if (TSDB_CODE_SUCCESS == code && NULL != pAggFuncCond) {
106,381!
2004
    code = pushCondToAggCond(pCxt, pAgg, &pAggFuncCond);
45,252✔
2005
  }
2006
  if (TSDB_CODE_SUCCESS == code && NULL != pGroupKeyCond) {
106,381!
2007
    code = rewriteAggGroupKeyCondForPushDown(pCxt, pAgg, pGroupKeyCond);
61,179✔
2008
  }
2009
  if (TSDB_CODE_SUCCESS == code && NULL != pGroupKeyCond) {
106,381!
2010
    SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pAgg->node.pChildren, 0);
61,179✔
2011
    code = pdcPushDownCondToChild(pCxt, pChild, &pGroupKeyCond);
61,179✔
2012
  }
2013
  if (TSDB_CODE_SUCCESS == code) {
106,381!
2014
    OPTIMIZE_FLAG_SET_MASK(pAgg->node.optimizedFlag, OPTIMIZE_FLAG_PUSH_DOWN_CONDE);
106,381✔
2015
    pCxt->optimized = true;
106,381✔
2016
  } else {
2017
    nodesDestroyNode(pGroupKeyCond);
×
2018
    nodesDestroyNode(pAggFuncCond);
×
2019
  }
2020
  return code;
106,381✔
2021
}
2022

2023
typedef struct SRewriteProjCondContext {
2024
  SProjectLogicNode* pProj;
2025
  int32_t            errCode;
2026
} SRewriteProjCondContext;
2027

2028
static EDealRes rewriteProjectCondForPushDownImpl(SNode** ppNode, void* pContext) {
64,438✔
2029
  SRewriteProjCondContext* pCxt = pContext;
64,438✔
2030
  SProjectLogicNode*       pProj = pCxt->pProj;
64,438✔
2031
  if (QUERY_NODE_COLUMN == nodeType(*ppNode)) {
64,438✔
2032
    SNode* pTarget = NULL;
19,258✔
2033
    FOREACH(pTarget, pProj->node.pTargets) {
44,469!
2034
      if (nodesEqualNode(pTarget, *ppNode)) {
44,469✔
2035
        SNode* pProjection = NULL;
19,258✔
2036
        FOREACH(pProjection, pProj->pProjections) {
44,469!
2037
          if (0 == strcmp(((SExprNode*)pProjection)->aliasName, ((SColumnNode*)(*ppNode))->colName)) {
44,469✔
2038
            SNode* pExpr = NULL;
19,258✔
2039
            pCxt->errCode = nodesCloneNode(pProjection, &pExpr);
19,258✔
2040
            if (pExpr == NULL) {
19,258!
2041
              return DEAL_RES_ERROR;
×
2042
            }
2043
            nodesDestroyNode(*ppNode);
19,258✔
2044
            *ppNode = pExpr;
19,258✔
2045
            return DEAL_RES_IGNORE_CHILD;
19,258✔
2046
          }  // end if expr alias name equal column name
2047
        }    // end for each project
2048
      }      // end if target node equals cond column node
2049
    }        // end for each targets
2050
  }
2051
  return DEAL_RES_CONTINUE;
45,180✔
2052
}
2053

2054
static int32_t rewriteProjectCondForPushDown(SOptimizeContext* pCxt, SProjectLogicNode* pProject,
12,289✔
2055
                                             SNode** ppProjectCond) {
2056
  SRewriteProjCondContext cxt = {.pProj = pProject, .errCode = TSDB_CODE_SUCCESS};
12,289✔
2057
  SNode*                  pProjectCond = pProject->node.pConditions;
12,289✔
2058
  nodesRewriteExpr(&pProjectCond, rewriteProjectCondForPushDownImpl, &cxt);
12,289✔
2059
  *ppProjectCond = pProjectCond;
12,289✔
2060
  pProject->node.pConditions = NULL;
12,289✔
2061
  return cxt.errCode;
12,289✔
2062
}
2063

2064
static int32_t pdcDealProject(SOptimizeContext* pCxt, SProjectLogicNode* pProject) {
3,389,680✔
2065
  if (NULL == pProject->node.pConditions ||
3,389,680✔
2066
      OPTIMIZE_FLAG_TEST_MASK(pProject->node.optimizedFlag, OPTIMIZE_FLAG_PUSH_DOWN_CONDE)) {
12,561!
2067
    return TSDB_CODE_SUCCESS;
3,377,119✔
2068
  }
2069
  // TODO: remove it after full implementation of pushing down to child
2070
  if (1 != LIST_LENGTH(pProject->node.pChildren)) {
12,561!
2071
    return TSDB_CODE_SUCCESS;
240✔
2072
  }
2073

2074
  if (NULL != pProject->node.pLimit || NULL != pProject->node.pSlimit) {
12,321!
2075
    return TSDB_CODE_SUCCESS;
32✔
2076
  }
2077

2078
  int32_t code = TSDB_CODE_SUCCESS;
12,289✔
2079
  SNode*  pProjCond = NULL;
12,289✔
2080
  code = rewriteProjectCondForPushDown(pCxt, pProject, &pProjCond);
12,289✔
2081
  if (TSDB_CODE_SUCCESS == code) {
12,289!
2082
    SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pProject->node.pChildren, 0);
12,289✔
2083
    code = pdcPushDownCondToChild(pCxt, pChild, &pProjCond);
12,289✔
2084
  }
2085

2086
  if (TSDB_CODE_SUCCESS == code) {
12,289!
2087
    OPTIMIZE_FLAG_SET_MASK(pProject->node.optimizedFlag, OPTIMIZE_FLAG_PUSH_DOWN_CONDE);
12,289✔
2088
    pCxt->optimized = true;
12,289✔
2089
  } else {
2090
    nodesDestroyNode(pProjCond);
×
2091
  }
2092
  return code;
12,289✔
2093
}
2094

2095
static int32_t pdcTrivialPushDown(SOptimizeContext* pCxt, SLogicNode* pLogicNode) {
1,267,554✔
2096
  if (NULL == pLogicNode->pConditions ||
1,267,554✔
2097
      OPTIMIZE_FLAG_TEST_MASK(pLogicNode->optimizedFlag, OPTIMIZE_FLAG_PUSH_DOWN_CONDE)) {
633!
2098
    return TSDB_CODE_SUCCESS;
1,266,921✔
2099
  }
2100
  SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pLogicNode->pChildren, 0);
633✔
2101
  int32_t     code = pdcPushDownCondToChild(pCxt, pChild, &pLogicNode->pConditions);
633✔
2102
  if (TSDB_CODE_SUCCESS == code) {
633!
2103
    OPTIMIZE_FLAG_SET_MASK(pLogicNode->optimizedFlag, OPTIMIZE_FLAG_PUSH_DOWN_CONDE);
633✔
2104
    pCxt->optimized = true;
633✔
2105
  }
2106
  return code;
633✔
2107
}
2108

2109
static int32_t pdcOptimizeImpl(SOptimizeContext* pCxt, SLogicNode* pLogicNode) {
9,876,786✔
2110
  int32_t code = TSDB_CODE_SUCCESS;
9,876,786✔
2111
  switch (nodeType(pLogicNode)) {
9,876,786✔
2112
    case QUERY_NODE_LOGIC_PLAN_SCAN:
2,854,736✔
2113
      code = pdcDealScan(pCxt, (SScanLogicNode*)pLogicNode);
2,854,736✔
2114
      break;
2,854,736✔
2115
    case QUERY_NODE_LOGIC_PLAN_JOIN:
414,285✔
2116
      code = pdcDealJoin(pCxt, (SJoinLogicNode*)pLogicNode);
414,285✔
2117
      break;
414,285✔
2118
    case QUERY_NODE_LOGIC_PLAN_AGG:
1,528,979✔
2119
      code = pdcDealAgg(pCxt, (SAggLogicNode*)pLogicNode);
1,528,979✔
2120
      break;
1,528,974✔
2121
    case QUERY_NODE_LOGIC_PLAN_PROJECT:
3,389,681✔
2122
      code = pdcDealProject(pCxt, (SProjectLogicNode*)pLogicNode);
3,389,681✔
2123
      break;
3,389,681✔
2124
    case QUERY_NODE_LOGIC_PLAN_SORT:
1,267,555✔
2125
    case QUERY_NODE_LOGIC_PLAN_PARTITION:
2126
      code = pdcTrivialPushDown(pCxt, pLogicNode);
1,267,555✔
2127
      break;
1,267,554✔
2128
    default:
421,550✔
2129
      break;
421,550✔
2130
  }
2131
  if (TSDB_CODE_SUCCESS == code) {
9,876,780✔
2132
    SNode* pChild = NULL;
9,875,890✔
2133
    FOREACH(pChild, pLogicNode->pChildren) {
17,672,153✔
2134
      code = pdcOptimizeImpl(pCxt, (SLogicNode*)pChild);
7,797,247✔
2135
      if (TSDB_CODE_SUCCESS != code) {
7,797,254✔
2136
        break;
991✔
2137
      }
2138
    }
2139
  }
2140
  return code;
9,876,787✔
2141
}
2142

2143
static int32_t pdcOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
2,079,544✔
2144
  return pdcOptimizeImpl(pCxt, pLogicSubplan->pNode);
2,079,544✔
2145
}
2146

2147

2148
static bool eliminateNotNullCondMayBeOptimized(SLogicNode* pNode, void* pCtx) {
7,818,805✔
2149
  if (QUERY_NODE_LOGIC_PLAN_AGG != nodeType(pNode)) {
7,818,805✔
2150
    return false;
6,596,343✔
2151
  }
2152
  
2153
  SAggLogicNode* pAgg = (SAggLogicNode*)pNode;
1,222,462✔
2154
  if (pNode->pChildren->length != 1 || NULL != pAgg->pGroupKeys) {
1,222,462✔
2155
    return false;
409,924✔
2156
  }
2157

2158
  SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pAgg->node.pChildren, 0);
812,538✔
2159
  if (QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(pChild)) {
812,536✔
2160
    return false;
354,824✔
2161
  }
2162

2163
  SScanLogicNode* pScan = (SScanLogicNode*)pChild;
457,712✔
2164
  if (NULL == pScan->node.pConditions || QUERY_NODE_OPERATOR != nodeType(pScan->node.pConditions)) {
457,712✔
2165
    return false;
432,522✔
2166
  }
2167

2168
  SOperatorNode* pOp = (SOperatorNode*)pScan->node.pConditions;
25,190✔
2169
  if (OP_TYPE_IS_NOT_NULL != pOp->opType) {
25,190✔
2170
    return false;
22,676✔
2171
  }
2172

2173
  if (QUERY_NODE_COLUMN != nodeType(pOp->pLeft)) {
2,514!
2174
    return false;
×
2175
  }
2176

2177
  SNode* pTmp = NULL;
2,514✔
2178
  FOREACH(pTmp, pAgg->pAggFuncs) {
2,532!
2179
    SFunctionNode* pFunc = (SFunctionNode*)pTmp;
2,530✔
2180
    if (!fmIsIgnoreNullFunc(pFunc->funcId)) {
2,530✔
2181
      return false;
2,140✔
2182
    }
2183
    if (fmIsMultiResFunc(pFunc->funcId)) {
390✔
2184
      SNode* pParam = NULL;
276✔
2185
      FOREACH(pParam, pFunc->pParameterList) {
286!
2186
        if (QUERY_NODE_COLUMN != nodeType(pParam)) {
286!
2187
          return false;
×
2188
        }
2189
        if (!nodesEqualNode(pParam, pOp->pLeft)) {
286✔
2190
          return false;
276✔
2191
        }
2192
      }
2193
    } else {
2194
      SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0);
114✔
2195
      if (QUERY_NODE_COLUMN != nodeType(pParam)) {
114!
2196
        return false;
×
2197
      }
2198
      if (!nodesEqualNode(pParam, pOp->pLeft)) {
114✔
2199
        return false;
96✔
2200
      }
2201
    }
2202
  }
2203

2204
  return true;
2✔
2205
}
2206

2207
static int32_t eliminateNotNullCondOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
1,709,014✔
2208
  SLogicNode* pNode = (SLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, eliminateNotNullCondMayBeOptimized, NULL);
1,709,014✔
2209
  if (NULL == pNode) {
1,709,022✔
2210
    return TSDB_CODE_SUCCESS;
1,709,020✔
2211
  }
2212
  
2213
  SScanLogicNode* pScan = (SScanLogicNode*)nodesListGetNode(pNode->pChildren, 0);
2✔
2214
  nodesDestroyNode(pScan->node.pConditions);
2✔
2215
  pScan->node.pConditions = NULL;
2✔
2216

2217
  pCxt->optimized = true;
2✔
2218

2219
  return TSDB_CODE_SUCCESS;
2✔
2220
}
2221

2222

2223
static bool sortPriKeyOptIsPriKeyOrderBy(SNodeList* pSortKeys) {
1,645,665✔
2224
  if (1 != LIST_LENGTH(pSortKeys)) {
1,645,665!
2225
    return false;
305,764✔
2226
  }
2227
  SNode* pNode = ((SOrderByExprNode*)nodesListGetNode(pSortKeys, 0))->pExpr;
1,339,901✔
2228
  return (QUERY_NODE_COLUMN == nodeType(pNode) ? isPrimaryKeyImpl(pNode) : false);
1,339,901✔
2229
}
2230

2231
static bool sortPriKeyOptMayBeOptimized(SLogicNode* pNode, void* pCtx) {
7,580,028✔
2232
  if (QUERY_NODE_LOGIC_PLAN_SORT != nodeType(pNode)) {
7,580,028✔
2233
    return false;
6,778,316✔
2234
  }
2235
  SSortLogicNode* pSort = (SSortLogicNode*)pNode;
801,712✔
2236
  if (pSort->skipPKSortOpt || !sortPriKeyOptIsPriKeyOrderBy(pSort->pSortKeys) ||
801,712✔
2237
      1 != LIST_LENGTH(pSort->node.pChildren)) {
145,970!
2238
    return false;
655,742✔
2239
  }
2240
  SNode* pChild = nodesListGetNode(pSort->node.pChildren, 0);
145,970✔
2241
  if (QUERY_NODE_LOGIC_PLAN_JOIN == nodeType(pChild)) {
145,970✔
2242
    SJoinLogicNode* pJoin = (SJoinLogicNode*)pChild;
17,192✔
2243
    if (JOIN_TYPE_FULL == pJoin->joinType) {
17,192✔
2244
      return false;
23✔
2245
    }
2246
  }
2247
  
2248
  FOREACH(pChild, pSort->node.pChildren) {
291,798!
2249
    SLogicNode* pSortDescendent = optFindPossibleNode((SLogicNode*)pChild, sortPriKeyOptMayBeOptimized, NULL);
145,947✔
2250
    if (pSortDescendent != NULL) {
145,947✔
2251
      return false;
96✔
2252
    }
2253
  }
2254
  return true;
145,851✔
2255
}
2256

2257
static int32_t sortPriKeyOptHandleLeftRightJoinSort(SJoinLogicNode* pJoin, SSortLogicNode* pSort, bool* pNotOptimize, bool* keepSort) {
553✔
2258
  if (JOIN_STYPE_SEMI == pJoin->subType || JOIN_STYPE_NONE == pJoin->subType) {
553!
2259
    return TSDB_CODE_SUCCESS;
124✔
2260
  }
2261

2262
  SSHashObj* pLeftTables = NULL;
429✔
2263
  SSHashObj* pRightTables = NULL;
429✔
2264
  bool sortByProbe = true;
429✔
2265
/*  
2266
  bool sortByLeft = true, sortByRight = true, sortByProbe = false;
2267
  collectTableAliasFromNodes(nodesListGetNode(pJoin->node.pChildren, 0), &pLeftTables);
2268
  collectTableAliasFromNodes(nodesListGetNode(pJoin->node.pChildren, 1), &pRightTables);
2269

2270
  SOrderByExprNode* pExprNode = (SOrderByExprNode*)nodesListGetNode(pSort->pSortKeys, 0);
2271
  SColumnNode* pSortCol = (SColumnNode*)pExprNode->pExpr;
2272
  if (NULL == tSimpleHashGet(pLeftTables, pSortCol->tableAlias, strlen(pSortCol->tableAlias))) {
2273
    sortByLeft = false;
2274
  }
2275
  if (NULL == tSimpleHashGet(pRightTables, pSortCol->tableAlias, strlen(pSortCol->tableAlias))) {
2276
    sortByRight = false;
2277
  }
2278

2279
  tSimpleHashCleanup(pLeftTables);
2280
  tSimpleHashCleanup(pRightTables);
2281

2282
  if (!sortByLeft && !sortByRight) {
2283
    planError("sort by primary key not in any join subtable, tableAlias: %s", pSortCol->tableAlias);
2284
    return TSDB_CODE_PLAN_INTERNAL_ERROR;
2285
  }
2286

2287
  if (sortByLeft && sortByRight) {
2288
    planError("sort by primary key in both join subtables, tableAlias: %s", pSortCol->tableAlias);
2289
    return TSDB_CODE_PLAN_INTERNAL_ERROR;
2290
  }
2291

2292
  if ((JOIN_TYPE_LEFT == pJoin->joinType && sortByLeft) || (JOIN_TYPE_RIGHT == pJoin->joinType && sortByRight)) {
2293
    sortByProbe = true;
2294
  }
2295
*/
2296
  switch (pJoin->subType) {
429!
2297
    case JOIN_STYPE_OUTER: {
202✔
2298
      if (sortByProbe) {
202!
2299
        return TSDB_CODE_SUCCESS;
202✔
2300
      }
2301
    }
2302
    case JOIN_STYPE_ANTI: {
2303
      if (sortByProbe) {
70!
2304
        return TSDB_CODE_SUCCESS;
70✔
2305
      }
2306
    }
2307
    case JOIN_STYPE_ASOF: 
2308
    case JOIN_STYPE_WIN: {
2309
      if (sortByProbe) {
157!
2310
        if (NULL != pJoin->pLeftEqNodes && pJoin->pLeftEqNodes->length > 0) {
157!
2311
          *pNotOptimize = true;
14✔
2312
        }
2313
        return TSDB_CODE_SUCCESS;
157✔
2314
      }
2315
    }
2316
    default:
2317
      return TSDB_CODE_PLAN_INTERNAL_ERROR;
×
2318
  }
2319

2320
  return TSDB_CODE_SUCCESS;
2321
}
2322

2323

2324
static int32_t sortPriKeyOptHandleJoinSort(SLogicNode* pNode, bool groupSort, SSortLogicNode* pSort,
22,037✔
2325
                                                   bool* pNotOptimize, SNodeList** pSequencingNodes, bool* keepSort) {
2326
  SJoinLogicNode* pJoin = (SJoinLogicNode*)pNode;
22,037✔
2327
  int32_t code = TSDB_CODE_SUCCESS;
22,037✔
2328

2329
  switch (pJoin->joinType) {
22,037✔
2330
    case JOIN_TYPE_LEFT:
553✔
2331
    case JOIN_TYPE_RIGHT: {
2332
      code = sortPriKeyOptHandleLeftRightJoinSort(pJoin, pSort, pNotOptimize, keepSort);
553✔
2333
      if (TSDB_CODE_SUCCESS != code) {
553!
2334
        return code;
×
2335
      }
2336
      if (*pNotOptimize || !(*keepSort)) {
553!
2337
        return TSDB_CODE_SUCCESS;
14✔
2338
      }
2339
      break;
539✔
2340
    }
2341
    default:
21,484✔
2342
      break;
21,484✔
2343
  }
2344

2345
  code = sortPriKeyOptGetSequencingNodesImpl((SLogicNode*)nodesListGetNode(pNode->pChildren, 0), groupSort,
22,023✔
2346
                                                     pSort, pNotOptimize, pSequencingNodes, keepSort);
2347
  if (TSDB_CODE_SUCCESS == code) {
22,023!
2348
    code = sortPriKeyOptGetSequencingNodesImpl((SLogicNode*)nodesListGetNode(pNode->pChildren, 1), groupSort,
22,023✔
2349
                                               pSort, pNotOptimize, pSequencingNodes, keepSort);
2350
  }
2351

2352
  return code;
22,023✔
2353
}
2354

2355
                                                   
2356
static EOrder sortPriKeyOptGetPriKeyOrder(SSortLogicNode* pSort) {
352,813✔
2357
 return ((SOrderByExprNode*)nodesListGetNode(pSort->pSortKeys, 0))->order;
352,813✔
2358
}
2359

2360

2361
static bool sortPriKeyOptHasUnsupportedPkFunc(SLogicNode* pLogicNode, EOrder sortOrder) {
207,058✔
2362
  if (sortOrder == ORDER_ASC) {
207,058✔
2363
    return false;
177,209✔
2364
  }
2365

2366
  SNodeList* pFuncList = NULL;
29,849✔
2367
  switch (nodeType(pLogicNode)) {
29,849!
2368
    case QUERY_NODE_LOGIC_PLAN_AGG:
447✔
2369
      pFuncList = ((SAggLogicNode*)pLogicNode)->pAggFuncs;
447✔
2370
      break;
447✔
2371
    case QUERY_NODE_LOGIC_PLAN_WINDOW:
2,045✔
2372
      pFuncList = ((SWindowLogicNode*)pLogicNode)->pFuncs;
2,045✔
2373
      break;
2,045✔
2374
    case QUERY_NODE_LOGIC_PLAN_PARTITION:
2,597✔
2375
      pFuncList = ((SPartitionLogicNode*)pLogicNode)->pAggFuncs;
2,597✔
2376
      break;
2,597✔
2377
    case QUERY_NODE_LOGIC_PLAN_INDEF_ROWS_FUNC:
×
2378
      pFuncList = ((SIndefRowsFuncLogicNode*)pLogicNode)->pFuncs;
×
2379
      break;
×
2380
    case QUERY_NODE_LOGIC_PLAN_INTERP_FUNC:
×
2381
      pFuncList = ((SInterpFuncLogicNode*)pLogicNode)->pFuncs;
×
2382
      break;
×
2383
    case QUERY_NODE_LOGIC_PLAN_FORECAST_FUNC:
×
2384
      pFuncList = ((SForecastFuncLogicNode*)pLogicNode)->pFuncs;
×
2385
    default:
24,760✔
2386
      break;
24,760✔
2387
  }
2388
  
2389
  SNode* pNode = 0;
29,849✔
2390
  FOREACH(pNode, pFuncList) {
34,796✔
2391
    if (nodeType(pNode) != QUERY_NODE_FUNCTION) {
4,947!
2392
      continue;
×
2393
    }
2394
    SFunctionNode* pFuncNode = (SFunctionNode*)pLogicNode;
4,947✔
2395
    if (pFuncNode->hasPk && 
4,947!
2396
        (pFuncNode->funcType == FUNCTION_TYPE_DIFF || 
×
2397
         pFuncNode->funcType == FUNCTION_TYPE_DERIVATIVE || 
×
2398
         pFuncNode->funcType == FUNCTION_TYPE_IRATE ||
×
2399
         pFuncNode->funcType == FUNCTION_TYPE_TWA)) {
×
2400
      return true;
×
2401
    }
2402
  }
2403
  return false;
29,849✔
2404
}
2405

2406
int32_t sortPriKeyOptGetSequencingNodesImpl(SLogicNode* pNode, bool groupSort, SSortLogicNode* pSort,
207,058✔
2407
                                                   bool* pNotOptimize, SNodeList** pSequencingNodes, bool* keepSort) {
2408
  EOrder sortOrder = sortPriKeyOptGetPriKeyOrder(pSort);
207,058✔
2409
  if (sortPriKeyOptHasUnsupportedPkFunc(pNode, sortOrder)) {
207,058!
2410
    *pNotOptimize = true;
×
2411
    return TSDB_CODE_SUCCESS;
×
2412
  }
2413

2414
  if (NULL != pNode->pLimit || NULL != pNode->pSlimit) {
207,058✔
2415
    *pNotOptimize = false;
4,925✔
2416
    return TSDB_CODE_SUCCESS;
4,925✔
2417
  }
2418

2419
  switch (nodeType(pNode)) {
202,133✔
2420
    case QUERY_NODE_LOGIC_PLAN_SCAN: {
132,701✔
2421
      SScanLogicNode* pScan = (SScanLogicNode*)pNode;
132,701✔
2422
      if ((!groupSort && NULL != pScan->pGroupTags) || TSDB_SYSTEM_TABLE == pScan->tableType) {
132,701!
2423
        *pNotOptimize = true;
55✔
2424
        return TSDB_CODE_SUCCESS;
55✔
2425
      }
2426
      return nodesListMakeAppend(pSequencingNodes, (SNode*)pNode);
132,646✔
2427
    }
2428
    case QUERY_NODE_LOGIC_PLAN_SORT: {
64✔
2429
      *keepSort = true;
64✔
2430
      NODES_CLEAR_LIST(*pSequencingNodes);      
64✔
2431
      return TSDB_CODE_SUCCESS;
64✔
2432
    }
2433
    case QUERY_NODE_LOGIC_PLAN_JOIN: {
22,037✔
2434
      return sortPriKeyOptHandleJoinSort(pNode, groupSort, pSort, pNotOptimize, pSequencingNodes, keepSort);
22,037✔
2435
    }
2436
    case QUERY_NODE_LOGIC_PLAN_WINDOW: {
5,074✔
2437
      SWindowLogicNode* pWindowLogicNode = (SWindowLogicNode*)pNode;
5,074✔
2438
      // For interval window, we always apply sortPriKey optimization.
2439
      // For session/event/state window, the output ts order will always be ASC.
2440
      // If sort order is also asc, we apply optimization, otherwise we keep sort node to get correct output order.
2441
      if (pWindowLogicNode->winType == WINDOW_TYPE_INTERVAL || sortOrder == ORDER_ASC)
5,074✔
2442
        return nodesListMakeAppend(pSequencingNodes, (SNode*)pNode);
5,057✔
2443
    }
2444
    case QUERY_NODE_LOGIC_PLAN_AGG:
2445
    case QUERY_NODE_LOGIC_PLAN_PARTITION:
2446
    case QUERY_NODE_LOGIC_PLAN_DYN_QUERY_CTRL:
2447
      *pNotOptimize = true;
19,967✔
2448
      return TSDB_CODE_SUCCESS;
19,967✔
2449
    default:
22,307✔
2450
      break;
22,307✔
2451
  }
2452

2453
  if (1 != LIST_LENGTH(pNode->pChildren)) {
22,307!
2454
    *pNotOptimize = true;
5,050✔
2455
    return TSDB_CODE_SUCCESS;
5,050✔
2456
  }
2457

2458
  return sortPriKeyOptGetSequencingNodesImpl((SLogicNode*)nodesListGetNode(pNode->pChildren, 0), groupSort, pSort,
17,257✔
2459
                                             pNotOptimize, pSequencingNodes, keepSort);
2460
}
2461

2462

2463
static int32_t sortPriKeyOptGetSequencingNodes(SSortLogicNode* pSort, bool groupSort, SNodeList** pSequencingNodes, bool* keepSort) {
145,755✔
2464
  bool    notOptimize = false;
145,755✔
2465
  int32_t code =
2466
      sortPriKeyOptGetSequencingNodesImpl((SLogicNode*)nodesListGetNode(pSort->node.pChildren, 0), groupSort,
145,755✔
2467
                                          pSort, &notOptimize, pSequencingNodes, keepSort);
2468
  if (TSDB_CODE_SUCCESS != code || notOptimize) {
145,755!
2469
    NODES_CLEAR_LIST(*pSequencingNodes);
25,086✔
2470
  }
2471
  return code;
145,755✔
2472
}
2473

2474
static int32_t sortPriKeyOptApply(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan, SSortLogicNode* pSort,
115,700✔
2475
                                  SNodeList* pSequencingNodes) {
2476
  EOrder order = sortPriKeyOptGetPriKeyOrder(pSort);
115,700✔
2477
  SNode* pSequencingNode = NULL;
115,700✔
2478
  FOREACH(pSequencingNode, pSequencingNodes) {
253,398!
2479
    if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pSequencingNode)) {
137,698✔
2480
      SScanLogicNode* pScan = (SScanLogicNode*)pSequencingNode;
132,641✔
2481
      if ((ORDER_DESC == order && pScan->scanSeq[0] > 0) || (ORDER_ASC == order && pScan->scanSeq[1] > 0)) {
132,641✔
2482
        TSWAP(pScan->scanSeq[0], pScan->scanSeq[1]);
18,803✔
2483
      }
2484
      pScan->node.outputTsOrder = order;
132,641✔
2485
      if (TSDB_SUPER_TABLE == pScan->tableType) {
132,641✔
2486
        pScan->scanType = SCAN_TYPE_TABLE_MERGE;
64,089✔
2487
        pScan->filesetDelimited = true;
64,089✔
2488
        pScan->node.resultDataOrder = DATA_ORDER_LEVEL_GLOBAL;
64,089✔
2489
        pScan->node.requireDataOrder = DATA_ORDER_LEVEL_GLOBAL;
64,089✔
2490
      }
2491
      pScan->sortPrimaryKey = true;
132,641✔
2492
    } else if (QUERY_NODE_LOGIC_PLAN_WINDOW == nodeType(pSequencingNode)) {
5,057!
2493
      ((SLogicNode*)pSequencingNode)->outputTsOrder = order;
5,057✔
2494
    }
2495
    optSetParentOrder(((SLogicNode*)pSequencingNode)->pParent, order, (SLogicNode*)pSort);
137,698✔
2496
  }
2497

2498
  SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pSort->node.pChildren, 0);
115,700✔
2499
  if (NULL == pSort->node.pParent) {
115,700!
2500
    TSWAP(pSort->node.pTargets, pChild->pTargets);
×
2501
  }
2502
  int32_t code = replaceLogicNode(pLogicSubplan, (SLogicNode*)pSort, pChild);
115,700✔
2503
  if (TSDB_CODE_SUCCESS == code) {
115,700!
2504
    NODES_CLEAR_LIST(pSort->node.pChildren);
115,700✔
2505
    nodesDestroyNode((SNode*)pSort);
115,700✔
2506
  }
2507
  pCxt->optimized = true;
115,700✔
2508
  return code;
115,700✔
2509
}
2510

2511
static int32_t sortPrimaryKeyOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan, SSortLogicNode* pSort) {
145,755✔
2512
  SNodeList* pSequencingNodes = NULL;
145,755✔
2513
  bool keepSort = true;
145,755✔
2514
  int32_t    code = sortPriKeyOptGetSequencingNodes(pSort, pSort->groupSort, &pSequencingNodes, &keepSort);
145,755✔
2515
  if (TSDB_CODE_SUCCESS == code) {
145,755!
2516
    if (pSequencingNodes != NULL) {
145,755✔
2517
      code = sortPriKeyOptApply(pCxt, pLogicSubplan, pSort, pSequencingNodes);
115,700✔
2518
    } else if (!keepSort) {
30,055!
2519
      SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pSort->node.pChildren, 0);
×
2520
      if (NULL == pSort->node.pParent) {
×
2521
        TSWAP(pSort->node.pTargets, pChild->pTargets);
×
2522
      }
2523
      int32_t code = replaceLogicNode(pLogicSubplan, (SLogicNode*)pSort, pChild);
×
2524
      if (TSDB_CODE_SUCCESS == code) {
×
2525
        NODES_CLEAR_LIST(pSort->node.pChildren);
×
2526
        nodesDestroyNode((SNode*)pSort);
×
2527
      }
2528
      pCxt->optimized = true;
×
2529
    } else {
2530
      // if we decided not to push down sort info to children, we should propagate output ts order to parents of pSort
2531
      optSetParentOrder(pSort->node.pParent, sortPriKeyOptGetPriKeyOrder(pSort), 0);
30,055✔
2532
      // we need to prevent this pSort from being chosen to do optimization again
2533
      pSort->skipPKSortOpt = true;
30,055✔
2534
      pCxt->optimized = true;
30,055✔
2535
    }
2536
  }
2537
  nodesClearList(pSequencingNodes);
145,755✔
2538
  return code;
145,754✔
2539
}
2540

2541
static int32_t sortPrimaryKeyOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
1,684,247✔
2542
  SSortLogicNode* pSort = (SSortLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, sortPriKeyOptMayBeOptimized, NULL);
1,684,247✔
2543
  if (NULL == pSort) {
1,684,247✔
2544
    return TSDB_CODE_SUCCESS;
1,538,492✔
2545
  }
2546
  return sortPrimaryKeyOptimizeImpl(pCxt, pLogicSubplan, pSort);
145,755✔
2547
}
2548

2549
static int32_t sortForJoinOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan, SJoinLogicNode* pJoin) {
55✔
2550
  SLogicNode* pLeft = (SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 0);
55✔
2551
  SLogicNode* pRight = (SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 1);
55✔
2552
  SScanLogicNode* pScan = NULL;
55✔
2553
  SLogicNode* pChild = NULL;
55✔
2554
  SNode** pChildPos = NULL;
55✔
2555
  EOrder targetOrder = 0;
55✔
2556
  SSHashObj* pTables = NULL;
55✔
2557
  
2558
  if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pLeft) && ((SScanLogicNode*)pLeft)->node.outputTsOrder != SCAN_ORDER_BOTH) {
55!
2559
    pScan = (SScanLogicNode*)pLeft;
5✔
2560
    pChild = pRight;
5✔
2561
    pChildPos = &pJoin->node.pChildren->pTail->pNode;
5✔
2562
    targetOrder = pScan->node.outputTsOrder;
5✔
2563
  } else if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pRight) && ((SScanLogicNode*)pRight)->node.outputTsOrder != SCAN_ORDER_BOTH) {
50!
2564
    pScan = (SScanLogicNode*)pRight;
3✔
2565
    pChild = pLeft;
3✔
2566
    pChildPos = &pJoin->node.pChildren->pHead->pNode;
3✔
2567
    targetOrder = pScan->node.outputTsOrder;
3✔
2568
  } else {
2569
    pChild = pRight;
47✔
2570
    pChildPos = &pJoin->node.pChildren->pTail->pNode;
47✔
2571
    targetOrder = pLeft->outputTsOrder;
47✔
2572
  }
2573

2574
  if (QUERY_NODE_OPERATOR != nodeType(pJoin->pPrimKeyEqCond)) {
55!
2575
    return TSDB_CODE_PLAN_INTERNAL_ERROR;
×
2576
  }
2577

2578
  bool res = false;
55✔
2579
  SOperatorNode* pOp = (SOperatorNode*)pJoin->pPrimKeyEqCond;
55✔
2580
  if (QUERY_NODE_COLUMN != nodeType(pOp->pLeft) || QUERY_NODE_COLUMN != nodeType(pOp->pRight)) {
55!
2581
    return TSDB_CODE_PLAN_INTERNAL_ERROR;
×
2582
  }
2583

2584
  SNode* pOrderByNode = NULL;
55✔
2585

2586
  int32_t code = collectTableAliasFromNodes((SNode*)pChild, &pTables);  
55✔
2587
  if (TSDB_CODE_SUCCESS != code) {
55!
2588
    return code;
×
2589
  }
2590
  if (NULL != tSimpleHashGet(pTables, ((SColumnNode*)pOp->pLeft)->tableAlias, strlen(((SColumnNode*)pOp->pLeft)->tableAlias))) {
55✔
2591
    pOrderByNode = pOp->pLeft;
3✔
2592
  } else if (NULL != tSimpleHashGet(pTables, ((SColumnNode*)pOp->pRight)->tableAlias, strlen(((SColumnNode*)pOp->pRight)->tableAlias))) {
52!
2593
    pOrderByNode = pOp->pRight;
52✔
2594
  }
2595

2596
  tSimpleHashCleanup(pTables);
55✔
2597

2598
  if (NULL == pOrderByNode) {
55!
2599
    return TSDB_CODE_PLAN_INTERNAL_ERROR;
×
2600
  }
2601

2602
  SSortLogicNode* pSort = NULL;
55✔
2603
  code = nodesMakeNode(QUERY_NODE_LOGIC_PLAN_SORT, (SNode**)&pSort);
55✔
2604
  if (NULL == pSort) {
55!
2605
    return code;
×
2606
  }
2607

2608
  pSort->node.outputTsOrder = targetOrder;
55✔
2609
  pSort->node.pTargets = NULL;
55✔
2610
  code = nodesCloneList(pChild->pTargets, &pSort->node.pTargets);
55✔
2611
  if (NULL == pSort->node.pTargets) {
55!
2612
    nodesDestroyNode((SNode *)pSort);
×
2613
    return code;
×
2614
  }
2615
  
2616
  pSort->groupSort = false;
55✔
2617
  SOrderByExprNode* pOrder = NULL;
55✔
2618
  code = nodesMakeNode(QUERY_NODE_ORDER_BY_EXPR, (SNode**)&pOrder);
55✔
2619
  if (NULL == pOrder) {
55!
2620
    nodesDestroyNode((SNode *)pSort);
×
2621
    return code;
×
2622
  }
2623

2624
  code = nodesListMakeStrictAppend(&pSort->pSortKeys, (SNode*)pOrder);
55✔
2625
  if (TSDB_CODE_SUCCESS != code) {
55!
2626
    nodesDestroyNode((SNode*)pSort);
×
2627
    return code;
×
2628
  }
2629
  pOrder->order = targetOrder;
55✔
2630
  pOrder->pExpr = NULL;
55✔
2631
  pOrder->nullOrder = (ORDER_ASC == pOrder->order) ? NULL_ORDER_FIRST : NULL_ORDER_LAST;
55✔
2632
  code = nodesCloneNode(pOrderByNode, &pOrder->pExpr);
55✔
2633
  if (!pOrder->pExpr) {
55!
2634
    nodesDestroyNode((SNode *)pSort);
×
2635
    return code;
×
2636
  }
2637

2638
  pChild->pParent = (SLogicNode*)pSort;
55✔
2639
  code = nodesListMakeAppend(&pSort->node.pChildren, (SNode*)pChild);
55✔
2640
  if (TSDB_CODE_SUCCESS != code) {
55!
2641
    return code;
×
2642
  }
2643
  *pChildPos = (SNode*)pSort;
55✔
2644
  pSort->node.pParent = (SLogicNode*)pJoin;;
55✔
2645

2646
_return:
55✔
2647

2648
  pCxt->optimized = true;
55✔
2649

2650
  return TSDB_CODE_SUCCESS;
55✔
2651
}
2652

2653

2654
static bool sortForJoinOptMayBeOptimized(SLogicNode* pNode, void* pCtx) {
6,698,713✔
2655
  if (QUERY_NODE_LOGIC_PLAN_JOIN != nodeType(pNode)) {
6,698,713✔
2656
    return false;
6,474,118✔
2657
  }
2658
  
2659
  SJoinLogicNode* pJoin = (SJoinLogicNode*)pNode;
224,595✔
2660
  if (pNode->pChildren->length != 2 || !pJoin->hasSubQuery || pJoin->isLowLevelJoin) {
224,595✔
2661
    return false;
223,530✔
2662
  }
2663

2664
  SLogicNode* pLeft = (SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 0);
1,065✔
2665
  SLogicNode* pRight = (SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 1);
1,065✔
2666

2667
  if (ORDER_ASC != pLeft->outputTsOrder && ORDER_DESC != pLeft->outputTsOrder) {
1,065✔
2668
    pLeft->outputTsOrder = ORDER_ASC;
13✔
2669
  }
2670
  if (ORDER_ASC != pRight->outputTsOrder && ORDER_DESC != pRight->outputTsOrder) {
1,065✔
2671
    pRight->outputTsOrder = ORDER_ASC;
13✔
2672
  }
2673

2674
  if (pLeft->outputTsOrder == pRight->outputTsOrder) {
1,065✔
2675
    return false;
1,010✔
2676
  }
2677

2678
  return true;
55✔
2679
}
2680

2681

2682
static int32_t sortForJoinOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
1,538,485✔
2683
  SJoinLogicNode* pJoin = (SJoinLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, sortForJoinOptMayBeOptimized, NULL);
1,538,485✔
2684
  if (NULL == pJoin) {
1,538,491✔
2685
    return TSDB_CODE_SUCCESS;
1,538,436✔
2686
  }
2687
  return sortForJoinOptimizeImpl(pCxt, pLogicSubplan, pJoin);
55✔
2688
}
2689

2690
static SScanLogicNode* joinCondGetScanNode(SLogicNode* pNode) {
263,443✔
2691
  switch (nodeType(pNode)) {
263,443!
2692
    case QUERY_NODE_LOGIC_PLAN_SCAN:
263,420✔
2693
      return (SScanLogicNode*)pNode;
263,420✔
2694
    case QUERY_NODE_LOGIC_PLAN_JOIN: {
23✔
2695
      SJoinLogicNode* pJoin = (SJoinLogicNode*)pNode;
23✔
2696
      if (JOIN_TYPE_INNER != pJoin->joinType) {
23✔
2697
        return NULL;
12✔
2698
      }
2699
      return joinCondGetScanNode((SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 0));
11✔
2700
    }
2701
    default:
×
2702
      return NULL;
×
2703
  }
2704
}
2705

2706
static int32_t joinCondGetAllScanNodes(SLogicNode* pNode, SNodeList** pList) {
15,337✔
2707
  switch (nodeType(pNode)) {
15,337!
2708
    case QUERY_NODE_LOGIC_PLAN_SCAN:
10,224✔
2709
      return nodesListMakeStrictAppend(pList, (SNode*)pNode);
10,224✔
2710
    case QUERY_NODE_LOGIC_PLAN_JOIN: {
5,113✔
2711
      SJoinLogicNode* pJoin = (SJoinLogicNode*)pNode;
5,113✔
2712
      if (JOIN_TYPE_INNER != pJoin->joinType) {
5,113!
2713
        return TSDB_CODE_SUCCESS;
×
2714
      }
2715
      int32_t code = joinCondGetAllScanNodes((SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 0), pList);
5,113✔
2716
      if (TSDB_CODE_SUCCESS == code) {
5,113!
2717
        code = joinCondGetAllScanNodes((SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 1), pList);
5,113✔
2718
      }
2719
      return code;
5,113✔
2720
    }
2721
    default:
×
2722
      return TSDB_CODE_SUCCESS;
×
2723
  }
2724
}
2725

2726

2727
static bool joinCondMayBeOptimized(SLogicNode* pNode, void* pCtx) {
7,804,635✔
2728
  if (QUERY_NODE_LOGIC_PLAN_JOIN != nodeType(pNode) || OPTIMIZE_FLAG_TEST_MASK(pNode->optimizedFlag, OPTIMIZE_FLAG_JOIN_COND)) {
7,804,635✔
2729
    return false;
7,670,959✔
2730
  }
2731
  
2732
  SJoinLogicNode* pJoin = (SJoinLogicNode*)pNode;
133,676✔
2733
  if (pNode->pChildren->length != 2 || JOIN_STYPE_ASOF == pJoin->subType || JOIN_STYPE_WIN == pJoin->subType || JOIN_TYPE_FULL == pJoin->joinType) {
133,676!
2734
    OPTIMIZE_FLAG_SET_MASK(pNode->optimizedFlag, OPTIMIZE_FLAG_JOIN_COND);
1,812✔
2735
    return false;
1,812✔
2736
  }
2737

2738
  SLogicNode* pLeft = (SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 0);
131,864✔
2739
  SLogicNode* pRight = (SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 1);
131,864✔
2740

2741
  if ((JOIN_TYPE_LEFT == pJoin->joinType || JOIN_TYPE_RIGHT == pJoin->joinType) && (QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(pLeft) || QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(pRight))) {
131,864✔
2742
    OPTIMIZE_FLAG_SET_MASK(pNode->optimizedFlag, OPTIMIZE_FLAG_JOIN_COND);
86✔
2743
    return false;
86✔
2744
  }
2745

2746
  if (JOIN_TYPE_INNER == pJoin->joinType && ((QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(pLeft) && QUERY_NODE_LOGIC_PLAN_JOIN != nodeType(pLeft)) || (QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(pRight) && QUERY_NODE_LOGIC_PLAN_JOIN != nodeType(pRight)))) {
131,778✔
2747
    OPTIMIZE_FLAG_SET_MASK(pNode->optimizedFlag, OPTIMIZE_FLAG_JOIN_COND);
221✔
2748
    return false;
221✔
2749
  }
2750

2751
  if (JOIN_TYPE_INNER == pJoin->joinType) {
131,557✔
2752
    if (QUERY_NODE_LOGIC_PLAN_JOIN == nodeType(pLeft) && !OPTIMIZE_FLAG_TEST_MASK(pLeft->optimizedFlag, OPTIMIZE_FLAG_JOIN_COND)) {
130,085✔
2753
      return false;
67✔
2754
    }
2755
    if (QUERY_NODE_LOGIC_PLAN_JOIN == nodeType(pRight) && !OPTIMIZE_FLAG_TEST_MASK(pRight->optimizedFlag, OPTIMIZE_FLAG_JOIN_COND)) {
130,018✔
2756
      return false;
4✔
2757
    }
2758
  }
2759

2760
  SScanLogicNode* pLScan = joinCondGetScanNode(pLeft);
131,486✔
2761
  SScanLogicNode* pRScan = joinCondGetScanNode(pRight);
131,486✔
2762

2763
  if (NULL == pLScan || NULL == pRScan) {
131,486!
2764
    OPTIMIZE_FLAG_SET_MASK(pNode->optimizedFlag, OPTIMIZE_FLAG_JOIN_COND);
12✔
2765
    return false;
12✔
2766
  }
2767

2768
  if (!IS_TSWINDOW_SPECIFIED(pLScan->scanRange) && !IS_TSWINDOW_SPECIFIED(pRScan->scanRange)) {
131,474✔
2769
    OPTIMIZE_FLAG_SET_MASK(pNode->optimizedFlag, OPTIMIZE_FLAG_JOIN_COND);
126,133✔
2770
    return false;
126,133✔
2771
  }
2772
  
2773
  return true;
5,341✔
2774
}
2775

2776
static void joinCondMergeScanRand(STimeWindow* pDst, STimeWindow* pSrc) {
10,454✔
2777
  if (pSrc->skey > pDst->skey) {
10,454✔
2778
    pDst->skey = pSrc->skey;
146✔
2779
  }
2780
  if (pSrc->ekey < pDst->ekey) {
10,454✔
2781
    pDst->ekey = pSrc->ekey;
5,188✔
2782
  }
2783
}
10,454✔
2784

2785
static int32_t joinCondOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
1,709,019✔
2786
  SJoinLogicNode* pJoin = (SJoinLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, joinCondMayBeOptimized, NULL);
1,709,019✔
2787
  if (NULL == pJoin) {
1,709,022✔
2788
    return TSDB_CODE_SUCCESS;
1,703,681✔
2789
  }
2790

2791
  switch (pJoin->joinType) {
5,341!
2792
    case JOIN_TYPE_INNER: {
5,111✔
2793
      SNodeList* pScanList = NULL;
5,111✔
2794
      int32_t code = joinCondGetAllScanNodes((SLogicNode*)pJoin, &pScanList);
5,111✔
2795
      if (TSDB_CODE_SUCCESS != code) {
5,111!
2796
        return code;
×
2797
      }
2798
      if (NULL == pScanList || pScanList->length <= 0) {
5,111!
2799
        nodesClearList(pScanList);
×
2800
        return TSDB_CODE_SUCCESS;
×
2801
      }
2802
      SNode* pNode = NULL;
5,111✔
2803
      STimeWindow   scanRange = TSWINDOW_INITIALIZER;
5,111✔
2804
      FOREACH(pNode, pScanList) {
15,335!
2805
        joinCondMergeScanRand(&scanRange, &((SScanLogicNode*)pNode)->scanRange);
10,224✔
2806
      }
2807
      FOREACH(pNode, pScanList) {
15,335!
2808
        ((SScanLogicNode*)pNode)->scanRange.skey = scanRange.skey;
10,224✔
2809
        ((SScanLogicNode*)pNode)->scanRange.ekey = scanRange.ekey;
10,224✔
2810
      }
2811
      nodesClearList(pScanList);
5,111✔
2812
      break;
5,111✔
2813
    }
2814
    case JOIN_TYPE_LEFT: {
118✔
2815
      SLogicNode* pLeft = (SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 0);
118✔
2816
      SLogicNode* pRight = (SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 1);
118✔
2817
      SScanLogicNode* pLScan = joinCondGetScanNode(pLeft);
118✔
2818
      SScanLogicNode* pRScan = joinCondGetScanNode(pRight);
118✔
2819
      
2820
      if (NULL == pLScan || NULL == pRScan) {
118!
2821
        return TSDB_CODE_SUCCESS;
×
2822
      }
2823
      joinCondMergeScanRand(&pRScan->scanRange, &pLScan->scanRange);
118✔
2824
      break;
118✔
2825
    }
2826
    case JOIN_TYPE_RIGHT: {
112✔
2827
      SLogicNode* pLeft = (SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 0);
112✔
2828
      SLogicNode* pRight = (SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 1);
112✔
2829
      SScanLogicNode* pLScan = joinCondGetScanNode(pLeft);
112✔
2830
      SScanLogicNode* pRScan = joinCondGetScanNode(pRight);
112✔
2831
      
2832
      if (NULL == pLScan || NULL == pRScan) {
112!
2833
        return TSDB_CODE_SUCCESS;
×
2834
      }
2835
      joinCondMergeScanRand(&pLScan->scanRange, &pRScan->scanRange);
112✔
2836
      break;
112✔
2837
    }
2838
    default:
×
2839
      return TSDB_CODE_SUCCESS;
×
2840
  }
2841

2842
  OPTIMIZE_FLAG_SET_MASK(pJoin->node.optimizedFlag, OPTIMIZE_FLAG_JOIN_COND);
5,341✔
2843

2844
  pCxt->optimized = true;
5,341✔
2845

2846
  return TSDB_CODE_SUCCESS;
5,341✔
2847
}
2848

2849
static bool smaIndexOptMayBeOptimized(SLogicNode* pNode, void* pCtx) {
6,698,590✔
2850
  if (QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(pNode) || NULL == pNode->pParent ||
6,698,590✔
2851
      QUERY_NODE_LOGIC_PLAN_WINDOW != nodeType(pNode->pParent) ||
1,950,073✔
2852
      WINDOW_TYPE_INTERVAL != ((SWindowLogicNode*)pNode->pParent)->winType) {
64,065✔
2853
    return false;
6,650,823✔
2854
  }
2855

2856
  SScanLogicNode* pScan = (SScanLogicNode*)pNode;
47,767✔
2857
  if (NULL == pScan->pSmaIndexes || NULL != pScan->node.pConditions) {
47,767!
2858
    return false;
47,767✔
2859
  }
2860

2861
  return true;
×
2862
}
2863

2864
static int32_t smaIndexOptCreateSmaScan(SScanLogicNode* pScan, STableIndexInfo* pIndex, SNodeList* pCols,
×
2865
                                        SLogicNode** pOutput) {
2866
  SScanLogicNode* pSmaScan = NULL;
×
2867
  int32_t code = nodesMakeNode(QUERY_NODE_LOGIC_PLAN_SCAN, (SNode**)&pSmaScan);
×
2868
  if (NULL == pSmaScan) {
×
2869
    return code;
×
2870
  }
2871
  pSmaScan->pScanCols = pCols;
×
2872
  pSmaScan->tableType = TSDB_SUPER_TABLE;
×
2873
  pSmaScan->tableId = pIndex->dstTbUid;
×
2874
  pSmaScan->stableId = pIndex->dstTbUid;
×
2875
  pSmaScan->scanType = SCAN_TYPE_TABLE;
×
2876
  pSmaScan->scanSeq[0] = pScan->scanSeq[0];
×
2877
  pSmaScan->scanSeq[1] = pScan->scanSeq[1];
×
2878
  pSmaScan->scanRange = pScan->scanRange;
×
2879
  pSmaScan->dataRequired = FUNC_DATA_REQUIRED_DATA_LOAD;
×
2880

2881
  pSmaScan->pVgroupList = taosMemoryCalloc(1, sizeof(SVgroupsInfo) + sizeof(SVgroupInfo));
×
2882
  if (!pSmaScan->pVgroupList) {
×
2883
    nodesDestroyNode((SNode*)pSmaScan);
×
2884
    return terrno;
×
2885
  }
2886
  code = nodesCloneList(pCols, &pSmaScan->node.pTargets);
×
2887
  if (NULL == pSmaScan->node.pTargets) {
×
2888
    nodesDestroyNode((SNode*)pSmaScan);
×
2889
    return code;
×
2890
  }
2891
  pSmaScan->pVgroupList->numOfVgroups = 1;
×
2892
  pSmaScan->pVgroupList->vgroups[0].vgId = pIndex->dstVgId;
×
2893
  memcpy(&(pSmaScan->pVgroupList->vgroups[0].epSet), &pIndex->epSet, sizeof(SEpSet));
×
2894

2895
  *pOutput = (SLogicNode*)pSmaScan;
×
2896
  return TSDB_CODE_SUCCESS;
×
2897
}
2898

2899
static bool smaIndexOptEqualInterval(SScanLogicNode* pScan, SWindowLogicNode* pWindow, STableIndexInfo* pIndex) {
×
2900
  if (pWindow->interval != pIndex->interval || pWindow->intervalUnit != pIndex->intervalUnit ||
×
2901
      pWindow->offset != pIndex->offset || pWindow->sliding != pIndex->sliding ||
×
2902
      pWindow->slidingUnit != pIndex->slidingUnit) {
×
2903
    return false;
×
2904
  }
2905
  if (IS_TSWINDOW_SPECIFIED(pScan->scanRange)) {
×
2906
    SInterval interval = {.interval = pIndex->interval,
×
2907
                          .intervalUnit = pIndex->intervalUnit,
×
2908
                          .offset = pIndex->offset,
×
2909
                          .offsetUnit = TIME_UNIT_MILLISECOND,
2910
                          .sliding = pIndex->sliding,
×
2911
                          .slidingUnit = pIndex->slidingUnit,
×
2912
                          .precision = pScan->node.precision};
×
2913
    return (pScan->scanRange.skey == taosTimeTruncate(pScan->scanRange.skey, &interval)) &&
×
2914
           (pScan->scanRange.ekey + 1 == taosTimeTruncate(pScan->scanRange.ekey + 1, &interval));
×
2915
  }
2916
  return true;
×
2917
}
2918

2919
static int32_t smaIndexOptCreateSmaCol(SNode* pFunc, uint64_t tableId, int32_t colId, SColumnNode** ppNode) {
×
2920
  SColumnNode* pCol = NULL;
×
2921
  int32_t code = nodesMakeNode(QUERY_NODE_COLUMN, (SNode**)&pCol);
×
2922
  if (NULL == pCol) {
×
2923
    return code;
×
2924
  }
2925
  pCol->tableId = tableId;
×
2926
  pCol->tableType = TSDB_SUPER_TABLE;
×
2927
  pCol->colId = colId;
×
2928
  pCol->colType = COLUMN_TYPE_COLUMN;
×
2929
  strcpy(pCol->colName, ((SExprNode*)pFunc)->aliasName);
×
2930
  pCol->node.resType = ((SExprNode*)pFunc)->resType;
×
2931
  strcpy(pCol->node.aliasName, ((SExprNode*)pFunc)->aliasName);
×
2932
  *ppNode = pCol;
×
2933
  return code;
×
2934
}
2935

2936
static int32_t smaIndexOptFindSmaFunc(SNode* pQueryFunc, SNodeList* pSmaFuncs) {
×
2937
  int32_t index = 0;
×
2938
  SNode*  pSmaFunc = NULL;
×
2939
  FOREACH(pSmaFunc, pSmaFuncs) {
×
2940
    if (nodesEqualNode(pQueryFunc, pSmaFunc)) {
×
2941
      return index;
×
2942
    }
2943
    ++index;
×
2944
  }
2945
  return -1;
×
2946
}
2947

2948
static SNode* smaIndexOptFindWStartFunc(SNodeList* pSmaFuncs) {
×
2949
  SNode* pSmaFunc = NULL;
×
2950
  FOREACH(pSmaFunc, pSmaFuncs) {
×
2951
    if (QUERY_NODE_FUNCTION == nodeType(pSmaFunc) && FUNCTION_TYPE_WSTART == ((SFunctionNode*)pSmaFunc)->funcType) {
×
2952
      return pSmaFunc;
×
2953
    }
2954
  }
2955
  return NULL;
×
2956
}
2957

2958
static int32_t smaIndexOptCreateSmaCols(SNodeList* pFuncs, uint64_t tableId, SNodeList* pSmaFuncs,
×
2959
                                        SNodeList** pOutput) {
2960
  SNodeList* pCols = NULL;
×
2961
  SNode*     pFunc = NULL;
×
2962
  int32_t    code = TSDB_CODE_SUCCESS;
×
2963
  int32_t    index = 0;
×
2964
  int32_t    smaFuncIndex = -1;
×
2965
  bool       hasWStart = false;
×
2966
  FOREACH(pFunc, pFuncs) {
×
2967
    smaFuncIndex = smaIndexOptFindSmaFunc(pFunc, pSmaFuncs);
×
2968
    if (smaFuncIndex < 0) {
×
2969
      break;
×
2970
    } else {
2971
      SColumnNode* pCol = NULL;
×
2972
      code = smaIndexOptCreateSmaCol(pFunc, tableId, smaFuncIndex + 1, &pCol);
×
2973
      if (TSDB_CODE_SUCCESS != code) {
×
2974
        break;
×
2975
      }
2976
      code = nodesListMakeStrictAppend(&pCols, (SNode*)pCol);
×
2977
      if (TSDB_CODE_SUCCESS != code) {
×
2978
        break;
×
2979
      }
2980
      if (!hasWStart) {
×
2981
        if (PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pCols->pTail->pNode)->colId) {
×
2982
          hasWStart = true;
×
2983
        }
2984
      }
2985
    }
2986
    ++index;
×
2987
  }
2988

2989
  if (TSDB_CODE_SUCCESS == code && smaFuncIndex >= 0) {
×
2990
    if (!hasWStart) {
×
2991
      SNode* pWsNode = smaIndexOptFindWStartFunc(pSmaFuncs);
×
2992
      if (!pWsNode) {
×
2993
        nodesDestroyList(pCols);
×
2994
        code = TSDB_CODE_APP_ERROR;
×
2995
        qError("create sma cols failed since %s(_wstart not exist)", tstrerror(code));
×
2996
        return code;
×
2997
      }
2998
      SExprNode exprNode;
2999
      exprNode.resType = ((SExprNode*)pWsNode)->resType;
×
3000
      sprintf(exprNode.aliasName, "#expr_%d", index + 1);
×
3001
      SColumnNode* pkNode = NULL;
×
3002
      code = smaIndexOptCreateSmaCol((SNode*)&exprNode, tableId, PRIMARYKEY_TIMESTAMP_COL_ID, &pkNode);
×
3003
      if (TSDB_CODE_SUCCESS != code) {
×
3004
        nodesDestroyList(pCols);
×
3005
        return code;
×
3006
      }
3007
      code = nodesListPushFront(pCols, (SNode*)pkNode);
×
3008
      if (TSDB_CODE_SUCCESS != code) {
×
3009
        nodesDestroyNode((SNode*)pkNode);
×
3010
        nodesDestroyList(pCols);
×
3011
        return code;
×
3012
      }
3013
    }
3014
    *pOutput = pCols;
×
3015
  } else {
3016
    nodesDestroyList(pCols);
×
3017
  }
3018

3019
  return code;
×
3020
}
3021

3022
static int32_t smaIndexOptCouldApplyIndex(SScanLogicNode* pScan, STableIndexInfo* pIndex, SNodeList** pCols) {
×
3023
  SWindowLogicNode* pWindow = (SWindowLogicNode*)pScan->node.pParent;
×
3024
  if (!smaIndexOptEqualInterval(pScan, pWindow, pIndex)) {
×
3025
    return TSDB_CODE_SUCCESS;
×
3026
  }
3027
  SNodeList* pSmaFuncs = NULL;
×
3028
  int32_t    code = nodesStringToList(pIndex->expr, &pSmaFuncs);
×
3029
  if (TSDB_CODE_SUCCESS == code) {
×
3030
    code = smaIndexOptCreateSmaCols(pWindow->pFuncs, pIndex->dstTbUid, pSmaFuncs, pCols);
×
3031
  }
3032
  nodesDestroyList(pSmaFuncs);
×
3033
  return code;
×
3034
}
3035

3036
static int32_t smaIndexOptApplyIndex(SLogicSubplan* pLogicSubplan, SScanLogicNode* pScan, STableIndexInfo* pIndex,
×
3037
                                     SNodeList* pSmaCols) {
3038
  SLogicNode* pSmaScan = NULL;
×
3039
  int32_t     code = smaIndexOptCreateSmaScan(pScan, pIndex, pSmaCols, &pSmaScan);
×
3040
  if (TSDB_CODE_SUCCESS == code) {
×
3041
    code = replaceLogicNode(pLogicSubplan, pScan->node.pParent, pSmaScan);
×
3042
  }
3043
  if (TSDB_CODE_SUCCESS == code) {
×
3044
    nodesDestroyNode((SNode*)pScan->node.pParent);
×
3045
  }
3046
  return code;
×
3047
}
3048

3049
static int32_t smaIndexOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan, SScanLogicNode* pScan) {
×
3050
  int32_t code = TSDB_CODE_SUCCESS;
×
3051
  int32_t nindexes = taosArrayGetSize(pScan->pSmaIndexes);
×
3052
  for (int32_t i = 0; i < nindexes; ++i) {
×
3053
    STableIndexInfo* pIndex = taosArrayGet(pScan->pSmaIndexes, i);
×
3054
    SNodeList*       pSmaCols = NULL;
×
3055
    code = smaIndexOptCouldApplyIndex(pScan, pIndex, &pSmaCols);
×
3056
    if (TSDB_CODE_SUCCESS == code && NULL != pSmaCols) {
×
3057
      code = smaIndexOptApplyIndex(pLogicSubplan, pScan, pIndex, pSmaCols);
×
3058
      pCxt->optimized = true;
×
3059
      break;
×
3060
    }
3061
  }
3062
  return code;
×
3063
}
3064

3065
static int32_t smaIndexOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
1,538,429✔
3066
  SScanLogicNode* pScan = (SScanLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, smaIndexOptMayBeOptimized, NULL);
1,538,429✔
3067
  if (NULL == pScan) {
1,538,435!
3068
    return TSDB_CODE_SUCCESS;
1,538,435✔
3069
  }
3070
  return smaIndexOptimizeImpl(pCxt, pLogicSubplan, pScan);
×
3071
}
3072

3073
static EDealRes partTagsOptHasTbname(SNode* pNode, void* pContext) {
2,560✔
3074
  if (QUERY_NODE_COLUMN == nodeType(pNode)) {
2,560✔
3075
    if (COLUMN_TYPE_TBNAME == ((SColumnNode*)pNode)->colType) {
1,271✔
3076
      *(bool*)pContext = true;
240✔
3077
      return DEAL_RES_END;
240✔
3078
    }
3079
  }
3080
  return DEAL_RES_CONTINUE;
2,320✔
3081
}
3082

3083
static bool planOptNodeListHasTbname(SNodeList* pKeys) {
1,072✔
3084
  bool hasCol = false;
1,072✔
3085
  nodesWalkExprs(pKeys, partTagsOptHasTbname, &hasCol);
1,072✔
3086
  return hasCol;
1,072✔
3087
}
3088

3089
static bool partTagsIsOptimizableNode(SLogicNode* pNode) {
5,930,218✔
3090
  bool ret = 1 == LIST_LENGTH(pNode->pChildren) &&
4,240,100✔
3091
             QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(nodesListGetNode(pNode->pChildren, 0)) &&
11,570,394✔
3092
             SCAN_TYPE_TAG != ((SScanLogicNode*)nodesListGetNode(pNode->pChildren, 0))->scanType;
1,400,060✔
3093
  if (!ret) return ret;
5,930,234✔
3094
  switch (nodeType(pNode)) {
1,399,565✔
3095
    case QUERY_NODE_LOGIC_PLAN_PARTITION: {
84,055✔
3096
      if (pNode->pParent) {
84,055✔
3097
        if (nodeType(pNode->pParent) == QUERY_NODE_LOGIC_PLAN_WINDOW) {
84,053✔
3098
          SWindowLogicNode* pWindow = (SWindowLogicNode*)pNode->pParent;
16,062✔
3099
          if (pWindow->winType == WINDOW_TYPE_INTERVAL) {
16,062✔
3100
            // if interval has slimit, we push down partition node to scan, and scan will set groupOrderScan to true
3101
            //   we want to skip groups of blocks after slimit satisfied
3102
            // if interval only has limit, we do not push down partition node to scan
3103
            //   we want to get grouped output from partition node and make use of limit
3104
            // if no slimit and no limit, we push down partition node and groupOrderScan is false, cause we do not need
3105
            //   group ordered output
3106
            if (!pWindow->node.pSlimit && pWindow->node.pLimit) ret = false;
11,738✔
3107
          }
3108
        } else if (nodeType(pNode->pParent) == QUERY_NODE_LOGIC_PLAN_JOIN) {
67,991✔
3109
          ret = false;
1,636✔
3110
        }
3111
      }
3112
    } break;
84,055✔
3113
    case QUERY_NODE_LOGIC_PLAN_AGG: {
666,757✔
3114
      SAggLogicNode* pAgg = (SAggLogicNode*)pNode;
666,757✔
3115
      ret = pAgg->pGroupKeys && pAgg->pAggFuncs;
666,757✔
3116
    } break;
666,757✔
3117
    default:
648,753✔
3118
      ret = false;
648,753✔
3119
      break;
648,753✔
3120
  }
3121
  return ret;
1,399,565✔
3122
}
3123

3124
static SNodeList* partTagsGetPartKeys(SLogicNode* pNode) {
161,049✔
3125
  if (QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pNode)) {
161,049✔
3126
    return ((SPartitionLogicNode*)pNode)->pPartitionKeys;
81,176✔
3127
  } else {
3128
    return ((SAggLogicNode*)pNode)->pGroupKeys;
79,873✔
3129
  }
3130
}
3131

3132
static SNodeList* partTagsGetFuncs(SLogicNode* pNode) {
145,429✔
3133
  if (QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pNode)) {
145,429✔
3134
    return NULL;
75,368✔
3135
  } else {
3136
    return ((SAggLogicNode*)pNode)->pAggFuncs;
70,061✔
3137
  }
3138
}
3139

3140
static bool partTagsOptAreSupportedFuncs(SNodeList* pFuncs) {
145,429✔
3141
  SNode* pFunc = NULL;
145,429✔
3142
  FOREACH(pFunc, pFuncs) {
324,623✔
3143
    if (fmIsIndefiniteRowsFunc(((SFunctionNode*)pFunc)->funcId) && !fmIsSelectFunc(((SFunctionNode*)pFunc)->funcId)) {
179,194!
3144
      return false;
×
3145
    }
3146
  }
3147
  return true;
145,429✔
3148
}
3149

3150
static bool partTagsOptMayBeOptimized(SLogicNode* pNode, void* pCtx) {
5,930,219✔
3151
  if (!partTagsIsOptimizableNode(pNode)) {
5,930,219✔
3152
    return false;
5,769,178✔
3153
  }
3154

3155
  return !keysHasCol(partTagsGetPartKeys(pNode)) && partTagsOptAreSupportedFuncs(partTagsGetFuncs(pNode));
161,049!
3156
}
3157

3158
static int32_t partTagsOptRebuildTbanme(SNodeList* pPartKeys) {
145,429✔
3159
  int32_t code = TSDB_CODE_SUCCESS;
145,429✔
3160
  nodesRewriteExprs(pPartKeys, optRebuildTbanme, &code);
145,429✔
3161
  return code;
145,429✔
3162
}
3163

3164
// todo refact: just to mask compilation warnings
3165
static void partTagsSetAlias(char* pAlias, const char* pTableAlias, const char* pColName) {
9,766✔
3166
  char    name[TSDB_COL_FNAME_LEN + 1] = {0};
9,766✔
3167
  int32_t len = tsnprintf(name, TSDB_COL_FNAME_LEN, "%s.%s", pTableAlias, pColName);
9,766✔
3168

3169
  (void)taosHashBinary(name, len);
3170
  strncpy(pAlias, name, TSDB_COL_NAME_LEN - 1);
9,766✔
3171
}
9,766✔
3172

3173
static int32_t partTagsCreateWrapperFunc(const char* pFuncName, SNode* pNode, SFunctionNode** ppNode) {
52,569✔
3174
  SNode*         pNew = NULL;
52,569✔
3175
  SFunctionNode* pFunc = NULL;
52,569✔
3176
  int32_t        code = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&pFunc);
52,569✔
3177
  if (NULL == pFunc) {
52,569!
3178
    return code;
×
3179
  }
3180

3181
  snprintf(pFunc->functionName, sizeof(pFunc->functionName), "%s", pFuncName);
52,569✔
3182
  if ((QUERY_NODE_COLUMN == nodeType(pNode) && COLUMN_TYPE_TBNAME != ((SColumnNode*)pNode)->colType) ||
52,569✔
3183
   (QUERY_NODE_COLUMN == nodeType(pNode) && COLUMN_TYPE_TBNAME == ((SColumnNode*)pNode)->colType &&
43,895!
3184
   ((SColumnNode*)pNode)->tableAlias[0] != '\0')){
53,104✔
3185
    SColumnNode* pCol = (SColumnNode*)pNode;
9,766✔
3186
    partTagsSetAlias(pFunc->node.aliasName, pCol->tableAlias, pCol->colName);
9,766✔
3187
  } else {
3188
    strcpy(pFunc->node.aliasName, ((SExprNode*)pNode)->aliasName);
42,803✔
3189
  }
3190
  code = nodesCloneNode(pNode, &pNew);
52,569✔
3191
  if (TSDB_CODE_SUCCESS == code) {
52,569!
3192
    code = nodesListMakeStrictAppend(&pFunc->pParameterList, pNew);
52,569✔
3193
  }
3194
  if (TSDB_CODE_SUCCESS == code) {
52,569!
3195
    code = fmGetFuncInfo(pFunc, NULL, 0);
52,569✔
3196
  }
3197

3198
  if (TSDB_CODE_SUCCESS != code) {
52,569!
3199
    nodesDestroyNode((SNode*)pFunc);
×
3200
    return code;
×
3201
  }
3202
  *ppNode = pFunc;
52,569✔
3203
  return code;
52,569✔
3204
}
3205

3206
static bool partTagsHasIndefRowsSelectFunc(SNodeList* pFuncs) {
70,086✔
3207
  SNode* pFunc = NULL;
70,086✔
3208
  FOREACH(pFunc, pFuncs) {
249,305!
3209
    if (fmIsIndefiniteRowsFunc(((SFunctionNode*)pFunc)->funcId)) {
179,219!
3210
      return true;
×
3211
    }
3212
  }
3213
  return false;
70,086✔
3214
}
3215

3216
static bool partTagsNeedOutput(SNode* pExpr, SNodeList* pTargets) {
76,533✔
3217
  SNode* pOutput = NULL;
76,533✔
3218
  FOREACH(pOutput, pTargets) {
312,122!
3219
    if (QUERY_NODE_COLUMN == nodeType(pExpr)) {
288,158✔
3220
      if (nodesEqualNode(pExpr, pOutput)) {
285,762✔
3221
        return true;
52,012✔
3222
      }
3223
    } else if (0 == strcmp(((SExprNode*)pExpr)->aliasName, ((SColumnNode*)pOutput)->colName)) {
2,396✔
3224
      return true;
557✔
3225
    }
3226
  }
3227
  return false;
23,964✔
3228
}
3229

3230
static int32_t partTagsRewriteGroupTagsToFuncs(SNodeList* pGroupTags, int32_t start, SAggLogicNode* pAgg) {
70,086✔
3231
  bool    hasIndefRowsSelectFunc = partTagsHasIndefRowsSelectFunc(pAgg->pAggFuncs);
70,086✔
3232
  int32_t code = TSDB_CODE_SUCCESS;
70,086✔
3233
  int32_t index = 0;
70,086✔
3234
  SNode*  pNode = NULL;
70,086✔
3235
  FOREACH(pNode, pGroupTags) {
146,619✔
3236
    if (index++ < start || !partTagsNeedOutput(pNode, pAgg->node.pTargets)) {
76,533!
3237
      continue;
23,964✔
3238
    }
3239
    SFunctionNode* pFunc = NULL;
52,569✔
3240
    if (hasIndefRowsSelectFunc) {
52,569!
3241
      code = partTagsCreateWrapperFunc("_select_value", pNode, &pFunc);
×
3242
      if (TSDB_CODE_SUCCESS == code) {
×
3243
        code = nodesListStrictAppend(pAgg->pAggFuncs, (SNode*)pFunc);
×
3244
      }
3245
    } else {
3246
      code = partTagsCreateWrapperFunc("_group_key", pNode, &pFunc);
52,569✔
3247
      if (TSDB_CODE_SUCCESS == code) {
52,569!
3248
        code = nodesListStrictAppend(pAgg->pAggFuncs, (SNode*)pFunc);
52,569✔
3249
      }
3250
    }
3251
    if (TSDB_CODE_SUCCESS != code) {
52,569!
3252
      break;
×
3253
    }
3254
  }
3255
  return code;
70,086✔
3256
}
3257

3258
static int32_t partTagsOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
1,454,068✔
3259
  SLogicNode* pNode = optFindPossibleNode(pLogicSubplan->pNode, partTagsOptMayBeOptimized, NULL);
1,454,068✔
3260
  if (NULL == pNode) {
1,454,076✔
3261
    return TSDB_CODE_SUCCESS;
1,308,648✔
3262
  }
3263

3264
  int32_t         code = TSDB_CODE_SUCCESS;
145,428✔
3265
  SScanLogicNode* pScan = (SScanLogicNode*)nodesListGetNode(pNode->pChildren, 0);
145,428✔
3266
  if (QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pNode)) {
145,429✔
3267
    TSWAP(((SPartitionLogicNode*)pNode)->pPartitionKeys, pScan->pGroupTags);
75,368✔
3268
    TSWAP(((SPartitionLogicNode*)pNode)->pTags, pScan->pTags);
75,368✔
3269
    TSWAP(((SPartitionLogicNode*)pNode)->pSubtable, pScan->pSubtable);
75,368✔
3270
    int32_t code = replaceLogicNode(pLogicSubplan, pNode, (SLogicNode*)pScan);
75,368✔
3271
    if (TSDB_CODE_SUCCESS == code) {
75,368!
3272
      code = adjustLogicNodeDataRequirement((SLogicNode*)pScan, pNode->resultDataOrder);
75,368✔
3273
    }
3274
    if (TSDB_CODE_SUCCESS == code) {
75,368!
3275
      if (QUERY_NODE_LOGIC_PLAN_AGG == pNode->pParent->type) {
75,368✔
3276
        SAggLogicNode* pParent = (SAggLogicNode*)(pNode->pParent);
51,811✔
3277
        scanPathOptSetGroupOrderScan(pScan);
51,811✔
3278
        pParent->hasGroupKeyOptimized = true;
51,811✔
3279
      }
3280
      if (pNode->pParent->pSlimit) pScan->groupOrderScan = true;
75,368✔
3281

3282
      NODES_CLEAR_LIST(pNode->pChildren);
75,368✔
3283
      nodesDestroyNode((SNode*)pNode);
75,368✔
3284
    }
3285
  } else {
3286
    SAggLogicNode* pAgg = (SAggLogicNode*)pNode;
70,061✔
3287
    int32_t        start = -1;
70,061✔
3288
    SNode*         pGroupKey = NULL;
70,061✔
3289
    FOREACH(pGroupKey, pAgg->pGroupKeys) {
146,571!
3290
      SNode* pGroupExpr = nodesListGetNode(((SGroupingSetNode*)pGroupKey)->pParameterList, 0);
76,510✔
3291
      if (NULL != pScan->pGroupTags) {
76,510✔
3292
        SNode* pGroupTag = NULL;
6,449✔
3293
        FOREACH(pGroupTag, pScan->pGroupTags) {
15,899!
3294
          if (nodesEqualNode(pGroupTag, pGroupExpr)) {
9,450✔
3295
            continue;
557✔
3296
          }
3297
        }
3298
      }
3299
      if (start < 0) {
76,510✔
3300
        start = LIST_LENGTH(pScan->pGroupTags);
70,061!
3301
      }
3302
      SNode* pNew = NULL;
76,510✔
3303
      code = nodesCloneNode(pGroupExpr, &pNew);
76,510✔
3304
      if (TSDB_CODE_SUCCESS == code) {
76,510!
3305
        code = nodesListMakeStrictAppend(&pScan->pGroupTags, pNew);
76,510✔
3306
      }
3307
      if (TSDB_CODE_SUCCESS != code) {
76,510!
3308
        break;
×
3309
      }
3310
    }
3311
    pAgg->hasGroupKeyOptimized = true;
70,061✔
3312

3313
    NODES_DESTORY_LIST(pAgg->pGroupKeys);
70,061✔
3314
    if (TSDB_CODE_SUCCESS == code && start >= 0) {
70,061!
3315
      code = partTagsRewriteGroupTagsToFuncs(pScan->pGroupTags, start, pAgg);
70,061✔
3316
    }
3317
  }
3318
  if (TSDB_CODE_SUCCESS == code) {
145,429!
3319
    code = partTagsOptRebuildTbanme(pScan->pGroupTags);
145,429✔
3320
  }
3321

3322
  pCxt->optimized = true;
145,429✔
3323
  return code;
145,429✔
3324
}
3325

3326
static int32_t eliminateProjOptCheckProjColumnNames(SProjectLogicNode* pProjectNode, bool* pRet) {
379,417✔
3327
  int32_t   code = 0;
379,417✔
3328
  SHashObj* pProjColNameHash = taosHashInit(16, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
379,417✔
3329
  SNode*    pProjection;
3330
  FOREACH(pProjection, pProjectNode->pProjections) {
2,002,489!
3331
    char*    projColumnName = ((SColumnNode*)pProjection)->colName;
1,631,253✔
3332
    int32_t* pExist = taosHashGet(pProjColNameHash, projColumnName, strlen(projColumnName));
1,631,253✔
3333
    if (NULL != pExist) {
1,631,245✔
3334
      taosHashCleanup(pProjColNameHash);
8,187✔
3335
      return false;
8,187✔
3336
    } else {
3337
      int32_t exist = 1;
1,623,058✔
3338
      code = taosHashPut(pProjColNameHash, projColumnName, strlen(projColumnName), &exist, sizeof(exist));
1,623,058✔
3339
      if (TSDB_CODE_SUCCESS != code) {
1,623,070!
3340
        break;
×
3341
      }
3342
    }
3343
  }
3344
  taosHashCleanup(pProjColNameHash);
371,236✔
3345
  *pRet = true;
371,231✔
3346
  return code;
371,231✔
3347
}
3348

3349
static bool eliminateProjOptMayBeOptimized(SLogicNode* pNode, void* pCtx) {
3,097,679✔
3350
  // Super table scan requires project operator to merge packets to improve performance.
3351
  if (NULL == pNode->pParent && (QUERY_NODE_LOGIC_PLAN_PROJECT != nodeType(pNode) || 1 != LIST_LENGTH(pNode->pChildren) ||
3,097,679✔
3352
      (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(nodesListGetNode(pNode->pChildren, 0)) &&
720,649✔
3353
       TSDB_SUPER_TABLE == ((SScanLogicNode*)nodesListGetNode(pNode->pChildren, 0))->tableType))) {
261,845✔
3354
    return false;
507,170✔
3355
  }
3356

3357
  if (OPTIMIZE_FLAG_TEST_MASK(pNode->optimizedFlag, OPTIMIZE_FLAG_ELIMINATE_PROJ)) {
2,590,518✔
3358
    return false;
7,068✔
3359
  }
3360

3361
  if (NULL != pNode->pParent && (QUERY_NODE_LOGIC_PLAN_PROJECT != nodeType(pNode) || 1 != LIST_LENGTH(pNode->pChildren) ||
2,583,450✔
3362
      QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(nodesListGetNode(pNode->pChildren, 0)) || QUERY_NODE_LOGIC_PLAN_JOIN != nodeType(pNode->pParent))) {
303,365✔
3363
    return false;
1,955,821✔
3364
  }  
3365

3366
  if (QUERY_NODE_LOGIC_PLAN_PROJECT != nodeType(pNode) || 1 != LIST_LENGTH(pNode->pChildren)) {
627,629!
3367
    return false;
×
3368
  }
3369
  
3370
  if (QUERY_NODE_LOGIC_PLAN_DYN_QUERY_CTRL == nodeType(nodesListGetNode(pNode->pChildren, 0))) {
627,631✔
3371
    SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pNode->pChildren, 0);
74✔
3372
    if(LIST_LENGTH(pChild->pTargets) != LIST_LENGTH(pNode->pTargets)) {
75!
3373
      return false;
67✔
3374
    }
3375
  }
3376

3377
  SProjectLogicNode* pProjectNode = (SProjectLogicNode*)pNode;
627,562✔
3378
  if (NULL != pProjectNode->node.pLimit || NULL != pProjectNode->node.pSlimit ||
627,562✔
3379
      NULL != pProjectNode->node.pConditions) {
577,473✔
3380
    return false;
50,090✔
3381
  }
3382

3383
  SNode* pProjection;
3384
  FOREACH(pProjection, pProjectNode->pProjections) {
2,370,469!
3385
    SExprNode* pExprNode = (SExprNode*)pProjection;
1,991,056✔
3386
    if (QUERY_NODE_COLUMN != nodeType(pExprNode)) {
1,991,056✔
3387
      return false;
198,058✔
3388
    }
3389
    SColumnNode* pCol = (SColumnNode*)pExprNode;
1,792,998✔
3390
    if (NULL != pNode->pParent && 0 != strcmp(pCol->colName, pCol->node.aliasName)) {
1,792,998✔
3391
      return false;
1✔
3392
    }
3393
  }
3394
  int32_t* pCode = pCtx;
379,413✔
3395
  bool     ret = false;
379,413✔
3396
  int32_t  code = eliminateProjOptCheckProjColumnNames(pProjectNode, &ret);
379,413✔
3397
  if (TSDB_CODE_SUCCESS != code) {
379,418!
3398
    *pCode = code;
×
3399
  }
3400
  return ret;
379,418✔
3401
}
3402

3403
typedef struct CheckNewChildTargetsCxt {
3404
  SNodeList* pNewChildTargets;
3405
  bool       canUse;
3406
} CheckNewChildTargetsCxt;
3407

3408
static EDealRes eliminateProjOptCanUseNewChildTargetsImpl(SNode* pNode, void* pContext) {
97,011✔
3409
  if (QUERY_NODE_COLUMN == nodeType(pNode)) {
97,011✔
3410
    CheckNewChildTargetsCxt* pCxt = pContext;
32,450✔
3411
    SNode*                   pTarget = NULL;
32,450✔
3412
    FOREACH(pTarget, pCxt->pNewChildTargets) {
107,896✔
3413
      if (nodesEqualNode(pTarget, pNode)) {
101,782✔
3414
        pCxt->canUse = true;
26,336✔
3415
        return DEAL_RES_CONTINUE;
26,336✔
3416
      }
3417
    }
3418
    pCxt->canUse = false;
6,114✔
3419
    return DEAL_RES_END;
6,114✔
3420
  }
3421
  return DEAL_RES_CONTINUE;
64,561✔
3422
}
3423

3424
static bool eliminateProjOptCanChildConditionUseChildTargets(SLogicNode* pChild, SNodeList* pNewChildTargets) {
370,879✔
3425
  if (NULL != pChild->pConditions) {
370,879✔
3426
    CheckNewChildTargetsCxt cxt = {.pNewChildTargets = pNewChildTargets, .canUse = false};
24,290✔
3427
    nodesWalkExpr(pChild->pConditions, eliminateProjOptCanUseNewChildTargetsImpl, &cxt);
24,290✔
3428
    if (!cxt.canUse) return false;
24,290✔
3429
  }
3430

3431
  if (QUERY_NODE_LOGIC_PLAN_JOIN == nodeType(pChild) && ((SJoinLogicNode*)pChild)->joinAlgo != JOIN_ALGO_UNKNOWN) {
364,765!
3432
    return false;
810✔
3433
  }  
3434
  if (QUERY_NODE_LOGIC_PLAN_JOIN == nodeType(pChild) && ((SJoinLogicNode*)pChild)->pFullOnCond) {
363,955!
3435
    SJoinLogicNode*         pJoinLogicNode = (SJoinLogicNode*)pChild;
×
3436
    CheckNewChildTargetsCxt cxt = {.pNewChildTargets = pNewChildTargets, .canUse = false};
×
3437
    nodesWalkExpr(pJoinLogicNode->pFullOnCond, eliminateProjOptCanUseNewChildTargetsImpl, &cxt);
×
3438
    if (!cxt.canUse) return false;
×
3439
  }
3440
  return true;
363,955✔
3441
}
3442

3443
static void alignProjectionWithTarget(SLogicNode* pNode) {
364,181✔
3444
  if (QUERY_NODE_LOGIC_PLAN_PROJECT != pNode->type) {
364,181✔
3445
    return;
358,863✔
3446
  }
3447

3448
  SProjectLogicNode* pProjectNode = (SProjectLogicNode*)pNode;
5,318✔
3449
  SNode*             pProjection = NULL;
5,318✔
3450
  FOREACH(pProjection, pProjectNode->pProjections) {
13,510!
3451
    SNode* pTarget = NULL;
8,192✔
3452
    bool   keep = false;
8,192✔
3453
    FOREACH(pTarget, pNode->pTargets) {
12,557!
3454
      if (0 == strcmp(((SColumnNode*)pProjection)->node.aliasName, ((SColumnNode*)pTarget)->colName)) {
12,481✔
3455
        keep = true;
8,116✔
3456
        break;
8,116✔
3457
      }
3458
    }
3459
    if (!keep) {
8,192✔
3460
      (void)nodesListErase(pProjectNode->pProjections, cell);
76✔
3461
    }
3462
  }
3463
}
3464

3465
typedef struct RewriteTableAliasCxt {
3466
  char* newTableAlias;
3467
  bool  rewriteColName;
3468
} RewriteTableAliasCxt;
3469

3470
static EDealRes eliminateProjOptRewriteScanTableAlias(SNode* pNode, void* pContext) {
2,260✔
3471
  if (QUERY_NODE_COLUMN == nodeType(pNode)) {
2,260✔
3472
    SColumnNode* pCol = (SColumnNode*)pNode;
1,857✔
3473
    RewriteTableAliasCxt* pCtx = (RewriteTableAliasCxt*)pContext;
1,857✔
3474
    strncpy(pCol->tableAlias, pCtx->newTableAlias, TSDB_TABLE_NAME_LEN);
1,857✔
3475
  }
3476
  return DEAL_RES_CONTINUE;
2,260✔
3477
}
3478

3479

3480
static void eliminateProjPushdownProjIdx(SNodeList* pParentProjects, SNodeList* pChildTargets) {
350✔
3481
  SNode* pChildTarget = NULL, *pParentProject = NULL;
350✔
3482
  FOREACH(pChildTarget, pChildTargets) {
1,195!
3483
    SColumnNode* pTargetCol = (SColumnNode*)pChildTarget;
845✔
3484
    FOREACH(pParentProject, pParentProjects) {
2,103!
3485
      SExprNode* pProject = (SExprNode*)pParentProject;
2,066✔
3486
      if (0 == strcmp(pTargetCol->colName, pProject->aliasName)) {
2,066✔
3487
        pTargetCol->resIdx = pProject->projIdx;
808✔
3488
        break;
808✔
3489
      }
3490
    }
3491
  }
3492
}
350✔
3493

3494
static int32_t eliminateProjOptFindProjPrefixWithOrderCheck(SProjectLogicNode* pProj, SProjectLogicNode* pChild, SNodeList** pNewChildTargets, bool *orderMatch) {
215✔
3495
  int32_t code = 0;
215✔
3496
  SNode* pProjection = NULL, *pChildTarget = NULL;
215✔
3497
  *orderMatch = true;
215✔
3498
  FORBOTH(pProjection, pProj->pProjections, pChildTarget, pChild->node.pTargets) {
609!
3499
    if (!pProjection) break;
424!
3500
    if (0 != strcmp(((SColumnNode*)pProjection)->colName, ((SColumnNode*)pChildTarget)->colName)) {
424✔
3501
      *orderMatch = false;
30✔
3502
      break;
30✔
3503
    }
3504
    if (pNewChildTargets) {
394✔
3505
      SNode* pNew = NULL;
220✔
3506
      code = nodesCloneNode(pChildTarget, &pNew);
220✔
3507
      if (TSDB_CODE_SUCCESS == code) {
220!
3508
        code = nodesListMakeStrictAppend(pNewChildTargets, pNew);
220✔
3509
      }
3510
      if (TSDB_CODE_SUCCESS != code && pNewChildTargets) {
220!
3511
        nodesDestroyList(*pNewChildTargets);
×
3512
        *pNewChildTargets = NULL;
×
3513
        break;
×
3514
      }
3515
    }
3516
  }
3517
  return code;
215✔
3518
}
3519

3520
static int32_t eliminateProjOptPushTargetsToSetOpChildren(SProjectLogicNode* pSetOp) {
20✔
3521
  SNode*  pChildProj = NULL;
20✔
3522
  int32_t code = 0;
20✔
3523
  bool    orderMatch = false;
20✔
3524
  FOREACH(pChildProj, pSetOp->node.pChildren) {
60!
3525
    if (QUERY_NODE_LOGIC_PLAN_PROJECT == nodeType(pChildProj)) {
40!
3526
      SProjectLogicNode* pChildLogic = (SProjectLogicNode*)pChildProj;
40✔
3527
      SNodeList* pNewChildTargetsForChild = NULL;
40✔
3528
      code = eliminateProjOptFindProjPrefixWithOrderCheck(pSetOp, pChildLogic, &pNewChildTargetsForChild, &orderMatch);
40✔
3529
      if (TSDB_CODE_SUCCESS != code) break;
40!
3530
      nodesDestroyList(pChildLogic->node.pTargets);
40✔
3531
      pChildLogic->node.pTargets = pNewChildTargetsForChild;
40✔
3532
      alignProjectionWithTarget((SLogicNode*)pChildLogic);
40✔
3533
      if (pChildLogic->isSetOpProj) {
40✔
3534
        code = eliminateProjOptPushTargetsToSetOpChildren(pChildLogic);
16✔
3535
        if (TSDB_CODE_SUCCESS != code) break;
16!
3536
      }
3537
    }
3538
  }
3539
  return code;
20✔
3540
}
3541

3542
static int32_t eliminateProjOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan,
371,226✔
3543
                                         SProjectLogicNode* pProjectNode) {
3544
  SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pProjectNode->node.pChildren, 0);
371,226✔
3545
  int32_t     code = 0;
371,229✔
3546
  bool        isSetOpProj = false;
371,229✔
3547
  bool        orderMatch = false;
371,229✔
3548
  bool        sizeMatch = LIST_LENGTH(pProjectNode->pProjections) == LIST_LENGTH(pChild->pTargets);
371,229!
3549
  bool        needReplaceTargets = true;
371,229✔
3550

3551
  if (NULL == pProjectNode->node.pParent) {
371,229✔
3552
    SNodeList* pNewChildTargets = NULL;
370,877✔
3553
    SNode *    pProjection = NULL, *pChildTarget = NULL;
370,877✔
3554
    isSetOpProj =
370,877✔
3555
        QUERY_NODE_LOGIC_PLAN_PROJECT == nodeType(pChild) && ((SProjectLogicNode*)pChild)->isSetOpProj;
370,877✔
3556
    if (isSetOpProj) {
370,877✔
3557
      // For sql: select ... from (select ... union all select ...);
3558
      // When eliminating the outer proj (the outer select), we have to make sure that the outer proj projections and
3559
      // union all project targets have same columns in the same order. See detail in TD-30188
3560
      code = eliminateProjOptFindProjPrefixWithOrderCheck(pProjectNode, (SProjectLogicNode*)pChild,
175✔
3561
                                                          sizeMatch ? NULL : &pNewChildTargets, &orderMatch);
3562
      if (TSDB_CODE_SUCCESS == code && sizeMatch && orderMatch) {
175!
3563
        pNewChildTargets = pChild->pTargets;
141✔
3564
        needReplaceTargets = false;
141✔
3565
      }
3566
    } else {
3567
      FOREACH(pProjection, pProjectNode->pProjections) {
1,951,259✔
3568
        FOREACH(pChildTarget, pChild->pTargets) {
1,243,325,453!
3569
          if (0 == strcmp(((SColumnNode*)pProjection)->colName, ((SColumnNode*)pChildTarget)->colName)) {
1,243,325,449✔
3570
            SNode* pNew = NULL;
1,580,549✔
3571
            code = nodesCloneNode(pChildTarget, &pNew);
1,580,549✔
3572
            if (TSDB_CODE_SUCCESS == code) {
1,580,559!
3573
              code = nodesListMakeStrictAppend(&pNewChildTargets, pNew);
1,580,560✔
3574
            }
3575
            break;
1,580,553✔
3576
          }
3577
        }
3578
        if (TSDB_CODE_SUCCESS != code) {
1,580,557!
3579
          break;
×
3580
        }
3581
      }
3582
    }
3583
    if (TSDB_CODE_SUCCESS != code) {
370,881!
3584
      nodesDestroyList(pNewChildTargets);
×
3585
      return code;
6,948✔
3586
    }
3587

3588
    if (eliminateProjOptCanChildConditionUseChildTargets(pChild, pNewChildTargets) && (!isSetOpProj || orderMatch)) {
370,881✔
3589
      if (needReplaceTargets) {
363,931✔
3590
        nodesDestroyList(pChild->pTargets);
363,790✔
3591
        pChild->pTargets = pNewChildTargets;
363,792✔
3592
      }
3593
    } else {
3594
      if (needReplaceTargets) nodesDestroyList(pNewChildTargets);
6,949✔
3595
      OPTIMIZE_FLAG_SET_MASK(pProjectNode->node.optimizedFlag, OPTIMIZE_FLAG_ELIMINATE_PROJ);
6,948✔
3596
      pCxt->optimized = true;
6,948✔
3597
      return TSDB_CODE_SUCCESS;
6,948✔
3598
    }
3599
  } else {
3600
    RewriteTableAliasCxt cxt = {.newTableAlias = pProjectNode->stmtName, .rewriteColName = false};
352✔
3601
    SScanLogicNode* pScan = (SScanLogicNode*)pChild;
352✔
3602
    nodesWalkExprs(pScan->pScanCols, eliminateProjOptRewriteScanTableAlias, &cxt);
352✔
3603
    nodesWalkExprs(pScan->pScanPseudoCols, eliminateProjOptRewriteScanTableAlias, &cxt);    
350✔
3604
    nodesWalkExpr(pScan->node.pConditions, eliminateProjOptRewriteScanTableAlias, &cxt);
350✔
3605
    nodesWalkExprs(pChild->pTargets, eliminateProjOptRewriteScanTableAlias, &cxt);
350✔
3606
    eliminateProjPushdownProjIdx(pProjectNode->pProjections, pChild->pTargets);
350✔
3607
  }
3608
  
3609
  if (TSDB_CODE_SUCCESS == code) {
364,283✔
3610
    code = replaceLogicNode(pLogicSubplan, (SLogicNode*)pProjectNode, pChild);
364,281✔
3611
  }
3612
  if (TSDB_CODE_SUCCESS == code) {
364,283✔
3613
    if (pProjectNode->node.pHint && !pChild->pHint) TSWAP(pProjectNode->node.pHint, pChild->pHint);
364,281!
3614
    NODES_CLEAR_LIST(pProjectNode->node.pChildren);
364,281✔
3615
    nodesDestroyNode((SNode*)pProjectNode);
364,281✔
3616
    // if pChild is a project logic node, remove its projection which is not reference by its target.
3617
    if (needReplaceTargets) {
364,283✔
3618
      alignProjectionWithTarget(pChild);
364,142✔
3619
      // Since we have eliminated the outer proj, we need to push down the new targets to the children of the set operation.
3620
      if (isSetOpProj && orderMatch && !sizeMatch) code = eliminateProjOptPushTargetsToSetOpChildren((SProjectLogicNode*)pChild);
364,142!
3621
    }
3622
  }
3623
  pCxt->optimized = true;
364,283✔
3624
  return code;
364,283✔
3625
}
3626

3627
static int32_t eliminateProjOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
1,141,509✔
3628
  int32_t            code = 0;
1,141,509✔
3629
  SProjectLogicNode* pProjectNode =
3630
      (SProjectLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, eliminateProjOptMayBeOptimized, &code);
1,141,509✔
3631

3632
  if (NULL == pProjectNode) {
1,141,512✔
3633
    return TSDB_CODE_SUCCESS;
770,282✔
3634
  }
3635

3636
  return eliminateProjOptimizeImpl(pCxt, pLogicSubplan, pProjectNode);
371,230✔
3637
}
3638

3639
static bool rewriteTailOptMayBeOptimized(SLogicNode* pNode, void* pCtx) {
4,368,574✔
3640
  return QUERY_NODE_LOGIC_PLAN_INDEF_ROWS_FUNC == nodeType(pNode) && ((SIndefRowsFuncLogicNode*)pNode)->isTailFunc;
4,368,574✔
3641
}
3642

3643
static int32_t rewriteTailOptCreateOrderByExpr(SNode* pSortKey, SNode** ppNode) {
11,273✔
3644
  SOrderByExprNode* pOrder = NULL;
11,273✔
3645
  int32_t code = nodesMakeNode(QUERY_NODE_ORDER_BY_EXPR, (SNode**)&pOrder);
11,273✔
3646
  if (NULL == pOrder) {
11,273!
3647
    return code;
×
3648
  }
3649
  pOrder->order = ORDER_DESC;
11,273✔
3650
  pOrder->pExpr = NULL;
11,273✔
3651
  code = nodesCloneNode(pSortKey, &pOrder->pExpr);
11,273✔
3652
  if (NULL == pOrder->pExpr) {
11,273!
3653
    nodesDestroyNode((SNode*)pOrder);
×
3654
    return code;
×
3655
  }
3656
  *ppNode = (SNode*)pOrder;
11,273✔
3657
  return code;
11,273✔
3658
}
3659

3660
static int32_t rewriteTailOptCreateLimit(SNode* pLimit, SNode* pOffset, SNode** pOutput) {
11,273✔
3661
  SLimitNode* pLimitNode = NULL;
11,273✔
3662
  int32_t code = nodesMakeNode(QUERY_NODE_LIMIT, (SNode**)&pLimitNode);
11,273✔
3663
  if (NULL == pLimitNode) {
11,273!
3664
    return code;
×
3665
  }
3666
  pLimitNode->limit = NULL == pLimit ? -1 : ((SValueNode*)pLimit)->datum.i;
11,273!
3667
  pLimitNode->offset = NULL == pOffset ? 0 : ((SValueNode*)pOffset)->datum.i;
11,273✔
3668
  *pOutput = (SNode*)pLimitNode;
11,273✔
3669
  return TSDB_CODE_SUCCESS;
11,273✔
3670
}
3671

3672
static bool rewriteTailOptNeedGroupSort(SIndefRowsFuncLogicNode* pIndef) {
11,273✔
3673
  if (1 != LIST_LENGTH(pIndef->node.pChildren)) {
11,273!
3674
    return false;
×
3675
  }
3676
  SNode* pChild = nodesListGetNode(pIndef->node.pChildren, 0);
11,273✔
3677
  return QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pChild) ||
22,196✔
3678
         (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pChild) && NULL != ((SScanLogicNode*)pChild)->pGroupTags);
10,923✔
3679
}
3680

3681
static int32_t rewriteTailOptCreateSort(SIndefRowsFuncLogicNode* pIndef, SLogicNode** pOutput) {
11,273✔
3682
  SSortLogicNode* pSort = NULL;
11,273✔
3683
  int32_t code = nodesMakeNode(QUERY_NODE_LOGIC_PLAN_SORT, (SNode**)&pSort);
11,273✔
3684
  if (NULL == pSort) {
11,273!
3685
    return code;
×
3686
  }
3687

3688
  pSort->groupSort = rewriteTailOptNeedGroupSort(pIndef);
11,273✔
3689
  TSWAP(pSort->node.pChildren, pIndef->node.pChildren);
11,273✔
3690
  optResetParent((SLogicNode*)pSort);
11,273✔
3691
  pSort->node.precision = pIndef->node.precision;
11,273✔
3692

3693
  SFunctionNode* pTail = NULL;
11,273✔
3694
  SNode*         pFunc = NULL;
11,273✔
3695
  FOREACH(pFunc, pIndef->pFuncs) {
11,586!
3696
    if (FUNCTION_TYPE_TAIL == ((SFunctionNode*)pFunc)->funcType) {
11,586✔
3697
      pTail = (SFunctionNode*)pFunc;
11,273✔
3698
      break;
11,273✔
3699
    }
3700
  }
3701

3702
  // tail(expr, [limit, offset,] _rowts)
3703
  int32_t rowtsIndex = LIST_LENGTH(pTail->pParameterList) - 1;
11,273!
3704

3705
  SNode* pNewNode = NULL;
11,273✔
3706
  code = rewriteTailOptCreateOrderByExpr(nodesListGetNode(pTail->pParameterList, rowtsIndex), &pNewNode);
11,273✔
3707
  if (TSDB_CODE_SUCCESS == code) {
11,273!
3708
    code = nodesListMakeStrictAppend(&pSort->pSortKeys, pNewNode);
11,273✔
3709
  }
3710
  if (TSDB_CODE_SUCCESS == code) {
11,273!
3711
    code = nodesCloneList(((SLogicNode*)nodesListGetNode(pSort->node.pChildren, 0))->pTargets, &pSort->node.pTargets);
11,273✔
3712
  }
3713

3714
  if (TSDB_CODE_SUCCESS == code) {
11,273!
3715
    *pOutput = (SLogicNode*)pSort;
11,273✔
3716
  } else {
3717
    nodesDestroyNode((SNode*)pSort);
×
3718
  }
3719

3720
  return code;
11,273✔
3721
}
3722

3723
static int32_t rewriteTailOptCreateProjectExpr(SFunctionNode* pFunc, SNode** ppNode) {
11,610✔
3724
  SNode* pExpr = NULL;
11,610✔
3725
  int32_t code = nodesCloneNode(nodesListGetNode(pFunc->pParameterList, 0), &pExpr);
11,610✔
3726
  if (NULL == pExpr) {
11,610!
3727
    return code;
×
3728
  }
3729
  strcpy(((SExprNode*)pExpr)->aliasName, pFunc->node.aliasName);
11,610✔
3730
  *ppNode = pExpr;
11,610✔
3731
  return code;
11,610✔
3732
}
3733

3734
static int32_t rewriteTailOptCreateProject(SIndefRowsFuncLogicNode* pIndef, SLogicNode** pOutput) {
11,273✔
3735
  SProjectLogicNode* pProject = NULL;
11,273✔
3736
  int32_t code = nodesMakeNode(QUERY_NODE_LOGIC_PLAN_PROJECT, (SNode**)&pProject);
11,273✔
3737
  if (NULL == pProject) {
11,273!
3738
    return TSDB_CODE_OUT_OF_MEMORY;
×
3739
  }
3740

3741
  TSWAP(pProject->node.pTargets, pIndef->node.pTargets);
11,273✔
3742
  pProject->node.precision = pIndef->node.precision;
11,273✔
3743

3744
  SFunctionNode* pTail = NULL;
11,273✔
3745
  SNode*         pFunc = NULL;
11,273✔
3746
  FOREACH(pFunc, pIndef->pFuncs) {
22,883!
3747
    SNode* pNew = NULL;
11,610✔
3748
    code = rewriteTailOptCreateProjectExpr((SFunctionNode*)pFunc, &pNew);
11,610✔
3749
    if (TSDB_CODE_SUCCESS == code) {
11,610!
3750
      code = nodesListMakeStrictAppend(&pProject->pProjections, pNew);
11,610✔
3751
    }
3752
    if (TSDB_CODE_SUCCESS != code) {
11,610!
3753
      break;
×
3754
    }
3755
    if (FUNCTION_TYPE_TAIL == ((SFunctionNode*)pFunc)->funcType) {
11,610✔
3756
      pTail = (SFunctionNode*)pFunc;
11,273✔
3757
    }
3758
  }
3759

3760
  // tail(expr, [limit, offset,] _rowts)
3761
  int32_t limitIndex = LIST_LENGTH(pTail->pParameterList) > 2 ? 1 : -1;
11,273!
3762
  int32_t offsetIndex = LIST_LENGTH(pTail->pParameterList) > 3 ? 2 : -1;
11,273!
3763
  if (TSDB_CODE_SUCCESS == code) {
11,273!
3764
    code = rewriteTailOptCreateLimit(limitIndex < 0 ? NULL : nodesListGetNode(pTail->pParameterList, limitIndex),
11,273!
3765
                                     offsetIndex < 0 ? NULL : nodesListGetNode(pTail->pParameterList, offsetIndex),
6,633✔
3766
                                     &pProject->node.pLimit);
11,273✔
3767
  }
3768
  if (TSDB_CODE_SUCCESS == code) {
11,273!
3769
    *pOutput = (SLogicNode*)pProject;
11,273✔
3770
  } else {
3771
    nodesDestroyNode((SNode*)pProject);
×
3772
  }
3773
  return code;
11,273✔
3774
}
3775

3776
static int32_t rewriteTailOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan,
11,273✔
3777
                                       SIndefRowsFuncLogicNode* pIndef) {
3778
  SLogicNode* pSort = NULL;
11,273✔
3779
  SLogicNode* pProject = NULL;
11,273✔
3780
  int32_t     code = rewriteTailOptCreateSort(pIndef, &pSort);
11,273✔
3781
  if (TSDB_CODE_SUCCESS == code) {
11,273!
3782
    code = rewriteTailOptCreateProject(pIndef, &pProject);
11,273✔
3783
  }
3784
  if (TSDB_CODE_SUCCESS == code) {
11,273!
3785
    code = nodesListMakeAppend(&pProject->pChildren, (SNode*)pSort);
11,273✔
3786
    pSort->pParent = pProject;
11,273✔
3787
    pSort = NULL;
11,273✔
3788
  }
3789
  if (TSDB_CODE_SUCCESS == code) {
11,273!
3790
    code = replaceLogicNode(pLogicSubplan, (SLogicNode*)pIndef, pProject);
11,273✔
3791
  }
3792
  if (TSDB_CODE_SUCCESS == code) {
11,273!
3793
    nodesDestroyNode((SNode*)pIndef);
11,273✔
3794
  } else {
3795
    nodesDestroyNode((SNode*)pSort);
×
3796
    nodesDestroyNode((SNode*)pProject);
×
3797
  }
3798
  pCxt->optimized = true;
11,273✔
3799
  return code;
11,273✔
3800
}
3801

3802
static int32_t rewriteTailOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
1,168,906✔
3803
  SIndefRowsFuncLogicNode* pIndef =
3804
      (SIndefRowsFuncLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, rewriteTailOptMayBeOptimized, NULL);
1,168,906✔
3805

3806
  if (NULL == pIndef) {
1,168,914✔
3807
    return TSDB_CODE_SUCCESS;
1,157,641✔
3808
  }
3809

3810
  return rewriteTailOptimizeImpl(pCxt, pLogicSubplan, pIndef);
11,273✔
3811
}
3812

3813
static bool eliminateSetOpMayBeOptimized(SLogicNode* pNode, void* pCtx) {
2,723,334✔
3814
  SLogicNode* pParent = pNode->pParent;
2,723,334✔
3815
  if (NULL == pParent ||
2,723,334✔
3816
      QUERY_NODE_LOGIC_PLAN_AGG != nodeType(pParent) && QUERY_NODE_LOGIC_PLAN_PROJECT != nodeType(pParent) ||
1,953,059✔
3817
      LIST_LENGTH(pParent->pChildren) < 2) {
1,279,184✔
3818
    return false;
2,563,003✔
3819
  }
3820
  if (nodeType(pNode) != nodeType(pNode->pParent) || LIST_LENGTH(pNode->pChildren) < 2) {
160,331✔
3821
    return false;
160,213✔
3822
  }
3823
  return true;
118✔
3824
}
3825

3826
static int32_t eliminateSetOpOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan,
118✔
3827
                                          SLogicNode* pSetOpNode) {
3828
  SNode* pSibling;
3829
  FOREACH(pSibling, pSetOpNode->pParent->pChildren) {
119!
3830
    if (nodesEqualNode(pSibling, (SNode*)pSetOpNode)) {
119✔
3831
      SNode* pChild;
3832
      FOREACH(pChild, pSetOpNode->pChildren) { ((SLogicNode*)pChild)->pParent = pSetOpNode->pParent; }
354!
3833
      INSERT_LIST(pSetOpNode->pParent->pChildren, pSetOpNode->pChildren);
118✔
3834

3835
      pSetOpNode->pChildren = NULL;
118✔
3836
      ERASE_NODE(pSetOpNode->pParent->pChildren);
118✔
3837
      pCxt->optimized = true;
118✔
3838
      return TSDB_CODE_SUCCESS;
118✔
3839
    }
3840
  }
3841

3842
  return TSDB_CODE_PLAN_INTERNAL_ERROR;
×
3843
}
3844

3845
static int32_t eliminateSetOpOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
770,279✔
3846
  SLogicNode* pSetOpNode = optFindPossibleNode(pLogicSubplan->pNode, eliminateSetOpMayBeOptimized, NULL);
770,279✔
3847
  if (NULL == pSetOpNode) {
770,283✔
3848
    return TSDB_CODE_SUCCESS;
770,166✔
3849
  }
3850

3851
  return eliminateSetOpOptimizeImpl(pCxt, pLogicSubplan, pSetOpNode);
117✔
3852
}
3853

3854
static bool rewriteUniqueOptMayBeOptimized(SLogicNode* pNode, void* pCtx) {
4,302,799✔
3855
  return QUERY_NODE_LOGIC_PLAN_INDEF_ROWS_FUNC == nodeType(pNode) && ((SIndefRowsFuncLogicNode*)pNode)->isUniqueFunc;
4,302,799✔
3856
}
3857

3858
static int32_t rewriteUniqueOptCreateGroupingSet(SNode* pExpr, SNode** ppNode) {
10,181✔
3859
  SGroupingSetNode* pGroupingSet = NULL;
10,181✔
3860
  int32_t code = nodesMakeNode(QUERY_NODE_GROUPING_SET, (SNode**)&pGroupingSet);
10,181✔
3861
  if (NULL == pGroupingSet) {
10,181!
3862
    return code;
×
3863
  }
3864
  pGroupingSet->groupingSetType = GP_TYPE_NORMAL;
10,181✔
3865
  SExprNode* pGroupExpr = NULL;
10,181✔
3866
  code = nodesCloneNode(pExpr, (SNode**)&pGroupExpr);
10,181✔
3867
  if (TSDB_CODE_SUCCESS == code) {
10,181!
3868
    code = nodesListMakeStrictAppend(&pGroupingSet->pParameterList, (SNode*)pGroupExpr);
10,181✔
3869
  }
3870
  if (TSDB_CODE_SUCCESS != code) {
10,181!
3871
    nodesDestroyNode((SNode*)pGroupingSet);
×
3872
    return code;
×
3873
  }
3874
  *ppNode = (SNode*)pGroupingSet;
10,181✔
3875
  return code;
10,181✔
3876
}
3877

3878
static int32_t rewriteUniqueOptCreateFirstFunc(SFunctionNode* pSelectValue, SNode* pCol, SNode** ppNode) {
1,442✔
3879
  SFunctionNode* pFunc = NULL;
1,442✔
3880
  int32_t code = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&pFunc);
1,442✔
3881
  if (NULL == pFunc) {
1,442!
3882
    return code;
×
3883
  }
3884

3885
  strcpy(pFunc->functionName, "first");
1,442✔
3886
  if (NULL != pSelectValue) {
1,442✔
3887
    strcpy(pFunc->node.aliasName, pSelectValue->node.aliasName);
1,148✔
3888
  } else {
3889
    int64_t pointer = (int64_t)pFunc;
294✔
3890
    char    name[TSDB_FUNC_NAME_LEN + TSDB_POINTER_PRINT_BYTES + TSDB_NAME_DELIMITER_LEN + 1] = {0};
294✔
3891
    int32_t len = tsnprintf(name, sizeof(name) - 1, "%s.%" PRId64 "", pFunc->functionName, pointer);
294✔
3892
    (void)taosHashBinary(name, len);
3893
    strncpy(pFunc->node.aliasName, name, TSDB_COL_NAME_LEN - 1);
294✔
3894
  }
3895
  SNode* pNew = NULL;
1,442✔
3896
  code = nodesCloneNode(pCol, &pNew);
1,442✔
3897
  if (TSDB_CODE_SUCCESS == code) {
1,442!
3898
    code = nodesListMakeStrictAppend(&pFunc->pParameterList, pNew);
1,442✔
3899
  }
3900
  if (TSDB_CODE_SUCCESS == code) {
1,442!
3901
    code = fmGetFuncInfo(pFunc, NULL, 0);
1,442✔
3902
  }
3903

3904
  if (TSDB_CODE_SUCCESS != code) {
1,442!
3905
    nodesDestroyNode((SNode*)pFunc);
×
3906
    return code;
×
3907
  }
3908
  *ppNode = (SNode*)pFunc;
1,442✔
3909
  return code;
1,442✔
3910
}
3911

3912
static int32_t rewriteUniqueOptCreateAgg(SIndefRowsFuncLogicNode* pIndef, SLogicNode** pOutput) {
10,181✔
3913
  SAggLogicNode* pAgg = NULL;
10,181✔
3914
  int32_t code = nodesMakeNode(QUERY_NODE_LOGIC_PLAN_AGG, (SNode**)&pAgg);
10,181✔
3915
  if (NULL == pAgg) {
10,181!
3916
    return code;
×
3917
  }
3918

3919
  TSWAP(pAgg->node.pChildren, pIndef->node.pChildren);
10,181✔
3920
  optResetParent((SLogicNode*)pAgg);
10,181✔
3921
  pAgg->node.precision = pIndef->node.precision;
10,181✔
3922
  pAgg->node.requireDataOrder = DATA_ORDER_LEVEL_IN_BLOCK;  // first function requirement
10,181✔
3923
  pAgg->node.resultDataOrder = DATA_ORDER_LEVEL_NONE;
10,181✔
3924

3925
  bool    hasSelectPrimaryKey = false;
10,181✔
3926
  SNode*  pPrimaryKey = NULL;
10,181✔
3927
  SNode*  pNode = NULL;
10,181✔
3928
  FOREACH(pNode, pIndef->pFuncs) {
22,145!
3929
    SFunctionNode* pFunc = (SFunctionNode*)pNode;
11,964✔
3930
    SNode*         pExpr = nodesListGetNode(pFunc->pParameterList, 0);
11,964✔
3931
    if (FUNCTION_TYPE_UNIQUE == pFunc->funcType) {
11,964✔
3932
      pPrimaryKey = nodesListGetNode(pFunc->pParameterList, 1);
10,181✔
3933
      SNode* pNew = NULL;
10,181✔
3934
      code = rewriteUniqueOptCreateGroupingSet(pExpr, &pNew);
10,181✔
3935
      if (TSDB_CODE_SUCCESS == code) {
10,181!
3936
        code = nodesListMakeStrictAppend(&pAgg->pGroupKeys, pNew);
10,181✔
3937
      }
3938
    } else if (PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pExpr)->colId) {  // _select_value(ts) => first(ts)
1,783✔
3939
      hasSelectPrimaryKey = true;
1,148✔
3940
      SNode* pNew = NULL;
1,148✔
3941
      code = rewriteUniqueOptCreateFirstFunc(pFunc, pExpr, &pNew);
1,148✔
3942
      if (TSDB_CODE_SUCCESS == code) {
1,148!
3943
        code = nodesListMakeStrictAppend(&pAgg->pAggFuncs, pNew);
1,148✔
3944
      }
3945
    } else {  // _select_value(other_col)
3946
      SNode* pNew = NULL;
635✔
3947
      code = nodesCloneNode(pNode, &pNew);
635✔
3948
      if (TSDB_CODE_SUCCESS == code) {
635!
3949
        code = nodesListMakeStrictAppend(&pAgg->pAggFuncs, pNew);
635✔
3950
      }
3951
    }
3952
    if (TSDB_CODE_SUCCESS != code) {
11,964!
3953
      break;
×
3954
    }
3955
  }
3956

3957
  if (TSDB_CODE_SUCCESS == code) {
10,181!
3958
    code = createColumnByRewriteExprs(pAgg->pGroupKeys, &pAgg->node.pTargets);
10,181✔
3959
  }
3960
  if (TSDB_CODE_SUCCESS == code && NULL != pAgg->pAggFuncs) {
10,181!
3961
    code = createColumnByRewriteExprs(pAgg->pAggFuncs, &pAgg->node.pTargets);
1,442✔
3962
  }
3963

3964
  if (TSDB_CODE_SUCCESS == code && !hasSelectPrimaryKey && NULL != pAgg->pAggFuncs) {
10,181!
3965
    SNode* pNew = NULL;
294✔
3966
    code = rewriteUniqueOptCreateFirstFunc(NULL, pPrimaryKey, &pNew);
294✔
3967
    if (TSDB_CODE_SUCCESS == code) {
294!
3968
      code = nodesListMakeStrictAppend(&pAgg->pAggFuncs, pNew);
294✔
3969
    }
3970
  }
3971

3972
  if (TSDB_CODE_SUCCESS == code) {
10,181!
3973
    *pOutput = (SLogicNode*)pAgg;
10,181✔
3974
  } else {
3975
    nodesDestroyNode((SNode*)pAgg);
×
3976
  }
3977
  return code;
10,181✔
3978
}
3979

3980
static int32_t rewriteUniqueOptCreateProjectCol(SFunctionNode* pFunc, SNode** ppNode) {
11,964✔
3981
  SColumnNode* pCol = NULL;
11,964✔
3982
  int32_t code = nodesMakeNode(QUERY_NODE_COLUMN, (SNode**)&pCol);
11,964✔
3983
  if (NULL == pCol) {
11,964!
3984
    return code;
×
3985
  }
3986

3987
  pCol->node.resType = pFunc->node.resType;
11,964✔
3988
  if (FUNCTION_TYPE_UNIQUE == pFunc->funcType) {
11,964✔
3989
    SExprNode* pExpr = (SExprNode*)nodesListGetNode(pFunc->pParameterList, 0);
10,181✔
3990
    if (QUERY_NODE_COLUMN == nodeType(pExpr)) {
10,181✔
3991
      strcpy(pCol->tableAlias, ((SColumnNode*)pExpr)->tableAlias);
10,173✔
3992
      strcpy(pCol->colName, ((SColumnNode*)pExpr)->colName);
10,173✔
3993
    } else {
3994
      strcpy(pCol->colName, pExpr->aliasName);
8✔
3995
    }
3996
  } else {
3997
    strcpy(pCol->colName, pFunc->node.aliasName);
1,783✔
3998
  }
3999
  strcpy(pCol->node.aliasName, pFunc->node.aliasName);
11,964✔
4000
  *ppNode = (SNode*)pCol;
11,964✔
4001
  return code;
11,964✔
4002
}
4003

4004
static int32_t rewriteUniqueOptCreateProject(SIndefRowsFuncLogicNode* pIndef, SLogicNode** pOutput) {
10,181✔
4005
  SProjectLogicNode* pProject = NULL;
10,181✔
4006
  int32_t code = nodesMakeNode(QUERY_NODE_LOGIC_PLAN_PROJECT, (SNode**)&pProject);
10,181✔
4007
  if (NULL == pProject) {
10,181!
4008
    return code;
×
4009
  }
4010

4011
  TSWAP(pProject->node.pTargets, pIndef->node.pTargets);
10,181✔
4012
  pProject->node.precision = pIndef->node.precision;
10,181✔
4013
  pProject->node.requireDataOrder = DATA_ORDER_LEVEL_NONE;
10,181✔
4014
  pProject->node.resultDataOrder = DATA_ORDER_LEVEL_NONE;
10,181✔
4015

4016
  SNode*  pNode = NULL;
10,181✔
4017
  FOREACH(pNode, pIndef->pFuncs) {
22,145!
4018
    SNode* pNew = NULL;
11,964✔
4019
    code = rewriteUniqueOptCreateProjectCol((SFunctionNode*)pNode, &pNew);
11,964✔
4020
    if (TSDB_CODE_SUCCESS == code) {
11,964!
4021
      code = nodesListMakeStrictAppend(&pProject->pProjections, pNew);
11,964✔
4022
    }
4023
    if (TSDB_CODE_SUCCESS != code) {
11,964!
4024
      break;
×
4025
    }
4026
  }
4027

4028
  if (TSDB_CODE_SUCCESS == code) {
10,181!
4029
    *pOutput = (SLogicNode*)pProject;
10,181✔
4030
  } else {
4031
    nodesDestroyNode((SNode*)pProject);
×
4032
  }
4033
  return code;
10,181✔
4034
}
4035

4036
static int32_t rewriteUniqueOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan,
10,181✔
4037
                                         SIndefRowsFuncLogicNode* pIndef) {
4038
  SLogicNode* pAgg = NULL;
10,181✔
4039
  SLogicNode* pProject = NULL;
10,181✔
4040
  int32_t     code = rewriteUniqueOptCreateAgg(pIndef, &pAgg);
10,181✔
4041
  if (TSDB_CODE_SUCCESS == code) {
10,181!
4042
    code = rewriteUniqueOptCreateProject(pIndef, &pProject);
10,181✔
4043
  }
4044
  if (TSDB_CODE_SUCCESS == code) {
10,181!
4045
    code = nodesListMakeAppend(&pProject->pChildren, (SNode*)pAgg);
10,181✔
4046
  }
4047
  if (TSDB_CODE_SUCCESS == code) {
10,181!
4048
    pAgg->pParent = pProject;
10,181✔
4049
    pAgg = NULL;
10,181✔
4050
    code = replaceLogicNode(pLogicSubplan, (SLogicNode*)pIndef, pProject);
10,181✔
4051
  }
4052
  if (TSDB_CODE_SUCCESS == code) {
10,181!
4053
    code = adjustLogicNodeDataRequirement(
10,181✔
4054
        pProject, NULL == pProject->pParent ? DATA_ORDER_LEVEL_NONE : pProject->pParent->requireDataOrder);
10,181!
4055
    pProject = NULL;
10,181✔
4056
  }
4057
  if (TSDB_CODE_SUCCESS == code) {
10,181!
4058
    nodesDestroyNode((SNode*)pIndef);
10,181✔
4059
  } else {
4060
    nodesDestroyNode((SNode*)pAgg);
×
4061
    nodesDestroyNode((SNode*)pProject);
×
4062
  }
4063
  pCxt->optimized = true;
10,181✔
4064
  return code;
10,181✔
4065
}
4066

4067
static int32_t rewriteUniqueOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
1,157,634✔
4068
  SIndefRowsFuncLogicNode* pIndef =
4069
      (SIndefRowsFuncLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, rewriteUniqueOptMayBeOptimized, NULL);
1,157,634✔
4070

4071
  if (NULL == pIndef) {
1,157,641✔
4072
    return TSDB_CODE_SUCCESS;
1,147,457✔
4073
  }
4074

4075
  return rewriteUniqueOptimizeImpl(pCxt, pLogicSubplan, pIndef);
10,184✔
4076
}
4077

4078
typedef struct SLastRowScanOptLastParaCkCxt {
4079
  bool hasTag;
4080
  bool hasCol;
4081
} SLastRowScanOptLastParaCkCxt;
4082

4083
static EDealRes lastRowScanOptLastParaIsTagImpl(SNode* pNode, void* pContext) {
17,978✔
4084
  if (QUERY_NODE_COLUMN == nodeType(pNode)) {
17,978!
4085
    SLastRowScanOptLastParaCkCxt* pCxt = pContext;
17,978✔
4086
    if (COLUMN_TYPE_TAG == ((SColumnNode*)pNode)->colType || COLUMN_TYPE_TBNAME == ((SColumnNode*)pNode)->colType) {
17,978!
4087
      pCxt->hasTag = true;
17,978✔
4088
    } else {
4089
      pCxt->hasCol = true;
×
4090
    }
4091
    return DEAL_RES_END;
17,978✔
4092
  }
4093
  return DEAL_RES_CONTINUE;
×
4094
}
4095

4096
static bool lastRowScanOptLastParaIsTag(SNode* pExpr) {
17,978✔
4097
  SLastRowScanOptLastParaCkCxt cxt = {.hasTag = false, .hasCol = false};
17,978✔
4098
  nodesWalkExpr(pExpr, lastRowScanOptLastParaIsTagImpl, &cxt);
17,978✔
4099
  return cxt.hasTag && !cxt.hasCol;
17,978!
4100
}
4101

4102
static bool hasSuitableCache(int8_t cacheLastMode, bool hasLastRow, bool hasLast) {
86,751✔
4103
  switch (cacheLastMode) {
86,751!
4104
    case TSDB_CACHE_MODEL_NONE:
49,468✔
4105
      return false;
49,468✔
4106
    case TSDB_CACHE_MODEL_LAST_ROW:
11,466✔
4107
      return hasLastRow;
11,466✔
4108
    case TSDB_CACHE_MODEL_LAST_VALUE:
6,148✔
4109
      return hasLast;
6,148✔
4110
    case TSDB_CACHE_MODEL_BOTH:
19,669✔
4111
      return true;
19,669✔
4112
    default:
×
4113
      break;
×
4114
  }
4115
  return false;
×
4116
}
4117

4118
/// @brief check if we can apply last row scan optimization
4119
/// @param lastColNum how many distinct last col specified
4120
/// @param lastColId only used when lastColNum equals 1, the col id of the only one last col
4121
/// @param selectNonPKColNum num of normal cols
4122
/// @param selectNonPKColId only used when selectNonPKColNum equals 1, the col id of the only one select col
4123
static bool lastRowScanOptCheckColNum(int32_t lastColNum, col_id_t lastColId, int32_t selectNonPKColNum,
45,344✔
4124
                                      col_id_t selectNonPKColId) {
4125
  // multi select non pk col + last func: select c1, c2, last(c1)
4126
  if (selectNonPKColNum > 1 && lastColNum > 0) return false;
45,344!
4127

4128
  if (selectNonPKColNum == 1) {
45,344✔
4129
    // select last(c1), last(c2), c1 ...
4130
    // which is not possible currently
4131
    if (lastColNum > 1) return false;
3,368!
4132

4133
    // select last(c1), c2 ...
4134
    if (lastColNum == 1 && lastColId != selectNonPKColId) return false;
3,368✔
4135
  }
4136
  return true;
45,064✔
4137
}
4138

4139
static bool isNeedSplitCacheLastFunc(SFunctionNode* pFunc, SScanLogicNode* pScan) {
4,718✔
4140
  int32_t funcType = pFunc->funcType;
4,718✔
4141
  if ((FUNCTION_TYPE_LAST_ROW != funcType || (FUNCTION_TYPE_LAST_ROW == funcType && TSDB_CACHE_MODEL_LAST_VALUE == pScan->cacheLastMode)) &&
4,718!
4142
       (FUNCTION_TYPE_LAST != funcType || (FUNCTION_TYPE_LAST == funcType && (TSDB_CACHE_MODEL_LAST_ROW == pScan->cacheLastMode ||
2,342!
4143
         QUERY_NODE_OPERATOR == nodeType(nodesListGetNode(pFunc->pParameterList, 0)) || QUERY_NODE_VALUE == nodeType(nodesListGetNode(pFunc->pParameterList, 0)) ||
1,242✔
4144
         COLUMN_TYPE_COLUMN != ((SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0))->colType))) &&
3,540!
4145
        FUNCTION_TYPE_SELECT_VALUE != funcType && FUNCTION_TYPE_GROUP_KEY != funcType) {
2,326!
4146
    return true;
2,326✔
4147
  }
4148
  return false;
2,392✔
4149
}
4150

4151
static bool lastRowScanOptCheckFuncList(SLogicNode* pNode, int8_t cacheLastModel, bool* hasOtherFunc) {
29,327✔
4152
  bool     hasNonPKSelectFunc = false;
29,327✔
4153
  SNode*   pFunc = NULL;
29,327✔
4154
  int32_t  lastColNum = 0, selectNonPKColNum = 0;
29,327✔
4155
  col_id_t lastColId = -1, selectNonPKColId = -1;
29,327✔
4156
  SScanLogicNode* pScan = (SScanLogicNode*)nodesListGetNode(((SAggLogicNode*)pNode)->node.pChildren, 0);
29,327✔
4157
  uint32_t needSplitFuncCount = 0;
29,327✔
4158
  FOREACH(pFunc, ((SAggLogicNode*)pNode)->pAggFuncs) {
316,461!
4159
    SFunctionNode* pAggFunc = (SFunctionNode*)pFunc;
287,414✔
4160
    SNode* pParam = nodesListGetNode(pAggFunc->pParameterList, 0);
287,414✔
4161
    if (FUNCTION_TYPE_LAST == pAggFunc->funcType) {
287,414✔
4162
      if (QUERY_NODE_COLUMN == nodeType(pParam)) {
42,908✔
4163
        SColumnNode* pCol = (SColumnNode*)pParam;
42,636✔
4164
        if (pCol->colType != COLUMN_TYPE_COLUMN && TSDB_CACHE_MODEL_LAST_ROW != cacheLastModel) {
42,636✔
4165
          needSplitFuncCount++;
44✔
4166
          *hasOtherFunc = true;
44✔
4167
        }
4168
        if (lastColId != pCol->colId) {
42,636!
4169
          lastColId = pCol->colId;
42,636✔
4170
          lastColNum++;
42,636✔
4171
        }
4172
      }
4173
      else if (QUERY_NODE_VALUE == nodeType(pParam) || QUERY_NODE_OPERATOR == nodeType(pParam)) {
272!
4174
        needSplitFuncCount++;
272✔
4175
        *hasOtherFunc = true;
272✔
4176
      }
4177
      if (!lastRowScanOptCheckColNum(lastColNum, lastColId, selectNonPKColNum, selectNonPKColId)) {
42,908!
4178
        return false;
×
4179
      }
4180
      if (TSDB_CACHE_MODEL_LAST_ROW == cacheLastModel) {
42,908✔
4181
        needSplitFuncCount++;
7,208✔
4182
        *hasOtherFunc = true;
7,208✔
4183
      }
4184
    } else if (FUNCTION_TYPE_SELECT_VALUE == pAggFunc->funcType) {
244,506✔
4185
      if (QUERY_NODE_COLUMN == nodeType(pParam)) {
6,896!
4186
        SColumnNode* pCol = (SColumnNode*)pParam;
6,896✔
4187
        if (COLUMN_TYPE_COLUMN == pCol->colType && PRIMARYKEY_TIMESTAMP_COL_ID != pCol->colId) {
6,896✔
4188
          if (selectNonPKColId != pCol->colId) {
2,436!
4189
            selectNonPKColId = pCol->colId;
2,436✔
4190
            selectNonPKColNum++;
2,436✔
4191
          }
4192
        } else {
4193
          continue;
4,460✔
4194
        }
4195
      } else if (lastColNum > 0) {
×
4196
        return false;
×
4197
      }
4198
      if (!lastRowScanOptCheckColNum(lastColNum, lastColId, selectNonPKColNum, selectNonPKColId)) return false;
2,436✔
4199
    } else if (FUNCTION_TYPE_GROUP_KEY == pAggFunc->funcType) {
237,610✔
4200
      if (!lastRowScanOptLastParaIsTag(nodesListGetNode(pAggFunc->pParameterList, 0))) {
17,978!
4201
        return false;
×
4202
      }
4203
    } else if (FUNCTION_TYPE_LAST_ROW != pAggFunc->funcType) {
219,632✔
4204
      *hasOtherFunc = true;
176,746✔
4205
      needSplitFuncCount++;
176,746✔
4206
    } else if (FUNCTION_TYPE_LAST_ROW == pAggFunc->funcType && TSDB_CACHE_MODEL_LAST_VALUE == cacheLastModel) {
42,886!
4207
      *hasOtherFunc = true;
1,324✔
4208
      needSplitFuncCount++;
1,324✔
4209
    }
4210
  }
4211
  if (needSplitFuncCount >= ((SAggLogicNode*)pNode)->pAggFuncs->length) {
29,047✔
4212
    return false;
216✔
4213
  }
4214

4215
  return true;
28,831✔
4216
}
4217

4218
static bool lastRowScanOptCheckLastCache(SAggLogicNode* pAgg, SScanLogicNode* pScan) {
1,095,006✔
4219
  if ((pAgg->hasLastRow == pAgg->hasLast && !pAgg->hasLastRow) || (!pAgg->hasLast && !pAgg->hasLastRow) || NULL != pAgg->pGroupKeys || NULL != pScan->node.pConditions ||
1,095,006!
4220
      !hasSuitableCache(pScan->cacheLastMode, pAgg->hasLastRow, pAgg->hasLast) ||
86,756✔
4221
      IS_TSWINDOW_SPECIFIED(pScan->scanRange)) {
29,359!
4222
    return false;
1,065,677✔
4223
  }
4224

4225
  return true;
29,327✔
4226
}
4227

4228
static bool lastRowScanOptMayBeOptimized(SLogicNode* pNode, void* pCtx) {
4,249,833✔
4229
  if (QUERY_NODE_LOGIC_PLAN_AGG != nodeType(pNode) || 1 != LIST_LENGTH(pNode->pChildren) ||
4,249,833!
4230
      QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(nodesListGetNode(pNode->pChildren, 0))) {
780,908✔
4231
    return false;
3,702,603✔
4232
  }
4233

4234
  SAggLogicNode*  pAgg = (SAggLogicNode*)pNode;
547,229✔
4235
  SScanLogicNode* pScan = (SScanLogicNode*)nodesListGetNode(pNode->pChildren, 0);
547,229✔
4236
  if (!lastRowScanOptCheckLastCache(pAgg, pScan)) {
547,242✔
4237
    return false;
532,845✔
4238
  }
4239

4240
  bool hasOtherFunc = false;
14,399✔
4241
  if (!lastRowScanOptCheckFuncList(pNode, pScan->cacheLastMode, &hasOtherFunc)) {
14,399✔
4242
    return false;
248✔
4243
  }
4244

4245
  if (hasOtherFunc) {
14,151✔
4246
    return false;
8,774✔
4247
  }
4248

4249
  return true;
5,377✔
4250
}
4251

4252
typedef struct SLastRowScanOptSetColDataTypeCxt {
4253
  bool       doAgg;
4254
  SNodeList* pLastCols;
4255
  SNodeList* pOtherCols;
4256
  int32_t    funcType;
4257
  int32_t    pkBytes;
4258
  int32_t    code;
4259
} SLastRowScanOptSetColDataTypeCxt;
4260

4261
static EDealRes lastRowScanOptSetColDataType(SNode* pNode, void* pContext) {
11,504✔
4262
  if (QUERY_NODE_COLUMN == nodeType(pNode)) {
11,504✔
4263
    SLastRowScanOptSetColDataTypeCxt* pCxt = pContext;
11,129✔
4264
    if (pCxt->doAgg) {
11,129✔
4265
      pCxt->code = nodesListMakeAppend(&pCxt->pLastCols, pNode);
11,044✔
4266
      if (TSDB_CODE_SUCCESS != pCxt->code) {
11,044!
4267
        return DEAL_RES_ERROR;
×
4268
      }
4269
      getLastCacheDataType(&(((SColumnNode*)pNode)->node.resType), pCxt->pkBytes);
11,044✔
4270
    } else {
4271
      SNode* pCol = NULL;
85✔
4272
      FOREACH(pCol, pCxt->pLastCols) {
182!
4273
        if (nodesEqualNode(pCol, pNode)) {
97!
4274
          getLastCacheDataType(&(((SColumnNode*)pNode)->node.resType), pCxt->pkBytes);
×
4275
          break;
×
4276
        }
4277
      }
4278
    }
4279
    return DEAL_RES_IGNORE_CHILD;
11,129✔
4280
  }
4281
  return DEAL_RES_CONTINUE;
375✔
4282
}
4283

4284
static void lastRowScanOptSetLastTargets(SNodeList* pTargets, SNodeList* pLastCols, SNodeList* pLastRowCols, bool erase, int32_t pkBytes) {
5,282✔
4285
  SNode* pTarget = NULL;
5,282✔
4286
  WHERE_EACH(pTarget, pTargets) {
36,468!
4287
    bool   found = false;
31,186✔
4288
    SNode* pCol = NULL;
31,186✔
4289
    FOREACH(pCol, pLastCols) {
364,288!
4290
      if (nodesEqualNode(pCol, pTarget)) {
355,190✔
4291
        getLastCacheDataType(&(((SColumnNode*)pTarget)->node.resType), pkBytes);
22,088✔
4292
        found = true;
22,088✔
4293
        break;
22,088✔
4294
      }
4295
    }
4296
    if (!found && nodeListNodeEqual(pLastRowCols, pTarget)) {
31,186✔
4297
      found = true;
4,876✔
4298
    }
4299

4300
    if (!found && erase) {
31,186✔
4301
      ERASE_NODE(pTargets);
1,881✔
4302
      continue;
1,881✔
4303
    }
4304
    WHERE_NEXT;
29,305✔
4305
  }
4306
}
5,282✔
4307

4308
static void lastRowScanOptRemoveUslessTargets(SNodeList* pTargets, SNodeList* pList1, SNodeList* pList2, SNodeList* pList3) {
2,641✔
4309
  SNode* pTarget = NULL;
2,641✔
4310
  WHERE_EACH(pTarget, pTargets) {
18,464!
4311
    bool   found = false;
15,823✔
4312
    SNode* pCol = NULL;
15,823✔
4313
    FOREACH(pCol, pList1) {
184,482!
4314
      if (nodesEqualNode(pCol, pTarget)) {
179,703✔
4315
        found = true;
11,044✔
4316
        break;
11,044✔
4317
      }
4318
    }
4319
    if (!found) {
15,823✔
4320
      FOREACH(pCol, pList2) {
6,676✔
4321
        if (nodesEqualNode(pCol, pTarget)) {
3,264✔
4322
          found = true;
1,367✔
4323
          break;
1,367✔
4324
        }
4325
      }
4326
    }
4327

4328
    if (!found && nodeListNodeEqual(pList3, pTarget)) {
15,823✔
4329
      found = true;
2,428✔
4330
    }
4331

4332
    if (!found) {
15,823✔
4333
      ERASE_NODE(pTargets);
984✔
4334
      continue;
984✔
4335
    }
4336
    WHERE_NEXT;
14,839✔
4337
  }
4338
}
2,641✔
4339

4340
static int32_t lastRowScanBuildFuncTypes(SScanLogicNode* pScan, SColumnNode* pColNode, int32_t funcType) {
4,914✔
4341
  SFunctParam* pFuncTypeParam = taosMemoryCalloc(1, sizeof(SFunctParam));
4,914✔
4342
  if (NULL == pFuncTypeParam) {
4,914!
4343
    return terrno;
×
4344
  }
4345
  pFuncTypeParam->type = funcType;
4,914✔
4346
  if (NULL == pScan->pFuncTypes) {
4,914✔
4347
    pScan->pFuncTypes = taosArrayInit(pScan->pScanCols->length, sizeof(SFunctParam));
186✔
4348
    if (NULL == pScan->pFuncTypes) {
186!
4349
      taosMemoryFree(pFuncTypeParam);
×
4350
      return terrno;
×
4351
    }
4352
  }
4353
 
4354
  pFuncTypeParam->pCol = taosMemoryCalloc(1, sizeof(SColumn));
4,914✔
4355
  if (NULL == pFuncTypeParam->pCol) {
4,914!
4356
    taosMemoryFree(pFuncTypeParam);
×
4357
    return terrno;
×
4358
  }
4359
  pFuncTypeParam->pCol->colId = pColNode->colId;
4,914✔
4360
  strcpy(pFuncTypeParam->pCol->name, pColNode->colName);
4,914✔
4361
  if (NULL == taosArrayPush(pScan->pFuncTypes, pFuncTypeParam)) {
9,828!
4362
    taosMemoryFree(pFuncTypeParam);
×
4363
    return terrno;
×
4364
  }
4365

4366
  taosMemoryFree(pFuncTypeParam);
4,914✔
4367
  return TSDB_CODE_SUCCESS;
4,914✔
4368
}
4369

4370
static int32_t lastRowScanOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
1,147,120✔
4371
  SAggLogicNode* pAgg = (SAggLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, lastRowScanOptMayBeOptimized, NULL);
1,147,120✔
4372

4373
  if (NULL == pAgg) {
1,147,128✔
4374
    return TSDB_CODE_SUCCESS;
1,141,751✔
4375
  }
4376

4377
  SLastRowScanOptSetColDataTypeCxt cxt = {.doAgg = true, .pLastCols = NULL, .pOtherCols = NULL};
5,377✔
4378
  SNode*                           pNode = NULL;
5,377✔
4379
  SColumnNode*                     pPKTsCol = NULL;
5,377✔
4380
  SColumnNode*                     pNonPKCol = NULL;
5,377✔
4381
  SScanLogicNode*                  pScan = (SScanLogicNode*)nodesListGetNode(pAgg->node.pChildren, 0);
5,377✔
4382
  pScan->scanType = SCAN_TYPE_LAST_ROW;
5,377✔
4383
  pScan->igLastNull = pAgg->hasLast ? true : false;
5,377✔
4384
  SArray*    isDuplicateCol = taosArrayInit(pScan->pScanCols->length, sizeof(bool));
5,377✔
4385
  SNodeList* pLastRowCols = NULL;
5,377✔
4386
  bool       adjLastRowTsColName = false;
5,377✔
4387
  char       tsColName[TSDB_COL_NAME_LEN] = {0};
5,377✔
4388
  int32_t    code = 0;
5,377✔
4389

4390
  FOREACH(pNode, pAgg->pAggFuncs) {
31,228!
4391
    SFunctionNode* pFunc = (SFunctionNode*)pNode;
25,851✔
4392
    int32_t        funcType = pFunc->funcType;
25,851✔
4393
    SNode*         pParamNode = NULL;
25,851✔
4394
    if (FUNCTION_TYPE_LAST == funcType) {
25,851✔
4395
      (void)nodesListErase(pFunc->pParameterList, nodesListGetCell(pFunc->pParameterList, 1));
11,044✔
4396
      nodesWalkExpr(nodesListGetNode(pFunc->pParameterList, 0), lastRowScanOptSetColDataType, &cxt);
11,044✔
4397
      if (TSDB_CODE_SUCCESS != cxt.code) break;
11,044!
4398
    }
4399
    FOREACH(pParamNode, pFunc->pParameterList) {
65,709!
4400
      if (FUNCTION_TYPE_LAST_ROW == funcType || FUNCTION_TYPE_LAST == funcType) {
76,271✔
4401
        int32_t len = tsnprintf(pFunc->functionName, sizeof(pFunc->functionName),
36,413✔
4402
                              FUNCTION_TYPE_LAST_ROW == funcType ? "_cache_last_row" : "_cache_last");
4403
        pFunc->functionName[len] = '\0';
36,413✔
4404
        code = fmGetFuncInfo(pFunc, NULL, 0);
36,413✔
4405
        if (TSDB_CODE_SUCCESS != code) {
36,413!
4406
          nodesClearList(cxt.pLastCols);
×
4407
          break;
×
4408
        }
4409
        cxt.funcType = pFunc->funcType;
36,413✔
4410
        cxt.pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
36,413✔
4411
        // add duplicate cols which be removed for both last_row, last
4412
        if (pAgg->hasLast && pAgg->hasLastRow) {
36,413✔
4413
          if (QUERY_NODE_COLUMN == nodeType(pParamNode)) {
7,110✔
4414
            SNode* pColNode = NULL;
7,102✔
4415
            int i = 0;
7,102✔
4416
            FOREACH(pColNode, pScan->pScanCols) {
236,344!
4417
              bool isDup = false;
229,242✔
4418
              bool* isDuplicate = taosArrayGet(isDuplicateCol, i);
229,242✔
4419
              if (NULL == isDuplicate) {
229,242✔
4420
                if (NULL == taosArrayInsert(isDuplicateCol, i, &isDup)) {
2,403!
4421
                  code = terrno;
×
4422
                  break;
×
4423
                }
4424
                isDuplicate = taosArrayGet(isDuplicateCol, i);
2,403✔
4425
              }
4426
              i++;
229,242✔
4427
              if (nodesEqualNode(pParamNode, pColNode)) {
229,242✔
4428
                if (*isDuplicate) {
11,790✔
4429
                  if (0 == strncmp(((SColumnNode*)pColNode)->colName, "#dup_col.", 9)) {
9,398✔
4430
                    continue;
6,971✔
4431
                  }
4432
                  SNode* newColNode = NULL;
4,710✔
4433
                  code = nodesCloneNode(pColNode, &newColNode);
4,710✔
4434
                  if (TSDB_CODE_SUCCESS != code) {
4,710!
4435
                    break;
×
4436
                  }
4437
                  sprintf(((SColumnNode*)newColNode)->colName, "#dup_col.%p", newColNode);
4,710✔
4438
                  sprintf(((SColumnNode*)pParamNode)->colName, "#dup_col.%p", newColNode);
4,710✔
4439
                  if (FUNCTION_TYPE_LAST_ROW == funcType &&
4,710✔
4440
                      ((SColumnNode*)pParamNode)->colId == PRIMARYKEY_TIMESTAMP_COL_ID) {
4,503✔
4441
                    if (!adjLastRowTsColName) {
2,469✔
4442
                      adjLastRowTsColName = true;
186✔
4443
                      strncpy(tsColName, ((SColumnNode*)pParamNode)->colName, TSDB_COL_NAME_LEN);
186✔
4444
                    } else {
4445
                      strncpy(((SColumnNode*)pParamNode)->colName, tsColName, TSDB_COL_NAME_LEN);
2,283✔
4446
                      nodesDestroyNode(newColNode);
2,283✔
4447
                      continue;
2,283✔
4448
                    }
4449
                  }
4450

4451
                  code = nodesListStrictAppend(pScan->pScanCols, newColNode);
2,427✔
4452
                  if (TSDB_CODE_SUCCESS != code) break;
2,427!
4453
                  isDup = true;
2,427✔
4454
                  if (NULL == taosArrayInsert(isDuplicateCol, pScan->pScanCols->length, &isDup)) {
2,427!
4455
                    code = terrno;
×
4456
                    break;
×
4457
                  }
4458
                  SNode* pNew = NULL;
2,427✔
4459
                  code = nodesCloneNode(newColNode, &pNew);
2,427✔
4460
                  if (TSDB_CODE_SUCCESS != code) break;
2,427!
4461
                  code = nodesListStrictAppend(pScan->node.pTargets, pNew);
2,427✔
4462
                  if (TSDB_CODE_SUCCESS != code) break;
2,427!
4463
                  if (funcType != FUNCTION_TYPE_LAST) {
2,427✔
4464
                    pNew = NULL;
2,220✔
4465
                    code = nodesCloneNode(newColNode, &pNew);
2,220✔
4466
                    if (TSDB_CODE_SUCCESS != code) break;
2,220!
4467
                    code = nodesListMakeAppend(&pLastRowCols, pNew);
2,220✔
4468
                    if (TSDB_CODE_SUCCESS != code) break;
2,220!
4469
                  }
4470

4471
                  code = lastRowScanBuildFuncTypes(pScan, (SColumnNode*)newColNode, pFunc->funcType);
2,427✔
4472
                  if (TSDB_CODE_SUCCESS != code) break;
2,427!
4473
                } else {
4474
                  isDup = true;
2,392✔
4475
                  *isDuplicate = isDup;
2,392✔
4476
                  if (funcType != FUNCTION_TYPE_LAST && !nodeListNodeEqual(cxt.pLastCols, pColNode)) {
2,392!
4477
                    SNode* pNew = NULL;
207✔
4478
                    code = nodesCloneNode(pColNode, &pNew);
207✔
4479
                    if (TSDB_CODE_SUCCESS != code) break;
207!
4480
                    code = nodesListMakeStrictAppend(&pLastRowCols, pNew);
207✔
4481
                    if (TSDB_CODE_SUCCESS != code) break;
207!
4482
                  }
4483
                  code = lastRowScanBuildFuncTypes(pScan, (SColumnNode*)pColNode, pFunc->funcType);
2,392✔
4484
                  if (TSDB_CODE_SUCCESS != code) break;
2,392!
4485
                }
4486
                continue;
4,819✔
4487
              } else if (nodeListNodeEqual(pFunc->pParameterList, pColNode)) {
217,452✔
4488
                if (funcType != FUNCTION_TYPE_LAST && ((SColumnNode*)pColNode)->colId == PRIMARYKEY_TIMESTAMP_COL_ID &&
4,400✔
4489
                    !nodeListNodeEqual(pLastRowCols, pColNode)) {
2,185✔
4490
                  SNode* pNew = NULL;
95✔
4491
                  code = nodesCloneNode(pColNode, &pNew);
95✔
4492
                  if (TSDB_CODE_SUCCESS != code) break;
95!
4493
                  code = nodesListMakeAppend(&pLastRowCols, pNew);
95✔
4494
                  if (TSDB_CODE_SUCCESS != code) break;
95!
4495

4496
                  code = lastRowScanBuildFuncTypes(pScan, (SColumnNode*)pColNode, pFunc->funcType);
95✔
4497
                  if (TSDB_CODE_SUCCESS != code) break;
95!
4498
                  isDup = true;
95✔
4499
                  *isDuplicate = isDup;
95✔
4500
                }
4501
              }
4502
            }
4503
            if (TSDB_CODE_SUCCESS != code) break;;
7,102!
4504
            FOREACH(pColNode, pScan->pScanPseudoCols) {
10,990✔
4505
              if (nodesEqualNode(pParamNode, pColNode)) {
3,888!
4506
                if (funcType != FUNCTION_TYPE_LAST) {
×
4507
                  SNode* pNew = NULL;
×
4508
                  code = nodesCloneNode(pColNode, &pNew);
×
4509
                  if (TSDB_CODE_SUCCESS != code) break;
×
4510
                  code = nodesListMakeAppend(&pLastRowCols, pNew);
×
4511
                  if (TSDB_CODE_SUCCESS != code) break;
×
4512
                }
4513
              }
4514
            }
4515
          }
4516
        }
4517

4518
        if (TSDB_CODE_SUCCESS != code) break;
36,413!
4519
        if (pFunc->hasPk) {
36,413✔
4520
          code = nodesListMakeAppend(&cxt.pOtherCols, nodesListGetNode(pFunc->pParameterList, LIST_LENGTH(pFunc->pParameterList) - 1));
6,439!
4521
        }
4522
        if (TSDB_CODE_SUCCESS != code) break;
36,413!
4523
      } else {
4524
        pNode = nodesListGetNode(pFunc->pParameterList, 0);
3,445✔
4525
        code = nodesListMakeAppend(&cxt.pOtherCols, pNode);
3,445✔
4526
        if (TSDB_CODE_SUCCESS != code) break;
3,445!
4527

4528
        if (FUNCTION_TYPE_SELECT_VALUE == funcType) {
3,445✔
4529
          if (nodeType(pNode) == QUERY_NODE_COLUMN) {
3,294!
4530
            SColumnNode* pCol = (SColumnNode*)pNode;
3,294✔
4531
            if (pCol->colId == PRIMARYKEY_TIMESTAMP_COL_ID) {
3,294✔
4532
              pPKTsCol = pCol;
2,156✔
4533
            } else {
4534
              pNonPKCol = pCol;
1,138✔
4535
            }
4536
          }
4537
        }
4538
      }
4539
    }
4540
    if (TSDB_CODE_SUCCESS != code) break;
25,851!
4541
  }
4542

4543
  if (TSDB_CODE_SUCCESS != code) {
5,377!
4544
    taosArrayDestroy(isDuplicateCol);
×
4545
    nodesClearList(cxt.pLastCols);
×
4546
    return code;
×
4547
  }
4548

4549
  if (NULL != cxt.pLastCols) {
5,377✔
4550
    cxt.doAgg = false;
2,641✔
4551
    cxt.funcType = FUNCTION_TYPE_CACHE_LAST;
2,641✔
4552

4553
    lastRowScanOptSetLastTargets(pScan->pScanCols, cxt.pLastCols, pLastRowCols, true, cxt.pkBytes);
2,641✔
4554
    nodesWalkExprs(pScan->pScanPseudoCols, lastRowScanOptSetColDataType, &cxt);
2,641✔
4555
    if (TSDB_CODE_SUCCESS != cxt.code) {
2,641!
4556
      nodesClearList(cxt.pLastCols);
×
4557
      nodesClearList(cxt.pOtherCols);
×
4558
      taosArrayDestroy(isDuplicateCol);
×
4559
      return cxt.code;
×
4560
    }
4561
    lastRowScanOptSetLastTargets(pScan->node.pTargets, cxt.pLastCols, pLastRowCols, false, cxt.pkBytes);
2,641✔
4562
    lastRowScanOptRemoveUslessTargets(pScan->node.pTargets, cxt.pLastCols, cxt.pOtherCols, pLastRowCols);
2,641✔
4563
    if (pPKTsCol &&
2,641✔
4564
        ((cxt.pLastCols->length == 1 && nodesEqualNode((SNode*)pPKTsCol, nodesListGetNode(cxt.pLastCols, 0))) ||
1,310!
4565
         (pScan->node.pTargets->length == 2 && cxt.pkBytes > 0))) {
1,228✔
4566
      // when select last(ts),tbname,ts from ..., we add another ts to targets
4567
      sprintf(pPKTsCol->colName, "#sel_val.%p", pPKTsCol);
1,144✔
4568
      SNode* pNew = NULL;
1,144✔
4569
      code = nodesCloneNode((SNode*)pPKTsCol, &pNew);
1,144✔
4570
      if (TSDB_CODE_SUCCESS == code) {
1,144!
4571
        code = nodesListAppend(pScan->node.pTargets, pNew);
1,144✔
4572
      }
4573
      if (TSDB_CODE_SUCCESS != code) {
1,144!
4574
        nodesClearList(cxt.pLastCols);
×
4575
        nodesClearList(cxt.pOtherCols);
×
4576
        taosArrayDestroy(isDuplicateCol);
×
4577
        return code;
×
4578
      }
4579
    }
4580

4581
    if (pNonPKCol && cxt.pLastCols->length == 1 &&
3,378!
4582
        nodesEqualNode((SNode*)pNonPKCol, nodesListGetNode(cxt.pLastCols, 0))) {
737✔
4583
      // when select last(c1), c1 from ..., we add c1 to targets
4584
      sprintf(pNonPKCol->colName, "#sel_val.%p", pNonPKCol);
710✔
4585
      SNode* pNew = NULL;
710✔
4586
      code = nodesCloneNode((SNode*)pNonPKCol, &pNew);
710✔
4587
      if (TSDB_CODE_SUCCESS == code) {
710!
4588
        code = nodesListAppend(pScan->node.pTargets, pNew);
710✔
4589
      }
4590
    }
4591

4592
    nodesClearList(cxt.pLastCols);
2,641✔
4593
  }
4594
  nodesClearList(cxt.pOtherCols);
5,377✔
4595

4596
  pAgg->hasLastRow = false;
5,377✔
4597
  pAgg->hasLast = false;
5,377✔
4598

4599
  pCxt->optimized = true;
5,377✔
4600
  taosArrayDestroy(isDuplicateCol);
5,377✔
4601
  return TSDB_CODE_SUCCESS;
5,372✔
4602
}
4603

4604
static bool splitCacheLastFuncOptMayBeOptimized(SLogicNode* pNode, void* pCtx) {
4,256,471✔
4605
  if (QUERY_NODE_LOGIC_PLAN_AGG != nodeType(pNode) || 1 != LIST_LENGTH(pNode->pChildren) ||
4,256,471!
4606
      QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(nodesListGetNode(pNode->pChildren, 0))) {
781,440✔
4607
    return false;
3,708,712✔
4608
  }
4609

4610
  SAggLogicNode*  pAgg = (SAggLogicNode*)pNode;
547,759✔
4611
  SScanLogicNode* pScan = (SScanLogicNode*)nodesListGetNode(pNode->pChildren, 0);
547,759✔
4612
  if (!lastRowScanOptCheckLastCache(pAgg, pScan)) {
547,772✔
4613
    return false;
532,841✔
4614
  }
4615

4616
  bool hasOtherFunc = false;
14,928✔
4617
  if (!lastRowScanOptCheckFuncList(pNode, pScan->cacheLastMode, &hasOtherFunc)) {
14,928✔
4618
    return false;
248✔
4619
  }
4620

4621
  if (pAgg->hasGroup || !hasOtherFunc) {
14,680✔
4622
    return false;
14,346✔
4623
  }
4624

4625
  return true;
334✔
4626
}
4627

4628
static int32_t splitCacheLastFuncOptCreateAggLogicNode(SAggLogicNode** pNewAgg, SAggLogicNode* pAgg, SNodeList* pFunc,
334✔
4629
                                                       SNodeList* pTargets) {
4630
  SAggLogicNode* pNew = NULL;
334✔
4631
  int32_t code = nodesMakeNode(QUERY_NODE_LOGIC_PLAN_AGG, (SNode**)&pNew);
334✔
4632
  if (NULL == pNew) {
334!
4633
    nodesDestroyList(pFunc);
×
4634
    nodesDestroyList(pTargets);
×
4635
    return code;
×
4636
  }
4637

4638
  pNew->hasLastRow = false;
334✔
4639
  pNew->hasLast = false;
334✔
4640
  SNode* pFuncNode = NULL;
334✔
4641
  FOREACH(pFuncNode, pFunc) {
2,660!
4642
    SFunctionNode* pFunc = (SFunctionNode*)pFuncNode;
2,326✔
4643
    if (FUNCTION_TYPE_LAST_ROW == pFunc->funcType) {
2,326✔
4644
      pNew->hasLastRow = true;
1,052✔
4645
    } else if (FUNCTION_TYPE_LAST == pFunc->funcType) {
1,274✔
4646
      pNew->hasLast = true;
1,128✔
4647
    }
4648
  }
4649

4650
  pNew->hasTimeLineFunc = pAgg->hasTimeLineFunc;
334✔
4651
  pNew->hasGroupKeyOptimized = false;
334✔
4652
  pNew->onlyHasKeepOrderFunc = pAgg->onlyHasKeepOrderFunc;
334✔
4653
  pNew->node.groupAction = pAgg->node.groupAction;
334✔
4654
  pNew->node.requireDataOrder = pAgg->node.requireDataOrder;
334✔
4655
  pNew->node.resultDataOrder = pAgg->node.resultDataOrder;
334✔
4656
  pNew->node.pTargets = pTargets;
334✔
4657
  pNew->pAggFuncs = pFunc;
334✔
4658
  code = nodesCloneList(pAgg->pGroupKeys, &pNew->pGroupKeys);
334✔
4659
  if (TSDB_CODE_SUCCESS != code) {
334!
4660
    nodesDestroyNode((SNode*)pNew);
×
4661
    return code;
×
4662
  }
4663
  code = nodesCloneNode(pAgg->node.pConditions, &pNew->node.pConditions);
334✔
4664
  if (TSDB_CODE_SUCCESS != code) {
334!
4665
    nodesDestroyNode((SNode*)pNew);
×
4666
    return code;
×
4667
  }
4668
  pNew->isGroupTb = pAgg->isGroupTb;
334✔
4669
  pNew->isPartTb = pAgg->isPartTb;
334✔
4670
  pNew->hasGroup = pAgg->hasGroup;
334✔
4671
  code = nodesCloneList(pAgg->node.pChildren, &pNew->node.pChildren);
334✔
4672
  if (TSDB_CODE_SUCCESS != code) {
334!
4673
    nodesDestroyNode((SNode*)pNew);
×
4674
    return code;
×
4675
  }
4676

4677
  SNode*  pNode = nodesListGetNode(pNew->node.pChildren, 0);
334✔
4678
  if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pNode)) {
334!
4679
    SScanLogicNode* pScan = (SScanLogicNode*)pNode;
334✔
4680
    SNodeList*      pOldScanCols = NULL;
334✔
4681
    TSWAP(pScan->pScanCols, pOldScanCols);
334✔
4682
    nodesDestroyList(pScan->pScanPseudoCols);
334✔
4683
    pScan->pScanPseudoCols = NULL;
334✔
4684
    nodesDestroyList(pScan->node.pTargets);
334✔
4685
    pScan->node.pTargets = NULL;
334✔
4686
    SNodeListNode* list = NULL;
334✔
4687
    code = nodesMakeNode(QUERY_NODE_NODE_LIST, (SNode**)&list);
334✔
4688
    if (!list) {
334!
4689
      nodesDestroyNode((SNode*)pNew);
×
4690
      return code;
×
4691
    }
4692
    list->pNodeList = pFunc;
334✔
4693
    code = nodesCollectColumnsFromNode((SNode*)list, NULL, COLLECT_COL_TYPE_COL, &pScan->pScanCols);
334✔
4694
    if (TSDB_CODE_SUCCESS != code) {
334!
4695
      nodesDestroyNode((SNode*)pNew);
×
4696
      return code;
×
4697
    }
4698
    code = nodesCollectColumnsFromNode((SNode*)list, NULL, COLLECT_COL_TYPE_TAG, &pScan->pScanPseudoCols);
334✔
4699
    if (TSDB_CODE_SUCCESS != code) {
334!
4700
      nodesDestroyNode((SNode*)pNew);
×
4701
      return code;
×
4702
    }
4703
    nodesFree(list);
334✔
4704
    bool found = false;
334✔
4705
    FOREACH(pNode, pScan->pScanCols) {
404✔
4706
      if (PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pNode)->colId) {
384✔
4707
        found = true;
314✔
4708
        break;
314✔
4709
      }
4710
    }
4711
    if (!found) {
334✔
4712
      FOREACH(pNode, pOldScanCols) {
40!
4713
        if (PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pNode)->colId) {
40✔
4714
          SNode* pTmp = NULL;
20✔
4715
          code = nodesCloneNode(pNode, &pTmp);
20✔
4716
          if (TSDB_CODE_SUCCESS == code) {
20!
4717
            code = nodesListMakeStrictAppend(&pScan->pScanCols, pTmp);
20✔
4718
          }
4719
          break;
20✔
4720
        }
4721
      }
4722
      if (TSDB_CODE_SUCCESS != code) {
20!
4723
        nodesDestroyNode((SNode*)pNew);
×
4724
        return code;
×
4725
      }
4726
    }
4727
    nodesDestroyList(pOldScanCols);
334✔
4728
    code = createColumnByRewriteExprs(pScan->pScanCols, &pScan->node.pTargets);
334✔
4729
    if (TSDB_CODE_SUCCESS != code) {
334!
4730
      nodesDestroyNode((SNode*)pNew);
×
4731
      return code;
×
4732
    }
4733
    code = createColumnByRewriteExprs(pScan->pScanPseudoCols, &pScan->node.pTargets);
334✔
4734
    if (TSDB_CODE_SUCCESS != code) {
334!
4735
      nodesDestroyNode((SNode*)pNew);
×
4736
      return code;
×
4737
    }
4738
    OPTIMIZE_FLAG_CLEAR_MASK(pScan->node.optimizedFlag, OPTIMIZE_FLAG_SCAN_PATH);
334✔
4739
  }
4740

4741
  *pNewAgg = pNew;
334✔
4742

4743
  return TSDB_CODE_SUCCESS;
334✔
4744
}
4745

4746
static int32_t splitCacheLastFuncOptModifyAggLogicNode(SAggLogicNode* pAgg) {
334✔
4747
  pAgg->hasTimeLineFunc = false;
334✔
4748
  pAgg->onlyHasKeepOrderFunc = true;
334✔
4749

4750
  return TSDB_CODE_SUCCESS;
334✔
4751
}
4752

4753
static int32_t splitCacheLastFuncOptCreateMergeLogicNode(SMergeLogicNode** pNew, SAggLogicNode* pAgg1,
334✔
4754
                                                         SAggLogicNode* pAgg2) {
4755
  SMergeLogicNode* pMerge = NULL;
334✔
4756
  int32_t code = nodesMakeNode(QUERY_NODE_LOGIC_PLAN_MERGE, (SNode**)&pMerge);
334✔
4757
  if (NULL == pMerge) {
334!
4758
    return code;
×
4759
  }
4760
  pMerge->colsMerge = true;
334✔
4761
  pMerge->numOfChannels = 2;
334✔
4762
  pMerge->srcGroupId = -1;
334✔
4763
  pMerge->node.precision = pAgg1->node.precision;
334✔
4764

4765
  SNode* pNewAgg1 = NULL;
334✔
4766
  code = nodesCloneNode((SNode*)pAgg1, &pNewAgg1);
334✔
4767
  if (TSDB_CODE_SUCCESS != code) {
334!
4768
    nodesDestroyNode((SNode*)pMerge);
×
4769
    return code;
×
4770
  }
4771
  SNode* pNewAgg2 = NULL;
334✔
4772
  code = nodesCloneNode((SNode*)pAgg2, &pNewAgg2);
334✔
4773
  if (TSDB_CODE_SUCCESS != code) {
334!
4774
    nodesDestroyNode(pNewAgg1);
×
4775
    nodesDestroyNode((SNode*)pMerge);
×
4776
    return code;
×
4777
  }
4778

4779
  ((SAggLogicNode*)pNewAgg1)->node.pParent = (SLogicNode*)pMerge;
334✔
4780
  ((SAggLogicNode*)pNewAgg2)->node.pParent = (SLogicNode*)pMerge;
334✔
4781

4782
  SNode* pNode = NULL;
334✔
4783
  FOREACH(pNode, ((SAggLogicNode*)pNewAgg1)->node.pChildren) { ((SLogicNode*)pNode)->pParent = (SLogicNode*)pNewAgg1; }
668!
4784
  FOREACH(pNode, ((SAggLogicNode*)pNewAgg2)->node.pChildren) { ((SLogicNode*)pNode)->pParent = (SLogicNode*)pNewAgg2; }
668!
4785

4786
  SNodeList* pNewTargets1 = NULL;
334✔
4787
  code = nodesCloneList(pAgg1->node.pTargets, &pNewTargets1);
334✔
4788
  if (TSDB_CODE_SUCCESS == code) {
334!
4789
    code = nodesListMakeStrictAppendList(&pMerge->node.pTargets, pNewTargets1);
334✔
4790
  }
4791
  SNodeList* pNewTargets2 = NULL;
334✔
4792
  if (TSDB_CODE_SUCCESS == code) {
334!
4793
    code = nodesCloneList(pAgg2->node.pTargets, &pNewTargets2);
334✔
4794
  }
4795
  if (TSDB_CODE_SUCCESS == code) {
334!
4796
    code = nodesListMakeStrictAppendList(&pMerge->node.pTargets, pNewTargets2);
334✔
4797
  }
4798
  if (TSDB_CODE_SUCCESS == code) {
334!
4799
    code = nodesListMakeStrictAppend(&pMerge->node.pChildren, pNewAgg1);
334✔
4800
  }
4801
  if (TSDB_CODE_SUCCESS == code) {
334!
4802
    code = nodesListMakeStrictAppend(&pMerge->node.pChildren, pNewAgg2);
334✔
4803
  }
4804

4805
  if (TSDB_CODE_SUCCESS != code) {
334!
4806
    nodesDestroyNode(pNewAgg1);
×
4807
    nodesDestroyNode(pNewAgg2);
×
4808
    nodesDestroyNode((SNode*)pMerge);
×
4809
  } else {
4810
    *pNew = pMerge;
334✔
4811
  }
4812

4813
  return code;
334✔
4814
}
4815

4816
static int32_t splitCacheLastFuncOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
1,147,455✔
4817
  SAggLogicNode* pAgg = (SAggLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, splitCacheLastFuncOptMayBeOptimized, NULL);
1,147,455✔
4818

4819
  if (NULL == pAgg) {
1,147,458✔
4820
    return TSDB_CODE_SUCCESS;
1,147,124✔
4821
  }
4822
  SScanLogicNode* pScan = (SScanLogicNode*)nodesListGetNode(pAgg->node.pChildren, 0);
334✔
4823
  SNode*          pNode = NULL;
334✔
4824
  SNodeList*      pAggFuncList = NULL;
334✔
4825
  int32_t         code = 0;
334✔
4826

4827
  {
4828
    bool hasLast = false;
334✔
4829
    bool hasLastRow = false;
334✔
4830
    WHERE_EACH(pNode, pAgg->pAggFuncs) {
5,052!
4831
      SFunctionNode* pFunc = (SFunctionNode*)pNode;
4,718✔
4832
      int32_t        funcType = pFunc->funcType;
4,718✔
4833

4834
      if (isNeedSplitCacheLastFunc(pFunc, pScan)) {
4,718✔
4835
        SNode* pNew = NULL;
2,326✔
4836
        code = nodesCloneNode(pNode, &pNew);
2,326✔
4837
        if (TSDB_CODE_SUCCESS == code) {
2,326!
4838
          code = nodesListMakeStrictAppend(&pAggFuncList, pNew);
2,326✔
4839
        }
4840
        if (TSDB_CODE_SUCCESS != code) {
2,326!
4841
          break;
×
4842
        }
4843
        ERASE_NODE(pAgg->pAggFuncs);
2,326✔
4844
        continue;
2,326✔
4845
      }
4846
      if (FUNCTION_TYPE_LAST_ROW == funcType ) {
2,392✔
4847
        hasLastRow = true;
1,178✔
4848
      } else if (FUNCTION_TYPE_LAST == funcType) {
1,214!
4849
        hasLast = true;
1,214✔
4850
      }
4851
      WHERE_NEXT;    
2,392✔
4852
    }
4853
    pAgg->hasLast = hasLast;
334✔
4854
    pAgg->hasLastRow = hasLastRow;
334✔
4855
  }
4856
  if (TSDB_CODE_SUCCESS != code) {
334!
4857
    nodesDestroyList(pAggFuncList);
×
4858
    return code;
×
4859
  }
4860

4861
  if (NULL == pAggFuncList) {
334!
4862
    planError("empty agg func list while splite projections, funcNum:%d", pAgg->pAggFuncs->length);
×
4863
    return TSDB_CODE_PLAN_INTERNAL_ERROR;
×
4864
  }
4865

4866
  SNodeList* pTargets = NULL;
334✔
4867
  {
4868
    WHERE_EACH(pNode, pAgg->node.pTargets) {
5,052!
4869
      SColumnNode* pCol = (SColumnNode*)pNode;
4,718✔
4870
      SNode*       pFuncNode = NULL;
4,718✔
4871
      bool         found = false;
4,718✔
4872
      FOREACH(pFuncNode, pAggFuncList) {
70,226!
4873
        SFunctionNode* pFunc = (SFunctionNode*)pFuncNode;
67,834✔
4874
        if (0 == strcmp(pFunc->node.aliasName, pCol->colName)) {
67,834✔
4875
          SNode* pNew = NULL;
2,326✔
4876
          code = nodesCloneNode(pNode, &pNew);
2,326✔
4877
          if (TSDB_CODE_SUCCESS == code) {
2,326!
4878
            code = nodesListMakeStrictAppend(&pTargets, pNew);
2,326✔
4879
          }
4880
          found = true;
2,326✔
4881
          break;
2,326✔
4882
        }
4883
      }
4884
      if (TSDB_CODE_SUCCESS != code) {
4,718!
4885
        break;
×
4886
      }
4887
      if (found) {
4,718✔
4888
        ERASE_NODE(pAgg->node.pTargets);
2,326✔
4889
        continue;
2,326✔
4890
      }
4891
      WHERE_NEXT;
2,392✔
4892
    }
4893
  }
4894
  if (TSDB_CODE_SUCCESS != code) {
334!
4895
    nodesDestroyList(pTargets);
×
4896
    return code;
×
4897
  }
4898

4899
  if (NULL == pTargets) {
334!
4900
    planError("empty target func list while splite projections, targetsNum:%d", pAgg->node.pTargets->length);
×
4901
    nodesDestroyList(pAggFuncList);
×
4902
    return TSDB_CODE_PLAN_INTERNAL_ERROR;
×
4903
  }
4904

4905
  SMergeLogicNode* pMerge = NULL;
334✔
4906
  SAggLogicNode*   pNewAgg = NULL;
334✔
4907
  code = splitCacheLastFuncOptCreateAggLogicNode(&pNewAgg, pAgg, pAggFuncList, pTargets);
334✔
4908
  if (TSDB_CODE_SUCCESS == code) {
334!
4909
    code = splitCacheLastFuncOptModifyAggLogicNode(pAgg);
334✔
4910
  }
4911
  if (TSDB_CODE_SUCCESS == code) {
334!
4912
    code = splitCacheLastFuncOptCreateMergeLogicNode(&pMerge, pNewAgg, pAgg);
334✔
4913
  }
4914
  if (TSDB_CODE_SUCCESS == code) {
334!
4915
    code = replaceLogicNode(pLogicSubplan, (SLogicNode*)pAgg, (SLogicNode*)pMerge);
334✔
4916
  }
4917

4918
  nodesDestroyNode((SNode*)pAgg);
334✔
4919
  nodesDestroyNode((SNode*)pNewAgg);
334✔
4920

4921
  if (TSDB_CODE_SUCCESS != code) {
334!
4922
    nodesDestroyNode((SNode*)pMerge);
×
4923
  }
4924

4925
  pCxt->optimized = true;
334✔
4926
  return code;
334✔
4927
}
4928

4929
// merge projects
4930
static bool mergeProjectsMayBeOptimized(SLogicNode* pNode, void* pCtx) {
4,626,791✔
4931
  if (QUERY_NODE_LOGIC_PLAN_PROJECT != nodeType(pNode) || 1 != LIST_LENGTH(pNode->pChildren)) {
4,626,791✔
4932
    return false;
3,258,316✔
4933
  }
4934
  SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pNode->pChildren, 0);
1,368,475✔
4935
  if (QUERY_NODE_LOGIC_PLAN_PROJECT != nodeType(pChild) || 1 < LIST_LENGTH(pChild->pChildren) ||
1,368,476✔
4936
      NULL != pChild->pConditions || NULL != pChild->pLimit || NULL != pChild->pSlimit) {
167,685!
4937
    return false;
1,228,746✔
4938
  }
4939

4940
  return true;
139,730✔
4941
}
4942

4943
typedef struct SMergeProjectionsContext {
4944
  SProjectLogicNode* pChildProj;
4945
  int32_t            errCode;
4946
} SMergeProjectionsContext;
4947

4948
static EDealRes mergeProjectionsExpr2(SNode** pNode, void* pContext) {
625,157✔
4949
  SMergeProjectionsContext* pCxt = pContext;
625,157✔
4950
  SProjectLogicNode*        pChildProj = pCxt->pChildProj;
625,157✔
4951
  if (QUERY_NODE_COLUMN == nodeType(*pNode)) {
625,157✔
4952
    SColumnNode* pProjCol = (SColumnNode*)(*pNode);
381,415✔
4953
    SNode* pProjection;
4954
    int32_t projIdx = 1;
381,415✔
4955
    FOREACH(pProjection, pChildProj->pProjections) {
9,242,905!
4956
      if (isColRefExpr(pProjCol, (SExprNode*)pProjection)) {
9,242,905✔
4957
        SNode* pExpr = NULL;
381,415✔
4958
        pCxt->errCode = nodesCloneNode(pProjection, &pExpr);
381,415✔
4959
        if (pExpr == NULL) {
381,415!
4960
          return DEAL_RES_ERROR;
×
4961
        }
4962
        snprintf(((SExprNode*)pExpr)->aliasName, sizeof(((SExprNode*)pExpr)->aliasName), "%s",
381,415✔
4963
            ((SExprNode*)*pNode)->aliasName);
381,415✔
4964
        nodesDestroyNode(*pNode);
381,415✔
4965
        *pNode = pExpr;
381,415✔
4966
        return DEAL_RES_IGNORE_CHILD;
381,415✔
4967
      }
4968
    }
4969
  }
4970
  return DEAL_RES_CONTINUE;
243,742✔
4971
}
4972

4973
static EDealRes mergeProjectionsExpr(SNode** pNode, void* pContext) {
×
4974
  SMergeProjectionsContext* pCxt = pContext;
×
4975
  SProjectLogicNode*        pChildProj = pCxt->pChildProj;
×
4976
  if (QUERY_NODE_COLUMN == nodeType(*pNode)) {
×
4977
    SNode* pTarget;
4978
    FOREACH(pTarget, ((SLogicNode*)pChildProj)->pTargets) {
×
4979
      if (nodesEqualNode(pTarget, *pNode)) {
×
4980
        SNode* pProjection;
4981
        FOREACH(pProjection, pChildProj->pProjections) {
×
4982
          if (0 == strcmp(((SColumnNode*)pTarget)->colName, ((SExprNode*)pProjection)->aliasName)) {
×
4983
            SNode* pExpr = NULL;
×
4984
            pCxt->errCode = nodesCloneNode(pProjection, &pExpr);
×
4985
            if (pExpr == NULL) {
×
4986
              return DEAL_RES_ERROR;
×
4987
            }
4988
            snprintf(((SExprNode*)pExpr)->aliasName, sizeof(((SExprNode*)pExpr)->aliasName), "%s",
×
4989
                     ((SExprNode*)*pNode)->aliasName);
×
4990
            nodesDestroyNode(*pNode);
×
4991
            *pNode = pExpr;
×
4992
            return DEAL_RES_IGNORE_CHILD;
×
4993
          }
4994
        }
4995
      }
4996
    }
4997
  }
4998
  return DEAL_RES_CONTINUE;
×
4999
}
5000

5001
static int32_t mergeProjectsOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan, SLogicNode* pSelfNode) {
139,730✔
5002
  SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pSelfNode->pChildren, 0);
139,730✔
5003
  if (((SProjectLogicNode*)pChild)->ignoreGroupId) {
139,730✔
5004
    ((SProjectLogicNode*)pSelfNode)->inputIgnoreGroup = true;
122,325✔
5005
  }
5006
  SMergeProjectionsContext cxt = {.pChildProj = (SProjectLogicNode*)pChild, .errCode = TSDB_CODE_SUCCESS};
139,730✔
5007
  nodesRewriteExprs(((SProjectLogicNode*)pSelfNode)->pProjections, mergeProjectionsExpr2, &cxt);
139,730✔
5008
  int32_t code = cxt.errCode;
139,730✔
5009

5010
  if (TSDB_CODE_SUCCESS == code) {
139,730!
5011
    if (1 == LIST_LENGTH(pChild->pChildren)) {
276,752!
5012
      SLogicNode* pGrandChild = (SLogicNode*)nodesListGetNode(pChild->pChildren, 0);
137,022✔
5013
      code = replaceLogicNode(pLogicSubplan, pChild, pGrandChild);
137,022✔
5014
    } else {  // no grand child
5015
      NODES_CLEAR_LIST(pSelfNode->pChildren);
2,708✔
5016
    }
5017
  }
5018

5019
  if (TSDB_CODE_SUCCESS == code) {
139,730!
5020
    NODES_CLEAR_LIST(pChild->pChildren);
139,730✔
5021
  }
5022
  nodesDestroyNode((SNode*)pChild);
139,730✔
5023
  pCxt->optimized = true;
139,730✔
5024
  return code;
139,730✔
5025
}
5026

5027
static int32_t mergeProjectsOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
1,308,640✔
5028
  SLogicNode* pProjectNode = optFindPossibleNode(pLogicSubplan->pNode, mergeProjectsMayBeOptimized, NULL);
1,308,640✔
5029
  if (NULL == pProjectNode) {
1,308,644✔
5030
    return TSDB_CODE_SUCCESS;
1,168,914✔
5031
  }
5032

5033
  return mergeProjectsOptimizeImpl(pCxt, pLogicSubplan, pProjectNode);
139,730✔
5034
}
5035

5036
static bool tagScanOptShouldBeOptimized(SLogicNode* pNode, void* pCtx) {
4,235,020✔
5037
  if (QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(pNode) || (SCAN_TYPE_TAG == ((SScanLogicNode*)pNode)->scanType)) {
4,235,020✔
5038
    return false;
2,845,451✔
5039
  }
5040
  SScanLogicNode* pScan = (SScanLogicNode*)pNode;
1,389,569✔
5041
  if (pScan->hasNormalCols) {
1,389,569✔
5042
    return false;
1,252,551✔
5043
  }
5044
  if (pScan->tableType == TSDB_SYSTEM_TABLE) {
137,018✔
5045
    return false;
16✔
5046
  }
5047
  if (NULL == pNode->pParent || QUERY_NODE_LOGIC_PLAN_AGG != nodeType(pNode->pParent) ||
137,002✔
5048
      1 != LIST_LENGTH(pNode->pParent->pChildren)) {
40,736!
5049
    return false;
96,266✔
5050
  }
5051

5052
  SAggLogicNode* pAgg = (SAggLogicNode*)(pNode->pParent);
40,736✔
5053
  if (NULL == pAgg->pGroupKeys || NULL != pAgg->pAggFuncs || keysHasCol(pAgg->pGroupKeys) ||
40,736!
5054
      !planOptNodeListHasTbname(pAgg->pGroupKeys)) {
1,072✔
5055
    return false;
40,496✔
5056
  }
5057

5058
  SNode* pGroupKey = NULL;
240✔
5059
  FOREACH(pGroupKey, pAgg->pGroupKeys) {
487!
5060
    SNode* pGroup = NULL;
250✔
5061
    FOREACH(pGroup, ((SGroupingSetNode*)pGroupKey)->pParameterList) {
497!
5062
      if (QUERY_NODE_COLUMN != nodeType(pGroup)) {
250✔
5063
        return false;
3✔
5064
      }
5065
    }
5066
  }
5067
  return true;
237✔
5068
}
5069

5070
static int32_t tagScanOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
1,141,746✔
5071
  SScanLogicNode* pScanNode = (SScanLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, tagScanOptShouldBeOptimized, NULL);
1,141,746✔
5072
  if (NULL == pScanNode) {
1,141,742✔
5073
    return TSDB_CODE_SUCCESS;
1,141,504✔
5074
  }
5075

5076
  pScanNode->scanType = SCAN_TYPE_TAG;
238✔
5077
  SNode* pTarget = NULL;
238✔
5078
  FOREACH(pTarget, pScanNode->node.pTargets) {
238✔
5079
    if (PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)(pTarget))->colId) {
237!
5080
      ERASE_NODE(pScanNode->node.pTargets);
237✔
5081
      break;
237✔
5082
    }
5083
  }
5084

5085
  NODES_DESTORY_LIST(pScanNode->pScanCols);
238✔
5086

5087
  SLogicNode* pAgg = pScanNode->node.pParent;
237✔
5088
  if (NULL == pAgg->pParent) {
237!
5089
    SNodeList* pScanTargets = NULL;
×
5090
    int32_t code = nodesMakeList(&pScanTargets);
×
5091
    if (TSDB_CODE_SUCCESS != code) {
×
5092
      return code;
×
5093
    }
5094

5095
    SNode* pAggTarget = NULL;
×
5096
    FOREACH(pAggTarget, pAgg->pTargets) {
×
5097
      SNode* pScanTarget = NULL;
×
5098
      FOREACH(pScanTarget, pScanNode->node.pTargets) {
×
5099
        if (0 == strcmp(((SColumnNode*)pAggTarget)->colName, ((SColumnNode*)pScanTarget)->colName)) {
×
5100
          SNode* pNew = NULL;
×
5101
          code = nodesCloneNode(pScanTarget, &pNew);
×
5102
          if (TSDB_CODE_SUCCESS == code) {
×
5103
           code = nodesListAppend(pScanTargets, pNew);
×
5104
          }
5105
          break;
×
5106
        }
5107
      }
5108
      if (TSDB_CODE_SUCCESS != code) {
×
5109
        break;
×
5110
      }
5111
    }
5112
    nodesDestroyList(pScanNode->node.pTargets);
×
5113
    pScanNode->node.pTargets = pScanTargets;
×
5114
  }
5115

5116
  pScanNode->onlyMetaCtbIdx = false;
237✔
5117

5118
  pCxt->optimized = true;
237✔
5119
  return TSDB_CODE_SUCCESS;
237✔
5120
}
5121

5122
static bool pushDownLimitOptShouldBeOptimized(SLogicNode* pNode, void* pCtx) {
5,781,242✔
5123
  if ((NULL == pNode->pLimit && pNode->pSlimit == NULL) || 1 != LIST_LENGTH(pNode->pChildren)) {
5,781,242✔
5124
    return false;
5,457,043✔
5125
  }
5126

5127
  SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pNode->pChildren, 0);
324,199✔
5128
  if (pChild->pLimit || pChild->pSlimit) return false;
324,199✔
5129
  return true;
245,025✔
5130
}
5131

5132
static void swapLimit(SLogicNode* pParent, SLogicNode* pChild) {
41,567✔
5133
  pChild->pLimit = pParent->pLimit;
41,567✔
5134
  pParent->pLimit = NULL;
41,567✔
5135
}
41,567✔
5136

5137
static int32_t pushDownLimitHow(SLogicNode* pNodeWithLimit, SLogicNode* pNodeLimitPushTo, bool* pPushed);
5138
static int32_t pushDownLimitTo(SLogicNode* pNodeWithLimit, SLogicNode* pNodeLimitPushTo, bool* pPushed) {
230,010✔
5139
  int32_t code = 0;
230,010✔
5140
  bool cloned;
5141
  switch (nodeType(pNodeLimitPushTo)) {
230,010✔
5142
    case QUERY_NODE_LOGIC_PLAN_WINDOW: {
10,704✔
5143
      SWindowLogicNode* pWindow = (SWindowLogicNode*)pNodeLimitPushTo;
10,704✔
5144
      if (pWindow->winType != WINDOW_TYPE_INTERVAL) break;
10,704✔
5145
      code = cloneLimit(pNodeWithLimit, pNodeLimitPushTo, CLONE_LIMIT_SLIMIT, &cloned);
5,933✔
5146
      if (TSDB_CODE_SUCCESS == code) {
5,933!
5147
        *pPushed = true;
5,933✔
5148
      }
5149
      return code;
5,933✔
5150
    }
5151
    case QUERY_NODE_LOGIC_PLAN_SORT:
34,469✔
5152
      if (((SSortLogicNode*)pNodeLimitPushTo)->calcGroupId) break;
34,469✔
5153
      // fall through
5154
    case QUERY_NODE_LOGIC_PLAN_FILL: {
5155
      SNode* pChild = NULL;
34,664✔
5156
      code = cloneLimit(pNodeWithLimit, pNodeLimitPushTo, CLONE_LIMIT_SLIMIT, &cloned);
34,664✔
5157
      if (TSDB_CODE_SUCCESS != code) {
34,664!
5158
        return code;
×
5159
      }
5160
      FOREACH(pChild, pNodeLimitPushTo->pChildren) {
69,328!
5161
        code = pushDownLimitHow(pNodeLimitPushTo, (SLogicNode*)pChild, &cloned);
34,664✔
5162
        if (TSDB_CODE_SUCCESS != code) {
34,664!
5163
          return code;
×
5164
        }
5165
      }
5166
      *pPushed = true;
34,664✔
5167
      return code;
34,664✔
5168
    }
5169
    case QUERY_NODE_LOGIC_PLAN_AGG: {
48,006✔
5170
      if (nodeType(pNodeWithLimit) == QUERY_NODE_LOGIC_PLAN_PROJECT &&
91,829✔
5171
          (isPartTagAgg((SAggLogicNode*)pNodeLimitPushTo) || isPartTableAgg((SAggLogicNode*)pNodeLimitPushTo))) {
81,234✔
5172
        // when part by tag/tbname, slimit will be cloned to agg, and it will be pipelined.
5173
        // The scan below will do scanning with group order
5174
        code = cloneLimit(pNodeWithLimit, pNodeLimitPushTo, CLONE_SLIMIT, &cloned);
7,526✔
5175
        if (TSDB_CODE_SUCCESS == code) {
7,526!
5176
          *pPushed = cloned;
7,526✔
5177
        }
5178
        return code;
7,526✔
5179
      }
5180
      // else if not part by tag and tbname, the partition node below indicates that results are sorted, the agg node
5181
      // can be pipelined.
5182
      if (nodeType(pNodeWithLimit) == QUERY_NODE_LOGIC_PLAN_PROJECT && LIST_LENGTH(pNodeLimitPushTo->pChildren) == 1) {
40,480!
5183
        SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pNodeLimitPushTo->pChildren, 0);
36,297✔
5184
        if (nodeType(pChild) == QUERY_NODE_LOGIC_PLAN_PARTITION) {
36,297✔
5185
          pNodeLimitPushTo->forceCreateNonBlockingOptr = true;
325✔
5186
          code = cloneLimit(pNodeWithLimit, pNodeLimitPushTo, CLONE_SLIMIT, &cloned);
325✔
5187
          if (TSDB_CODE_SUCCESS == code) {
325!
5188
            *pPushed = cloned;
325✔
5189
          }
5190
          return code;
325✔
5191
        }
5192
        // Currently, partColOpt is executed after pushDownLimitOpt, and partColOpt will replace partition node with
5193
        // sort node.
5194
        // To avoid dependencies between these two optimizations, we add sort node too.
5195
        if (nodeType(pChild) == QUERY_NODE_LOGIC_PLAN_SORT && ((SSortLogicNode*)pChild)->calcGroupId) {
35,972!
5196
          pNodeLimitPushTo->forceCreateNonBlockingOptr = true;
×
5197
          code = cloneLimit(pNodeWithLimit, pNodeLimitPushTo, CLONE_SLIMIT, &cloned);
×
5198
          if (TSDB_CODE_SUCCESS == code) {
×
5199
            *pPushed = cloned;
×
5200
          }
5201
          return code;
×
5202
        }
5203
      }
5204
      break;
40,155✔
5205
    }
5206
    case QUERY_NODE_LOGIC_PLAN_SCAN:
50,659✔
5207
      if (nodeType(pNodeWithLimit) == QUERY_NODE_LOGIC_PLAN_PROJECT && pNodeWithLimit->pLimit) {
50,659✔
5208
        if (((SProjectLogicNode*)pNodeWithLimit)->inputIgnoreGroup) {
42,181✔
5209
          code = cloneLimit(pNodeWithLimit, pNodeLimitPushTo, CLONE_LIMIT, &cloned);
614✔
5210
        } else {
5211
          swapLimit(pNodeWithLimit, pNodeLimitPushTo);
41,567✔
5212
        }
5213
        if (TSDB_CODE_SUCCESS == code) {
42,181!
5214
          *pPushed = true;
42,181✔
5215
        }
5216
        return code;
42,181✔
5217
      }
5218
      break;
8,478✔
5219
    case QUERY_NODE_LOGIC_PLAN_JOIN: {
12,936✔
5220
      code = cloneLimit(pNodeWithLimit, pNodeLimitPushTo, CLONE_LIMIT, &cloned);
12,936✔
5221
      break;
12,936✔
5222
    }
5223
    default:
72,945✔
5224
      break;
72,945✔
5225
  }
5226
  *pPushed = false;
139,381✔
5227
  return code;
139,381✔
5228
}
5229

5230
static int32_t pushDownLimitHow(SLogicNode* pNodeWithLimit, SLogicNode* pNodeLimitPushTo, bool* pPushed) {
279,689✔
5231
  switch (nodeType(pNodeWithLimit)) {
279,689✔
5232
    case QUERY_NODE_LOGIC_PLAN_PROJECT:
180,342✔
5233
    case QUERY_NODE_LOGIC_PLAN_FILL:
5234
      return pushDownLimitTo(pNodeWithLimit, pNodeLimitPushTo, pPushed);
180,342✔
5235
    case QUERY_NODE_LOGIC_PLAN_SORT: {
90,876✔
5236
      SSortLogicNode* pSort = (SSortLogicNode*)pNodeWithLimit;
90,876✔
5237
      if (sortPriKeyOptIsPriKeyOrderBy(pSort->pSortKeys)) return pushDownLimitTo(pNodeWithLimit, pNodeLimitPushTo, pPushed);
90,876✔
5238
    }
5239
    default:
5240
      break;
49,679✔
5241
  }
5242
  *pPushed = false;
49,679✔
5243
  return TSDB_CODE_SUCCESS;
49,679✔
5244
}
5245

5246
static int32_t pushDownLimitOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
1,538,431✔
5247
  SLogicNode* pNode = optFindPossibleNode(pLogicSubplan->pNode, pushDownLimitOptShouldBeOptimized, NULL);
1,538,431✔
5248
  if (NULL == pNode) {
1,538,439✔
5249
    return TSDB_CODE_SUCCESS;
1,293,414✔
5250
  }
5251

5252
  SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pNode->pChildren, 0);
245,025✔
5253
  nodesDestroyNode(pChild->pLimit);
245,025✔
5254
  bool pushed = false;
245,025✔
5255
  int32_t code = pushDownLimitHow(pNode, pChild, &pushed);
245,025✔
5256
  if (TSDB_CODE_SUCCESS != code) {
245,025!
5257
    return code;
×
5258
  }
5259
  if (pushed) {
245,025✔
5260
    pCxt->optimized = true;
84,365✔
5261
  }
5262
  return TSDB_CODE_SUCCESS;
245,025✔
5263
}
5264

5265
typedef struct STbCntScanOptInfo {
5266
  SAggLogicNode*  pAgg;
5267
  SScanLogicNode* pScan;
5268
  SName           table;
5269
} STbCntScanOptInfo;
5270

5271
static bool tbCntScanOptIsEligibleGroupKeys(SNodeList* pGroupKeys) {
541,093✔
5272
  if (NULL == pGroupKeys) {
541,093✔
5273
    return true;
411,076✔
5274
  }
5275

5276
  SNode* pGroupKey = NULL;
130,017✔
5277
  FOREACH(pGroupKey, pGroupKeys) {
130,050!
5278
    SNode* pKey = nodesListGetNode(((SGroupingSetNode*)pGroupKey)->pParameterList, 0);
130,028✔
5279
    if (QUERY_NODE_COLUMN != nodeType(pKey)) {
130,030✔
5280
      return false;
94,017✔
5281
    }
5282
    SColumnNode* pCol = (SColumnNode*)pKey;
36,013✔
5283
    if (0 != strcmp(pCol->colName, "db_name") && 0 != strcmp(pCol->colName, "stable_name")) {
36,013✔
5284
      return false;
35,980✔
5285
    }
5286
  }
5287

5288
  return true;
22✔
5289
}
5290

5291
static bool tbCntScanOptNotNullableExpr(SNode* pNode) {
161,213✔
5292
  if (QUERY_NODE_COLUMN != nodeType(pNode)) {
161,213✔
5293
    return false;
3,582✔
5294
  }
5295
  const char* pColName = ((SColumnNode*)pNode)->colName;
157,631✔
5296
  return 0 == strcmp(pColName, "*") || 0 == strcmp(pColName, "db_name") || 0 == strcmp(pColName, "stable_name") ||
315,262!
5297
         0 == strcmp(pColName, "table_name");
157,631✔
5298
}
5299

5300
static bool tbCntScanOptIsEligibleAggFuncs(SNodeList* pAggFuncs) {
411,099✔
5301
  SNode* pNode = NULL;
411,099✔
5302
  FOREACH(pNode, pAggFuncs) {
411,138!
5303
    SFunctionNode* pFunc = (SFunctionNode*)nodesListGetNode(pAggFuncs, 0);
411,098✔
5304
    if (FUNCTION_TYPE_COUNT != pFunc->funcType ||
411,099✔
5305
        !tbCntScanOptNotNullableExpr(nodesListGetNode(pFunc->pParameterList, 0))) {
161,213✔
5306
      return false;
411,060✔
5307
    }
5308
  }
5309
  return LIST_LENGTH(pAggFuncs) > 0;
40!
5310
}
5311

5312
static bool tbCntScanOptIsEligibleAgg(SAggLogicNode* pAgg) {
541,094✔
5313
  return tbCntScanOptIsEligibleGroupKeys(pAgg->pGroupKeys) && tbCntScanOptIsEligibleAggFuncs(pAgg->pAggFuncs);
541,094✔
5314
}
5315

5316
static bool tbCntScanOptGetColValFromCond(SOperatorNode* pOper, SColumnNode** pCol, SValueNode** pVal) {
21✔
5317
  if (OP_TYPE_EQUAL != pOper->opType) {
21✔
5318
    return false;
6✔
5319
  }
5320

5321
  *pCol = NULL;
15✔
5322
  *pVal = NULL;
15✔
5323
  if (QUERY_NODE_COLUMN == nodeType(pOper->pLeft)) {
15!
5324
    *pCol = (SColumnNode*)pOper->pLeft;
15✔
5325
  } else if (QUERY_NODE_VALUE == nodeType(pOper->pLeft)) {
×
5326
    *pVal = (SValueNode*)pOper->pLeft;
×
5327
  }
5328
  if (QUERY_NODE_COLUMN == nodeType(pOper->pRight)) {
15!
5329
    *pCol = (SColumnNode*)pOper->pRight;
×
5330
  } else if (QUERY_NODE_VALUE == nodeType(pOper->pRight)) {
15!
5331
    *pVal = (SValueNode*)pOper->pRight;
15✔
5332
  }
5333

5334
  return NULL != *pCol && NULL != *pVal;
15!
5335
}
5336

5337
static bool tbCntScanOptIsEligibleLogicCond(STbCntScanOptInfo* pInfo, SLogicConditionNode* pCond) {
9✔
5338
  if (LOGIC_COND_TYPE_AND != pCond->condType) {
9!
5339
    return false;
×
5340
  }
5341

5342
  bool         hasDbCond = false;
9✔
5343
  bool         hasStbCond = false;
9✔
5344
  SColumnNode* pCol = NULL;
9✔
5345
  SValueNode*  pVal = NULL;
9✔
5346
  SNode*       pNode = NULL;
9✔
5347
  FOREACH(pNode, pCond->pParameterList) {
21!
5348
    if (QUERY_NODE_OPERATOR != nodeType(pNode) || !tbCntScanOptGetColValFromCond((SOperatorNode*)pNode, &pCol, &pVal)) {
18!
5349
      return false;
6✔
5350
    }
5351
    if (!hasDbCond && 0 == strcmp(pCol->colName, "db_name")) {
12!
5352
      hasDbCond = true;
9✔
5353
      strcpy(pInfo->table.dbname, pVal->literal);
9✔
5354
    } else if (!hasStbCond && 0 == strcmp(pCol->colName, "stable_name")) {
3!
5355
      hasStbCond = true;
3✔
5356
      strcpy(pInfo->table.tname, pVal->literal);
3✔
5357
    } else {
5358
      return false;
×
5359
    }
5360
  }
5361
  return hasDbCond;
3✔
5362
}
5363

5364
static bool tbCntScanOptIsEligibleOpCond(SOperatorNode* pCond) {
3✔
5365
  SColumnNode* pCol = NULL;
3✔
5366
  SValueNode*  pVal = NULL;
3✔
5367
  if (!tbCntScanOptGetColValFromCond(pCond, &pCol, &pVal)) {
3!
5368
    return false;
×
5369
  }
5370
  return 0 == strcmp(pCol->colName, "db_name");
3✔
5371
}
5372

5373
static bool tbCntScanOptIsEligibleConds(STbCntScanOptInfo* pInfo, SNode* pConditions) {
37✔
5374
  if (NULL == pConditions) {
37✔
5375
    return true;
19✔
5376
  }
5377
  if (LIST_LENGTH(pInfo->pAgg->pGroupKeys) != 0) {
18!
5378
    return false;
6✔
5379
  }
5380
  if (QUERY_NODE_LOGIC_CONDITION == nodeType(pConditions)) {
12✔
5381
    return tbCntScanOptIsEligibleLogicCond(pInfo, (SLogicConditionNode*)pConditions);
9✔
5382
  }
5383

5384
  if (QUERY_NODE_OPERATOR == nodeType(pConditions)) {
3!
5385
    return tbCntScanOptIsEligibleOpCond((SOperatorNode*)pConditions);
3✔
5386
  }
5387

5388
  return false;
×
5389
}
5390

5391
static bool tbCntScanOptIsEligibleScan(STbCntScanOptInfo* pInfo) {
39✔
5392
  if (0 != strcmp(pInfo->pScan->tableName.dbname, TSDB_INFORMATION_SCHEMA_DB) ||
39!
5393
      0 != strcmp(pInfo->pScan->tableName.tname, TSDB_INS_TABLE_TABLES) || NULL != pInfo->pScan->pGroupTags) {
39!
5394
    return false;
2✔
5395
  }
5396
  if (1 == pInfo->pScan->pVgroupList->numOfVgroups && MNODE_HANDLE == pInfo->pScan->pVgroupList->vgroups[0].vgId) {
37!
5397
    return false;
×
5398
  }
5399
  return tbCntScanOptIsEligibleConds(pInfo, pInfo->pScan->node.pConditions);
37✔
5400
}
5401

5402
static bool tbCntScanOptShouldBeOptimized(SLogicNode* pNode, STbCntScanOptInfo* pInfo) {
4,233,929✔
5403
  if (QUERY_NODE_LOGIC_PLAN_AGG != nodeType(pNode) || 1 != LIST_LENGTH(pNode->pChildren) ||
4,233,929!
5404
      QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(nodesListGetNode(pNode->pChildren, 0))) {
774,595✔
5405
    return false;
3,692,843✔
5406
  }
5407

5408
  pInfo->pAgg = (SAggLogicNode*)pNode;
541,084✔
5409
  pInfo->pScan = (SScanLogicNode*)nodesListGetNode(pNode->pChildren, 0);
541,084✔
5410
  return tbCntScanOptIsEligibleAgg(pInfo->pAgg) && tbCntScanOptIsEligibleScan(pInfo);
541,097✔
5411
}
5412

5413
static int32_t tbCntScanOptCreateTableCountFunc(SNode** ppNode) {
25✔
5414
  SFunctionNode* pFunc = NULL;
25✔
5415
  int32_t code = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&pFunc);
25✔
5416
  if (NULL == pFunc) {
25!
5417
    return code;
×
5418
  }
5419
  strcpy(pFunc->functionName, "_table_count");
25✔
5420
  strcpy(pFunc->node.aliasName, "_table_count");
25✔
5421
  code = fmGetFuncInfo(pFunc, NULL, 0);
25✔
5422
  if (TSDB_CODE_SUCCESS != code) {
25!
5423
    nodesDestroyNode((SNode*)pFunc);
×
5424
    return code;
×
5425
  }
5426
  *ppNode = (SNode*)pFunc;
25✔
5427
  return code;
25✔
5428
}
5429

5430
static int32_t tbCntScanOptRewriteScan(STbCntScanOptInfo* pInfo) {
25✔
5431
  pInfo->pScan->scanType = SCAN_TYPE_TABLE_COUNT;
25✔
5432
  strcpy(pInfo->pScan->tableName.dbname, pInfo->table.dbname);
25✔
5433
  strcpy(pInfo->pScan->tableName.tname, pInfo->table.tname);
25✔
5434
  NODES_DESTORY_LIST(pInfo->pScan->node.pTargets);
25✔
5435
  NODES_DESTORY_LIST(pInfo->pScan->pScanCols);
25✔
5436
  NODES_DESTORY_NODE(pInfo->pScan->node.pConditions);
25✔
5437
  NODES_DESTORY_LIST(pInfo->pScan->pScanPseudoCols);
25✔
5438
  SNode* pNew = NULL;
25✔
5439
  int32_t code = tbCntScanOptCreateTableCountFunc(&pNew);
25✔
5440
  if (TSDB_CODE_SUCCESS == code) {
25!
5441
    code = nodesListMakeStrictAppend(&pInfo->pScan->pScanPseudoCols, pNew);
25✔
5442
  }
5443
  if (TSDB_CODE_SUCCESS == code) {
25!
5444
    code = createColumnByRewriteExpr(nodesListGetNode(pInfo->pScan->pScanPseudoCols, 0), &pInfo->pScan->node.pTargets);
25✔
5445
  }
5446
  SNode* pGroupKey = NULL;
25✔
5447
  if (TSDB_CODE_SUCCESS  == code) {
25!
5448
    FOREACH(pGroupKey, pInfo->pAgg->pGroupKeys) {
48✔
5449
      SNode* pGroupCol = nodesListGetNode(((SGroupingSetNode*)pGroupKey)->pParameterList, 0);
23✔
5450
      SNode* pNew = NULL;
23✔
5451
      code = nodesCloneNode(pGroupCol, &pNew);
23✔
5452
      if (TSDB_CODE_SUCCESS == code) {
23!
5453
        code = nodesListMakeStrictAppend(&pInfo->pScan->pGroupTags, pNew);
23✔
5454
      }
5455
      if (TSDB_CODE_SUCCESS == code) {
23!
5456
        pNew = NULL;
23✔
5457
        code = nodesCloneNode(pGroupCol, &pNew);
23✔
5458
        if (TSDB_CODE_SUCCESS == code) {
23!
5459
          code = nodesListMakeStrictAppend(&pInfo->pScan->pScanCols, pNew);
23✔
5460
        }
5461
      }
5462
      if (TSDB_CODE_SUCCESS == code) {
23!
5463
        pNew = NULL;
23✔
5464
        code = nodesCloneNode(pGroupCol, &pNew);
23✔
5465
        if (TSDB_CODE_SUCCESS == code) {
23!
5466
          code = nodesListMakeStrictAppend(&pInfo->pScan->node.pTargets, pNew);
23✔
5467
        }
5468
      }
5469
      if (TSDB_CODE_SUCCESS != code) {
23!
5470
        break;
×
5471
      }
5472
    }
5473
  }
5474
  return code;
25✔
5475
}
5476

5477
static int32_t tbCntScanOptCreateSumFunc(SFunctionNode* pCntFunc, SNode* pParam, SNode** pOutput) {
25✔
5478
  SFunctionNode* pFunc = NULL;
25✔
5479
  int32_t code = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&pFunc);
25✔
5480
  if (NULL == pFunc) {
25!
5481
    return code;
×
5482
  }
5483
  strcpy(pFunc->functionName, "sum");
25✔
5484
  strcpy(pFunc->node.aliasName, pCntFunc->node.aliasName);
25✔
5485
  code = createColumnByRewriteExpr(pParam, &pFunc->pParameterList);
25✔
5486
  if (TSDB_CODE_SUCCESS == code) {
25!
5487
    code = fmGetFuncInfo(pFunc, NULL, 0);
25✔
5488
  }
5489
  if (TSDB_CODE_SUCCESS == code) {
25!
5490
    *pOutput = (SNode*)pFunc;
25✔
5491
  } else {
5492
    nodesDestroyNode((SNode*)pFunc);
×
5493
  }
5494
  return code;
25✔
5495
}
5496

5497
static int32_t tbCntScanOptRewriteAgg(SAggLogicNode* pAgg) {
25✔
5498
  SScanLogicNode* pScan = (SScanLogicNode*)nodesListGetNode(pAgg->node.pChildren, 0);
25✔
5499
  SNode*          pSum = NULL;
25✔
5500
  int32_t         code = tbCntScanOptCreateSumFunc((SFunctionNode*)nodesListGetNode(pAgg->pAggFuncs, 0),
25✔
5501
                                                   nodesListGetNode(pScan->pScanPseudoCols, 0), &pSum);
5502
  if (TSDB_CODE_SUCCESS == code) {
25!
5503
    NODES_DESTORY_LIST(pAgg->pAggFuncs);
25✔
5504
    code = nodesListMakeStrictAppend(&pAgg->pAggFuncs, pSum);
25✔
5505
  }
5506
  if (TSDB_CODE_SUCCESS == code) {
25!
5507
    code = partTagsRewriteGroupTagsToFuncs(pScan->pGroupTags, 0, pAgg);
25✔
5508
  }
5509
  NODES_DESTORY_LIST(pAgg->pGroupKeys);
25✔
5510
  return code;
25✔
5511
}
5512

5513
static int32_t tableCountScanOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
1,141,499✔
5514
  STbCntScanOptInfo info = {0};
1,141,499✔
5515
  if (!optFindEligibleNode(pLogicSubplan->pNode, (FShouldBeOptimized)tbCntScanOptShouldBeOptimized, &info)) {
1,141,499✔
5516
    return TSDB_CODE_SUCCESS;
1,141,488✔
5517
  }
5518

5519
  int32_t code = tbCntScanOptRewriteScan(&info);
24✔
5520
  if (TSDB_CODE_SUCCESS == code) {
25!
5521
    code = tbCntScanOptRewriteAgg(info.pAgg);
25✔
5522
  }
5523
  return code;
25✔
5524
}
5525

5526
static SSortLogicNode* sortNonPriKeySatisfied(SLogicNode* pNode) {
7,650,633✔
5527
  if (QUERY_NODE_LOGIC_PLAN_SORT != nodeType(pNode)) {
7,650,633✔
5528
    return NULL;
6,833,424✔
5529
  }
5530
  SSortLogicNode* pSort = (SSortLogicNode*)pNode;
817,209✔
5531
  if (sortPriKeyOptIsPriKeyOrderBy(pSort->pSortKeys)) {
817,209✔
5532
    return NULL;
225,551✔
5533
  }
5534
  SNode *pSortKeyNode = NULL, *pSortKeyExpr = NULL;
591,661✔
5535
  FOREACH(pSortKeyNode, pSort->pSortKeys) {
1,444,368!
5536
    pSortKeyExpr = ((SOrderByExprNode*)pSortKeyNode)->pExpr;
852,920✔
5537
    switch (nodeType(pSortKeyExpr)) {
852,920✔
5538
      case QUERY_NODE_COLUMN:
852,697✔
5539
        break;
852,697✔
5540
      case QUERY_NODE_VALUE:
10✔
5541
        continue;
10✔
5542
      default:
213✔
5543
        return NULL;
213✔
5544
    }
5545
  }
5546

5547
  if (!pSortKeyExpr || ((SColumnNode*)pSortKeyExpr)->projIdx != 1 ||
591,448!
5548
      ((SColumnNode*)pSortKeyExpr)->node.resType.type != TSDB_DATA_TYPE_TIMESTAMP) {
195,085✔
5549
    return NULL;
571,876✔
5550
  }
5551
  return pSort;
19,572✔
5552
}
5553

5554
static bool sortNonPriKeyShouldOptimize(SLogicNode* pNode, void* pInfo) {
7,650,632✔
5555
  SSortLogicNode* pSort = sortNonPriKeySatisfied(pNode);
7,650,632✔
5556
  if (!pSort) return false;
7,650,637✔
5557
  SOptimizePKCtx* ctx = pInfo;
19,570✔
5558
  ctx->code = nodesListAppend(ctx->pList, (SNode*)pSort);
19,570✔
5559
  return false;
19,572✔
5560
}
5561

5562
static int32_t sortNonPriKeyOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
1,684,243✔
5563
  SNodeList* pNodeList = NULL;
1,684,243✔
5564
  int32_t code = nodesMakeList(&pNodeList);
1,684,243✔
5565
  if (TSDB_CODE_SUCCESS != code) {
1,684,250!
5566
    return code;
×
5567
  }
5568
  SOptimizePKCtx ctx = {.pList = pNodeList, .code = 0};
1,684,250✔
5569
  (void)optFindEligibleNode(pLogicSubplan->pNode, sortNonPriKeyShouldOptimize, &ctx);
1,684,250✔
5570
  if (TSDB_CODE_SUCCESS != ctx.code) {
1,684,249!
UNCOV
5571
    nodesClearList(pNodeList);
×
5572
    return code;
×
5573
  }
5574
  SNode* pNode = NULL;
1,684,251✔
5575
  FOREACH(pNode, pNodeList) {
1,703,821!
5576
    SSortLogicNode*   pSort = (SSortLogicNode*)pNode;
19,572✔
5577
    SOrderByExprNode* pOrderByExpr = (SOrderByExprNode*)nodesListGetNode(pSort->pSortKeys, 0);
19,572✔
5578
    pSort->node.outputTsOrder = pOrderByExpr->order;
19,572✔
5579
    optSetParentOrder(pSort->node.pParent, pOrderByExpr->order, NULL);
19,572✔
5580
  }
5581
  pCxt->optimized = false;
1,684,249✔
5582
  nodesClearList(pNodeList);
1,684,249✔
5583
  return TSDB_CODE_SUCCESS;
1,684,249✔
5584
}
5585

5586
static bool hashJoinOptShouldBeOptimized(SLogicNode* pNode, void* pCtx) {
7,780,078✔
5587
  bool res = false;
7,780,078✔
5588
  if (QUERY_NODE_LOGIC_PLAN_JOIN != nodeType(pNode)) {
7,780,078✔
5589
    return res;
7,487,665✔
5590
  }
5591

5592
  SJoinLogicNode* pJoin = (SJoinLogicNode*)pNode;
292,413✔
5593
  if (pJoin->joinAlgo != JOIN_ALGO_UNKNOWN) {
292,413✔
5594
    return res;
177,674✔
5595
  }
5596
  
5597
  if (!pJoin->hashJoinHint) {
114,739!
5598
    goto _return;
114,743✔
5599
  }
5600

5601
  if ((JOIN_STYPE_NONE != pJoin->subType && JOIN_STYPE_OUTER != pJoin->subType) || JOIN_TYPE_FULL == pJoin->joinType || pNode->pChildren->length != 2 ) {
×
5602
    goto _return;
×
5603
  }
5604

5605
  res = true;
×
5606

5607
_return:
114,739✔
5608

5609
  if (!res && DATA_ORDER_LEVEL_NONE == pJoin->node.requireDataOrder) {
114,739!
5610
    pJoin->node.requireDataOrder = DATA_ORDER_LEVEL_GLOBAL;
×
5611
    int32_t *pCode = pCtx;
×
5612
    int32_t code = adjustLogicNodeDataRequirement(pNode, pJoin->node.requireDataOrder);
×
5613
    if (TSDB_CODE_SUCCESS != code) {
×
5614
      *pCode = code;
×
5615
    }
5616
  }
5617

5618
  return res;
114,739✔
5619
}
5620

5621
static int32_t hashJoinOptSplitPrimFromLogicCond(SNode **pCondition, SNode **pPrimaryKeyCond) {
×
5622
  SLogicConditionNode *pLogicCond = (SLogicConditionNode *)(*pCondition);
×
5623
  int32_t code = TSDB_CODE_SUCCESS;
×
5624
  SNodeList *pPrimaryKeyConds = NULL;
×
5625
  SNode     *pCond = NULL;
×
5626
  WHERE_EACH(pCond, pLogicCond->pParameterList) {
×
5627
    bool result = false;
×
5628
    code = filterIsMultiTableColsCond(pCond, &result);
×
5629
    if (TSDB_CODE_SUCCESS != code) {
×
5630
      break;
×
5631
    }
5632

5633
    if (result || COND_TYPE_PRIMARY_KEY != filterClassifyCondition(pCond)) {
×
5634
      WHERE_NEXT;
×
5635
      continue;
×
5636
    }
5637

5638
    SNode* pNew = NULL;
×
5639
    code = nodesCloneNode(pCond, &pNew);
×
5640
    if (TSDB_CODE_SUCCESS == code) {
×
5641
      code = nodesListMakeAppend(&pPrimaryKeyConds, pNew);
×
5642
    }
5643
    if (TSDB_CODE_SUCCESS != code) {
×
5644
      break;
×
5645
    }
5646
    
5647
    ERASE_NODE(pLogicCond->pParameterList);
×
5648
  }
5649

5650
  SNode *pTempPrimaryKeyCond = NULL;
×
5651
  if (TSDB_CODE_SUCCESS == code && pPrimaryKeyConds) {
×
5652
    code = nodesMergeConds(&pTempPrimaryKeyCond, &pPrimaryKeyConds);
×
5653
  }
5654

5655
  if (TSDB_CODE_SUCCESS == code && pTempPrimaryKeyCond) {
×
5656
    *pPrimaryKeyCond = pTempPrimaryKeyCond;
×
5657

5658
    if (pLogicCond->pParameterList->length <= 0) {
×
5659
      nodesDestroyNode(*pCondition);
×
5660
      *pCondition = NULL;
×
5661
    }
5662
  } else {
5663
    nodesDestroyList(pPrimaryKeyConds);
×
5664
    nodesDestroyNode(pTempPrimaryKeyCond);
×
5665
  }
5666

5667
  return code;
×
5668
}
5669

5670

5671
int32_t hashJoinOptSplitPrimCond(SNode **pCondition, SNode **pPrimaryKeyCond) {
×
5672
  if (QUERY_NODE_LOGIC_CONDITION == nodeType(*pCondition)) {
×
5673
    if (LOGIC_COND_TYPE_AND == ((SLogicConditionNode *)*pCondition)->condType) {
×
5674
      return hashJoinOptSplitPrimFromLogicCond(pCondition, pPrimaryKeyCond);
×
5675
    }
5676

5677
    return TSDB_CODE_SUCCESS;
×
5678
  }
5679

5680
  bool needOutput = false;
×
5681
  bool result = false;
×
5682
  int32_t code = filterIsMultiTableColsCond(*pCondition, &result);
×
5683
  if (TSDB_CODE_SUCCESS != code) {
×
5684
    return code;
×
5685
  }
5686
  if (result) {
×
5687
    return TSDB_CODE_SUCCESS;
×
5688
  }
5689

5690
  EConditionType type = filterClassifyCondition(*pCondition);
×
5691
  if (COND_TYPE_PRIMARY_KEY == type) {
×
5692
    *pPrimaryKeyCond = *pCondition;
×
5693
    *pCondition = NULL;
×
5694
  }
5695

5696
  return TSDB_CODE_SUCCESS;
×
5697
}
5698

5699

5700
static int32_t hashJoinOptRewriteJoin(SOptimizeContext* pCxt, SLogicNode* pNode, SLogicSubplan* pLogicSubplan) {
×
5701
  SJoinLogicNode* pJoin = (SJoinLogicNode*)pNode;
×
5702
  int32_t code = TSDB_CODE_SUCCESS;
×
5703

5704
  pJoin->joinAlgo = JOIN_ALGO_HASH;
×
5705

5706
  if (NULL != pJoin->pColOnCond) {
×
5707
#if 0  
5708
    EJoinType t = pJoin->joinType;
5709
    EJoinSubType s = pJoin->subType;
5710

5711
    pJoin->joinType = JOIN_TYPE_INNER;
5712
    pJoin->subType = JOIN_STYPE_NONE;
5713
    
5714
    code = pdcJoinSplitCond(pJoin, &pJoin->pColOnCond, NULL, &pJoin->pLeftOnCond, &pJoin->pRightOnCond, true);
5715

5716
    pJoin->joinType = t;
5717
    pJoin->subType = s;
5718

5719
    if (TSDB_CODE_SUCCESS != code) {
5720
      return code;
5721
    }
5722

5723
    STimeWindow ltimeRange = TSWINDOW_INITIALIZER;
5724
    STimeWindow rtimeRange = TSWINDOW_INITIALIZER;
5725
    SNode* pPrimaryKeyCond = NULL;
5726
    if (NULL != pJoin->pLeftOnCond) {
5727
      hashJoinOptSplitPrimCond(&pJoin->pLeftOnCond, &pPrimaryKeyCond);
5728
      if (NULL != pPrimaryKeyCond) {
5729
        bool isStrict = false;
5730
        code = getTimeRangeFromNode(&pPrimaryKeyCond, &ltimeRange, &isStrict);
5731
        nodesDestroyNode(pPrimaryKeyCond);
5732
      }
5733
    }
5734

5735
    if (TSDB_CODE_SUCCESS != code) {
5736
      return code;
5737
    }
5738
    
5739
    if (NULL != pJoin->pRightOnCond) {
5740
      pPrimaryKeyCond = NULL;
5741
      hashJoinOptSplitPrimCond(&pJoin->pRightOnCond, &pPrimaryKeyCond);
5742
      if (NULL != pPrimaryKeyCond) {
5743
        bool isStrict = false;
5744
        code = getTimeRangeFromNode(&pPrimaryKeyCond, &rtimeRange, &isStrict);
5745
        nodesDestroyNode(pPrimaryKeyCond);
5746
      }
5747
    }    
5748

5749
    if (TSDB_CODE_SUCCESS != code) {
5750
      return code;
5751
    }
5752

5753
    if (TSWINDOW_IS_EQUAL(ltimeRange, TSWINDOW_INITIALIZER)) {
5754
      pJoin->timeRange.skey = rtimeRange.skey;
5755
      pJoin->timeRange.ekey = rtimeRange.ekey;
5756
    } else if (TSWINDOW_IS_EQUAL(rtimeRange, TSWINDOW_INITIALIZER)) {
5757
      pJoin->timeRange.skey = ltimeRange.skey;
5758
      pJoin->timeRange.ekey = ltimeRange.ekey;
5759
    } else if (ltimeRange.ekey < rtimeRange.skey || ltimeRange.skey > rtimeRange.ekey) {
5760
      pJoin->timeRange = TSWINDOW_DESC_INITIALIZER;
5761
    } else {
5762
      pJoin->timeRange.skey = TMAX(ltimeRange.skey, rtimeRange.skey);
5763
      pJoin->timeRange.ekey = TMIN(ltimeRange.ekey, rtimeRange.ekey);
5764
    }
5765
#else 
5766
    SNode* pPrimaryKeyCond = NULL;
×
5767
    code = hashJoinOptSplitPrimCond(&pJoin->pColOnCond, &pPrimaryKeyCond);
×
5768
    if (TSDB_CODE_SUCCESS != code) {
×
5769
      return code;
×
5770
    }
5771
    if (NULL != pPrimaryKeyCond) {
×
5772
      bool isStrict = false;
×
5773
      code = getTimeRangeFromNode(&pPrimaryKeyCond, &pJoin->timeRange, &isStrict);
×
5774
      nodesDestroyNode(pPrimaryKeyCond);
×
5775
    }
5776
#endif
5777
  } else {
5778
    pJoin->timeRange = TSWINDOW_INITIALIZER;
×
5779
  }
5780

5781
#if 0
5782
  if (NULL != pJoin->pTagOnCond && !TSWINDOW_IS_EQUAL(pJoin->timeRange, TSWINDOW_DESC_INITIALIZER)) {
5783
    EJoinType t = pJoin->joinType;
5784
    EJoinSubType s = pJoin->subType;
5785
    SNode*  pLeftChildCond = NULL;
5786
    SNode*  pRightChildCond = NULL;
5787

5788
    pJoin->joinType = JOIN_TYPE_INNER;
5789
    pJoin->subType = JOIN_STYPE_NONE;
5790
    
5791
    code = pdcJoinSplitCond(pJoin, &pJoin->pTagOnCond, NULL, &pLeftChildCond, &pRightChildCond, true);
5792

5793
    pJoin->joinType = t;
5794
    pJoin->subType = s;
5795

5796
    if (TSDB_CODE_SUCCESS == code) {
5797
      code = mergeJoinConds(&pJoin->pLeftOnCond, &pLeftChildCond);
5798
    }
5799
    if (TSDB_CODE_SUCCESS == code) {
5800
      code = mergeJoinConds(&pJoin->pRightOnCond, &pRightChildCond);
5801
    }
5802

5803
    nodesDestroyNode(pLeftChildCond);
5804
    nodesDestroyNode(pRightChildCond);
5805

5806
    if (TSDB_CODE_SUCCESS != code) {
5807
      return code;
5808
    }
5809
  }
5810
#endif
5811

5812
  if (!TSWINDOW_IS_EQUAL(pJoin->timeRange, TSWINDOW_DESC_INITIALIZER)) {
×
5813
    SNode* pChild = NULL;
×
5814
    FOREACH(pChild, pJoin->node.pChildren) {
×
5815
      if (QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(pChild)) {
×
5816
        continue;
×
5817
      }
5818

5819
      SScanLogicNode* pScan = (SScanLogicNode*)pChild;
×
5820
      if (TSWINDOW_IS_EQUAL(pScan->scanRange, TSWINDOW_INITIALIZER)) {
×
5821
        continue;
×
5822
      } else if (pJoin->timeRange.ekey < pScan->scanRange.skey || pJoin->timeRange.skey > pScan->scanRange.ekey) {
×
5823
        pJoin->timeRange = TSWINDOW_DESC_INITIALIZER;
×
5824
        break;
×
5825
      } else {
5826
        pJoin->timeRange.skey = TMAX(pJoin->timeRange.skey, pScan->scanRange.skey);
×
5827
        pJoin->timeRange.ekey = TMIN(pJoin->timeRange.ekey, pScan->scanRange.ekey);
×
5828
      }
5829
    }
5830
  }
5831

5832
  pJoin->timeRangeTarget = 0;
×
5833

5834
  if (!TSWINDOW_IS_EQUAL(pJoin->timeRange, TSWINDOW_INITIALIZER)) {
×
5835
    SNode* pChild = NULL;
×
5836
    int32_t timeRangeTarget = 1;
×
5837
    FOREACH(pChild, pJoin->node.pChildren) {
×
5838
      if (QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(pChild)) {
×
5839
        timeRangeTarget++;
×
5840
        continue;
×
5841
      }
5842
    
5843
      SScanLogicNode* pScan = (SScanLogicNode*)pChild;
×
5844
      if (TSWINDOW_IS_EQUAL(pScan->scanRange, pJoin->timeRange)) {
×
5845
        timeRangeTarget++;
×
5846
        continue;
×
5847
      }
5848

5849
      bool replaced = false;
×
5850
      switch (pJoin->joinType) {
×
5851
        case JOIN_TYPE_INNER:
×
5852
          pScan->scanRange.skey = pJoin->timeRange.skey;
×
5853
          pScan->scanRange.ekey = pJoin->timeRange.ekey;
×
5854
          replaced = true;
×
5855
          break;
×
5856
        case JOIN_TYPE_LEFT:
×
5857
          if (2 == timeRangeTarget) {
×
5858
            pScan->scanRange.skey = pJoin->timeRange.skey;
×
5859
            pScan->scanRange.ekey = pJoin->timeRange.ekey;
×
5860
            replaced = true;
×
5861
          }
5862
          break;
×
5863
        case JOIN_TYPE_RIGHT:
×
5864
          if (1 == timeRangeTarget) {
×
5865
            pScan->scanRange.skey = pJoin->timeRange.skey;
×
5866
            pScan->scanRange.ekey = pJoin->timeRange.ekey;
×
5867
            replaced = true;
×
5868
          }
5869
          break;
×
5870
        default:
×
5871
          break;
×
5872
      }
5873

5874
      if (replaced) {
×
5875
        timeRangeTarget++;
×
5876
        continue;
×
5877
      }
5878
      
5879
      pJoin->timeRangeTarget += timeRangeTarget;
×
5880
      timeRangeTarget++;
×
5881
    }
5882
  }
5883

5884
  pCxt->optimized = true;
×
5885
  OPTIMIZE_FLAG_SET_MASK(pJoin->node.optimizedFlag, OPTIMIZE_FLAG_STB_JOIN);
×
5886
  
5887
  return TSDB_CODE_SUCCESS;
×
5888
}
5889

5890

5891
static int32_t hashJoinOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
1,703,673✔
5892
  int32_t code = 0;
1,703,673✔
5893
  SLogicNode* pNode = optFindPossibleNode(pLogicSubplan->pNode, hashJoinOptShouldBeOptimized, &code);
1,703,673✔
5894
  if (TSDB_CODE_SUCCESS != code) {
1,703,679!
5895
    return code;
×
5896
  }
5897
  if (NULL == pNode) {
1,703,679!
5898
    return TSDB_CODE_SUCCESS;
1,703,680✔
5899
  }
5900

5901
  return hashJoinOptRewriteJoin(pCxt, pNode, pLogicSubplan);
×
5902
}
5903

5904
static bool stbJoinOptShouldBeOptimized(SLogicNode* pNode, void* pCtx) {
7,742,263✔
5905
  if (QUERY_NODE_LOGIC_PLAN_JOIN != nodeType(pNode) || OPTIMIZE_FLAG_TEST_MASK(pNode->optimizedFlag, OPTIMIZE_FLAG_STB_JOIN)) {
7,742,263✔
5906
    return false;
7,553,030✔
5907
  }
5908

5909
  SJoinLogicNode* pJoin = (SJoinLogicNode*)pNode;
189,233✔
5910
  if (pJoin->joinAlgo == JOIN_ALGO_UNKNOWN) {
189,233✔
5911
    pJoin->joinAlgo = JOIN_ALGO_MERGE;
114,743✔
5912
  }
5913

5914
  if (JOIN_STYPE_NONE != pJoin->subType || pJoin->isSingleTableJoin || NULL == pJoin->pTagEqCond || pNode->pChildren->length != 2 
189,233!
5915
      || pJoin->isLowLevelJoin) {
18,938✔
5916
    return false;
170,326✔
5917
  }
5918

5919
  SNode* pLeft = nodesListGetNode(pJoin->node.pChildren, 0);
18,907✔
5920
  SNode* pRight = nodesListGetNode(pJoin->node.pChildren, 1);
18,907✔
5921
  if (QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(pLeft) || QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(pRight)) {
18,907!
5922
    return false;
4✔
5923
  }
5924

5925
  return true;
18,903✔
5926
}
5927

5928
int32_t stbJoinOptAddFuncToScanNode(char* funcName, SScanLogicNode* pScan) {
75,612✔
5929
  SFunctionNode* pUidFunc = NULL;
75,612✔
5930
  int32_t code = createFunction(funcName, NULL, &pUidFunc);
75,612✔
5931
  if (TSDB_CODE_SUCCESS != code) {
75,612!
5932
    return code;
×
5933
  }
5934
  snprintf(pUidFunc->node.aliasName, sizeof(pUidFunc->node.aliasName), "%s.%p", pUidFunc->functionName, pUidFunc);
75,612✔
5935
  code = nodesListStrictAppend(pScan->pScanPseudoCols, (SNode*)pUidFunc);
75,612✔
5936
  if (TSDB_CODE_SUCCESS == code) {
75,612!
5937
    code = createColumnByRewriteExpr((SNode*)pUidFunc, &pScan->node.pTargets);
75,612✔
5938
  }
5939
  return code;
75,612✔
5940
}
5941

5942
int32_t stbJoinOptRewriteToTagScan(SLogicNode* pJoin, SNode* pNode) {
37,806✔
5943
  SScanLogicNode* pScan = (SScanLogicNode*)pNode;
37,806✔
5944
  SJoinLogicNode* pJoinNode = (SJoinLogicNode*)pJoin;
37,806✔
5945

5946
  pScan->scanType = SCAN_TYPE_TAG;
37,806✔
5947
  NODES_DESTORY_LIST(pScan->pScanCols);
37,806✔
5948
  NODES_DESTORY_NODE(pScan->node.pConditions);
37,806✔
5949
  pScan->node.requireDataOrder = DATA_ORDER_LEVEL_NONE;
37,806✔
5950
  pScan->node.resultDataOrder = DATA_ORDER_LEVEL_NONE;
37,806✔
5951

5952
  SNodeList* pTags = NULL;
37,806✔
5953
  int32_t code = nodesMakeList(&pTags);
37,806✔
5954
  if (TSDB_CODE_SUCCESS  == code) {
37,806!
5955
    code = nodesCollectColumnsFromNode(pJoinNode->pTagEqCond, NULL, COLLECT_COL_TYPE_TAG, &pTags);
37,806✔
5956
  }
5957
  if (TSDB_CODE_SUCCESS == code) {
37,806!
5958
    code = nodesCollectColumnsFromNode(pJoinNode->pTagOnCond, NULL, COLLECT_COL_TYPE_TAG, &pTags);
37,806✔
5959
  }
5960
  if (TSDB_CODE_SUCCESS == code) {
37,806!
5961
    SNode* pTarget = NULL;
37,806✔
5962
    SNode* pTag = NULL;
37,806✔
5963
    bool   found = false;
37,806✔
5964
    WHERE_EACH(pTarget, pScan->node.pTargets) {
193,944!
5965
      found = false;
156,138✔
5966
      SColumnNode* pTargetCol = (SColumnNode*)pTarget;
156,138✔
5967
      FOREACH(pTag, pTags) {
411,777!
5968
        SColumnNode* pTagCol = (SColumnNode*)pTag;
293,461✔
5969
        if (0 == strcasecmp(pTargetCol->node.aliasName, pTagCol->colName) && 0 == strcasecmp(pTargetCol->tableAlias, pTagCol->tableAlias)) {
293,461✔
5970
          found = true;
37,822✔
5971
          break;
37,822✔
5972
        }
5973
      }
5974
      if (!found) {
156,138✔
5975
        ERASE_NODE(pScan->node.pTargets);
118,316✔
5976
      } else {
5977
        WHERE_NEXT;
37,822✔
5978
      }
5979
    }
5980
  }
5981
  if (TSDB_CODE_SUCCESS == code) {
37,806!
5982
    code = stbJoinOptAddFuncToScanNode("_tbuid", pScan);
37,806✔
5983
  }
5984
  if (TSDB_CODE_SUCCESS == code) {
37,806!
5985
    code = stbJoinOptAddFuncToScanNode("_vgid", pScan);
37,806✔
5986
  }
5987

5988
  if (TSDB_CODE_SUCCESS == code) {
37,806!
5989
    code = tagScanSetExecutionMode(pScan);
37,806✔
5990
  }
5991

5992
  if (code) {
37,806!
5993
    nodesDestroyList(pTags);
×
5994
  }
5995

5996
  return code;
37,806✔
5997
}
5998

5999
static int32_t stbJoinOptCreateTagScanNode(SLogicNode* pJoin, SNodeList** ppList) {
18,903✔
6000
  SNodeList* pList = NULL;
18,903✔
6001
  int32_t code = nodesCloneList(pJoin->pChildren, &pList);
18,903✔
6002
  if (NULL == pList) {
18,903!
6003
    return code;
×
6004
  }
6005

6006
  SNode*  pNode = NULL;
18,903✔
6007
  FOREACH(pNode, pList) {
56,709!
6008
    code = stbJoinOptRewriteToTagScan(pJoin, pNode);
37,806✔
6009
    if (code) {
37,806!
6010
      break;
×
6011
    }
6012
  }
6013

6014
  if (TSDB_CODE_SUCCESS == code) {
18,903!
6015
    *ppList = pList;
18,903✔
6016
  } else {
6017
    nodesDestroyList(pList);
×
6018
  }
6019

6020
  return code;
18,903✔
6021
}
6022

6023
static int32_t stbJoinOptCreateTagHashJoinNode(SLogicNode* pOrig, SNodeList* pChildren, SLogicNode** ppLogic) {
18,903✔
6024
  SJoinLogicNode* pOrigJoin = (SJoinLogicNode*)pOrig;
18,903✔
6025
  SJoinLogicNode* pJoin = NULL;
18,903✔
6026
  int32_t code = nodesMakeNode(QUERY_NODE_LOGIC_PLAN_JOIN, (SNode**)&pJoin);
18,903✔
6027
  if (NULL == pJoin) {
18,903!
6028
    return code;
×
6029
  }
6030

6031
  pJoin->joinType = pOrigJoin->joinType;
18,903✔
6032
  pJoin->subType = pOrigJoin->subType;
18,903✔
6033
  pJoin->joinAlgo = JOIN_ALGO_HASH;
18,903✔
6034
  pJoin->isSingleTableJoin = pOrigJoin->isSingleTableJoin;
18,903✔
6035
  pJoin->hasSubQuery = pOrigJoin->hasSubQuery;
18,903✔
6036
  pJoin->node.inputTsOrder = pOrigJoin->node.inputTsOrder;
18,903✔
6037
  pJoin->node.groupAction = pOrigJoin->node.groupAction;
18,903✔
6038
  pJoin->node.requireDataOrder = DATA_ORDER_LEVEL_NONE;
18,903✔
6039
  pJoin->node.resultDataOrder = DATA_ORDER_LEVEL_NONE;
18,903✔
6040
  code = nodesCloneNode(pOrigJoin->pTagEqCond, &pJoin->pTagEqCond);
18,903✔
6041
  if (TSDB_CODE_SUCCESS  != code) {
18,903!
6042
    nodesDestroyNode((SNode*)pJoin);
×
6043
    return code;
×
6044
  }
6045
  code = nodesCloneNode(pOrigJoin->pTagOnCond, &pJoin->pTagOnCond);
18,903✔
6046
  if (TSDB_CODE_SUCCESS != code) {
18,903!
6047
    nodesDestroyNode((SNode*)pJoin);
×
6048
    return code;
×
6049
  }
6050
  
6051
  pJoin->node.pChildren = pChildren;
18,903✔
6052

6053
  SNode* pNode = NULL;
18,903✔
6054
  FOREACH(pNode, pChildren) {
56,709!
6055
    SScanLogicNode* pScan = (SScanLogicNode*)pNode;
37,806✔
6056
    SNode*          pCol = NULL;
37,806✔
6057
    FOREACH(pCol, pScan->pScanPseudoCols) {
198,367!
6058
      if (QUERY_NODE_FUNCTION == nodeType(pCol) && (((SFunctionNode*)pCol)->funcType == FUNCTION_TYPE_TBUID ||
160,561✔
6059
                                                    ((SFunctionNode*)pCol)->funcType == FUNCTION_TYPE_VGID)) {
37,810✔
6060
        code = createColumnByRewriteExpr(pCol, &pJoin->node.pTargets);
75,612✔
6061
        if (code) {
75,612!
6062
          break;
×
6063
        }
6064
      }
6065
    }
6066
    if (code) {
37,806!
6067
      break;
×
6068
    }
6069
    pScan->node.pParent = (SLogicNode*)pJoin;
37,806✔
6070
  }
6071

6072
  SNodeList* pCols = NULL;
18,903✔
6073
  code = nodesCollectColumnsFromNode(pJoin->pFullOnCond, NULL, COLLECT_COL_TYPE_ALL, &pCols);
18,903✔
6074

6075
  if (TSDB_CODE_SUCCESS == code) {
18,903!
6076
    FOREACH(pNode, pCols) {
18,903!
6077
      code = createColumnByRewriteExpr(pNode, &pJoin->node.pTargets);
×
6078
      if (code) {
×
6079
        break;
×
6080
      }
6081
    }
6082
  }
6083
  nodesDestroyList(pCols);
18,903✔
6084

6085
  if (TSDB_CODE_SUCCESS == code) {
18,903!
6086
    *ppLogic = (SLogicNode*)pJoin;    
18,903✔
6087
    OPTIMIZE_FLAG_SET_MASK(pJoin->node.optimizedFlag, OPTIMIZE_FLAG_STB_JOIN);
18,903✔
6088
  } else {
6089
    nodesDestroyNode((SNode*)pJoin);
×
6090
  }
6091

6092
  return code;
18,903✔
6093
}
6094

6095
static int32_t stbJoinOptCreateTableScanNodes(SLogicNode* pJoin, SNodeList** ppList, bool* srcScan) {
18,903✔
6096
  SNodeList* pList = NULL;
18,903✔
6097
  int32_t code = nodesCloneList(pJoin->pChildren, &pList);
18,903✔
6098
  if (NULL == pList) {
18,903!
6099
    return code;
×
6100
  }
6101

6102
  int32_t i = 0;
18,903✔
6103
  SNode*  pNode = NULL;
18,903✔
6104
  FOREACH(pNode, pList) {
56,709!
6105
    SScanLogicNode* pScan = (SScanLogicNode*)pNode;
37,806✔
6106
    //code = stbJoinOptAddFuncToScanNode("_tbuid", pScan);
6107
    //if (code) {
6108
    //  break;
6109
    //}
6110

6111
    nodesDestroyNode(pScan->pTagCond);
37,806✔
6112
    pScan->pTagCond = NULL;
37,806✔
6113
    nodesDestroyNode(pScan->pTagIndexCond);
37,806✔
6114
    pScan->pTagIndexCond = NULL;
37,806✔
6115
    
6116
    pScan->node.dynamicOp = true;
37,806✔
6117
    *(srcScan + i++) = pScan->pVgroupList->numOfVgroups <= 1;
37,806✔
6118

6119
    pScan->scanType = SCAN_TYPE_TABLE;
37,806✔
6120
  }
6121

6122
  *ppList = pList;
18,903✔
6123

6124
  return code;
18,903✔
6125
}
6126

6127
static int32_t stbJoinOptCreateGroupCacheNode(SLogicNode* pRoot, SNodeList* pChildren, SLogicNode** ppLogic) {
18,903✔
6128
  int32_t               code = TSDB_CODE_SUCCESS;
18,903✔
6129
  SGroupCacheLogicNode* pGrpCache = NULL;
18,903✔
6130
  code = nodesMakeNode(QUERY_NODE_LOGIC_PLAN_GROUP_CACHE, (SNode**)&pGrpCache);
18,903✔
6131
  if (NULL == pGrpCache) {
18,903!
6132
    return code;
×
6133
  }
6134

6135
  // pGrpCache->node.dynamicOp = true;
6136
  pGrpCache->grpColsMayBeNull = false;
18,903✔
6137
  pGrpCache->grpByUid = true;
18,903✔
6138
  pGrpCache->batchFetch = getBatchScanOptionFromHint(pRoot->pHint);
18,903✔
6139
  pGrpCache->node.pChildren = pChildren;
18,903✔
6140
  pGrpCache->node.pTargets = NULL;
18,903✔
6141
  code = nodesMakeList(&pGrpCache->node.pTargets);
18,903✔
6142
  if (TSDB_CODE_SUCCESS == code) {
18,903!
6143
    SScanLogicNode* pScan = (SScanLogicNode*)nodesListGetNode(pChildren, 0);
18,903✔
6144
    SNodeList* pNewList = NULL;
18,903✔
6145
    code = nodesCloneList(pScan->node.pTargets, &pNewList);
18,903✔
6146
    if (TSDB_CODE_SUCCESS == code) {
18,903!
6147
      code = nodesListStrictAppendList(pGrpCache->node.pTargets, pNewList);
18,903✔
6148
    }
6149
  }
6150

6151
  SScanLogicNode* pScan = (SScanLogicNode*)nodesListGetNode(pChildren, 0);
18,903✔
6152
  SNode*          pCol = NULL;
18,903✔
6153
  FOREACH(pCol, pScan->pScanPseudoCols) {
61,332!
6154
    if (QUERY_NODE_FUNCTION == nodeType(pCol) && (((SFunctionNode*)pCol)->funcType == FUNCTION_TYPE_TBUID ||
42,429!
6155
                                                  ((SFunctionNode*)pCol)->funcType == FUNCTION_TYPE_VGID)) {
4!
6156
      code = createColumnByRewriteExpr(pCol, &pGrpCache->pGroupCols);
×
6157
      if (code) {
×
6158
        break;
×
6159
      }
6160
    }
6161
  }
6162

6163
  bool   hasCond = false;
18,903✔
6164
  SNode* pNode = NULL;
18,903✔
6165
  FOREACH(pNode, pChildren) {
56,709!
6166
    SScanLogicNode* pScan = (SScanLogicNode*)pNode;
37,806✔
6167
    if (pScan->node.pConditions) {
37,806✔
6168
      hasCond = true;
73✔
6169
    }
6170
    pScan->node.pParent = (SLogicNode*)pGrpCache;
37,806✔
6171
  }
6172
  pGrpCache->globalGrp = false;
18,903✔
6173

6174
  if (TSDB_CODE_SUCCESS == code) {
18,903!
6175
    *ppLogic = (SLogicNode*)pGrpCache;
18,903✔
6176
  } else {
6177
    nodesDestroyNode((SNode*)pGrpCache);
×
6178
  }
6179

6180
  return code;
18,903✔
6181
}
6182

6183
static void stbJoinOptRemoveTagEqCond(SJoinLogicNode* pJoin) {
18,903✔
6184
  if (QUERY_NODE_OPERATOR == nodeType(pJoin->pFullOnCond) && nodesEqualNode(pJoin->pFullOnCond, pJoin->pTagEqCond)) {
18,903!
6185
    NODES_DESTORY_NODE(pJoin->pFullOnCond);
2,122✔
6186
    return;
2,122✔
6187
  }
6188
  if (QUERY_NODE_LOGIC_CONDITION == nodeType(pJoin->pFullOnCond)) {
16,781!
6189
    SLogicConditionNode* pLogic = (SLogicConditionNode*)pJoin->pFullOnCond;
16,781✔
6190
    SNode* pNode = NULL;
16,781✔
6191
    FOREACH(pNode, pLogic->pParameterList) {
16,810!
6192
      if (nodesEqualNode(pNode, pJoin->pTagEqCond)) {
16,798✔
6193
        ERASE_NODE(pLogic->pParameterList);
16,769✔
6194
        break;
16,769✔
6195
      } else if (QUERY_NODE_LOGIC_CONDITION == nodeType(pJoin->pTagEqCond)) {
29✔
6196
        SLogicConditionNode* pTags = (SLogicConditionNode*)pJoin->pTagEqCond;
28✔
6197
        SNode* pTag = NULL;
28✔
6198
        bool found = false;
28✔
6199
        FOREACH(pTag, pTags->pParameterList) {
48!
6200
          if (nodesEqualNode(pTag, pNode)) {
44✔
6201
            found = true;
24✔
6202
            break;
24✔
6203
          }
6204
        }
6205
        if (found) {
28✔
6206
          ERASE_NODE(pLogic->pParameterList);
24✔
6207
        }
6208
      }
6209
    }
6210

6211
    if (pLogic->pParameterList->length <= 0) {
16,781✔
6212
      NODES_DESTORY_NODE(pJoin->pFullOnCond);
8✔
6213
    }
6214
  }
6215
}
6216

6217
static int32_t stbJoinOptCreateMergeJoinNode(SLogicNode* pOrig, SLogicNode* pChild, SLogicNode** ppLogic) {
18,903✔
6218
  SJoinLogicNode* pOrigJoin = (SJoinLogicNode*)pOrig;
18,903✔
6219
  SJoinLogicNode* pJoin = NULL;
18,903✔
6220
  int32_t code = nodesCloneNode((SNode*)pOrig, (SNode**)&pJoin);
18,903✔
6221
  if (NULL == pJoin) {
18,903!
6222
    return code;
×
6223
  }
6224

6225
  pJoin->joinAlgo = JOIN_ALGO_MERGE;
18,903✔
6226
  // pJoin->node.dynamicOp = true;
6227

6228
  stbJoinOptRemoveTagEqCond(pJoin);
18,903✔
6229
  NODES_DESTORY_NODE(pJoin->pTagEqCond);
18,903✔
6230

6231
  SNode* pNode = NULL;
18,903✔
6232
  FOREACH(pNode, pJoin->node.pChildren) { ERASE_NODE(pJoin->node.pChildren); }
56,709!
6233
  code = nodesListStrictAppend(pJoin->node.pChildren, (SNode*)pChild);
18,903✔
6234
  if (TSDB_CODE_SUCCESS == code) {
18,903!
6235
    pChild->pParent = (SLogicNode*)pJoin;
18,903✔
6236
    *ppLogic = (SLogicNode*)pJoin;
18,903✔
6237
    OPTIMIZE_FLAG_SET_MASK(pJoin->node.optimizedFlag, OPTIMIZE_FLAG_STB_JOIN);
18,903✔
6238
  } else {
6239
    nodesDestroyNode((SNode*)pJoin);
×
6240
  }
6241

6242
  return code;
18,903✔
6243
}
6244

6245
static int32_t stbJoinOptCreateDynQueryCtrlNode(SLogicNode* pRoot, SLogicNode* pPrev, SLogicNode* pPost, bool* srcScan,
18,903✔
6246
                                                SLogicNode** ppDynNode) {
6247
  int32_t                 code = TSDB_CODE_SUCCESS;
18,903✔
6248
  SDynQueryCtrlLogicNode* pDynCtrl = NULL;
18,903✔
6249
  code = nodesMakeNode(QUERY_NODE_LOGIC_PLAN_DYN_QUERY_CTRL, (SNode**)&pDynCtrl);
18,903✔
6250
  if (NULL == pDynCtrl) {
18,903!
6251
    return code;
×
6252
  }
6253

6254
  pDynCtrl->qType = DYN_QTYPE_STB_HASH;
18,903✔
6255
  pDynCtrl->stbJoin.batchFetch = getBatchScanOptionFromHint(pRoot->pHint);
18,903✔
6256
  memcpy(pDynCtrl->stbJoin.srcScan, srcScan, sizeof(pDynCtrl->stbJoin.srcScan));
18,903✔
6257

6258
  if (TSDB_CODE_SUCCESS == code) {
18,903!
6259
    pDynCtrl->node.pChildren = NULL;
18,903✔
6260
    code = nodesMakeList(&pDynCtrl->node.pChildren);
18,903✔
6261
    if (NULL == pDynCtrl->node.pChildren) {
18,903!
6262
      code = code;
×
6263
    }
6264
  }
6265

6266
  if (TSDB_CODE_SUCCESS == code) {
18,903!
6267
    pDynCtrl->stbJoin.pVgList = NULL;
18,903✔
6268
    code = nodesMakeList(&pDynCtrl->stbJoin.pVgList);
18,903✔
6269
    if (NULL == pDynCtrl->stbJoin.pVgList) {
18,903!
6270
      code = code;
×
6271
    }
6272
  }
6273

6274
  if (TSDB_CODE_SUCCESS == code) {
18,903!
6275
    pDynCtrl->stbJoin.pUidList = NULL;
18,903✔
6276
    code = nodesMakeList(&pDynCtrl->stbJoin.pUidList);
18,903✔
6277
    if (NULL == pDynCtrl->stbJoin.pUidList) {
18,903!
6278
      code = code;
×
6279
    }
6280
  }
6281

6282
  SJoinLogicNode* pHJoin = (SJoinLogicNode*)pPrev;
18,903✔
6283
  code = nodesListStrictAppend(pDynCtrl->stbJoin.pUidList, nodesListGetNode(pHJoin->node.pTargets, 0));
18,903✔
6284
  if (TSDB_CODE_SUCCESS == code) {
18,903!
6285
    code = nodesListStrictAppend(pDynCtrl->stbJoin.pUidList, nodesListGetNode(pHJoin->node.pTargets, 2));
18,903✔
6286
  }
6287
  if (TSDB_CODE_SUCCESS == code) {
18,903!
6288
    code = nodesListStrictAppend(pDynCtrl->stbJoin.pVgList, nodesListGetNode(pHJoin->node.pTargets, 1));
18,903✔
6289
  }
6290
  if (TSDB_CODE_SUCCESS == code) {
18,903!
6291
    code = nodesListStrictAppend(pDynCtrl->stbJoin.pVgList, nodesListGetNode(pHJoin->node.pTargets, 3));
18,903✔
6292
  }
6293

6294
  if (TSDB_CODE_SUCCESS == code) {
18,903!
6295
    code = nodesListStrictAppend(pDynCtrl->node.pChildren, (SNode*)pPrev);
18,903✔
6296
    if (TSDB_CODE_SUCCESS == code) {
18,903!
6297
      code = nodesListStrictAppend(pDynCtrl->node.pChildren, (SNode*)pPost);
18,903✔
6298
    }
6299
    if (TSDB_CODE_SUCCESS == code) {
18,903!
6300
      pDynCtrl->node.pTargets = NULL;
18,903✔
6301
      code = nodesCloneList(pPost->pTargets, &pDynCtrl->node.pTargets);
18,903✔
6302
      if (!pDynCtrl->node.pTargets) {
18,903!
6303
        code = code;
×
6304
      }
6305
    }
6306
  }
6307

6308
  if (TSDB_CODE_SUCCESS == code) {
18,903!
6309
    pPrev->pParent = (SLogicNode*)pDynCtrl;
18,903✔
6310
    pPost->pParent = (SLogicNode*)pDynCtrl;
18,903✔
6311

6312
    *ppDynNode = (SLogicNode*)pDynCtrl;
18,903✔
6313
  } else {
6314
    nodesDestroyNode((SNode*)pDynCtrl);
×
6315
    *ppDynNode = NULL;
×
6316
  }
6317

6318
  return code;
18,903✔
6319
}
6320

6321
static int32_t stbJoinOptRewriteStableJoin(SOptimizeContext* pCxt, SLogicNode* pJoin, SLogicSubplan* pLogicSubplan) {
18,903✔
6322
  SNodeList*  pTagScanNodes = NULL;
18,903✔
6323
  SNodeList*  pTbScanNodes = NULL;
18,903✔
6324
  SLogicNode* pGrpCacheNode = NULL;
18,903✔
6325
  SLogicNode* pHJoinNode = NULL;
18,903✔
6326
  SLogicNode* pMJoinNode = NULL;
18,903✔
6327
  SLogicNode* pDynNode = NULL;
18,903✔
6328
  bool        srcScan[2] = {0};
18,903✔
6329

6330
  int32_t code = stbJoinOptCreateTagScanNode(pJoin, &pTagScanNodes);
18,903✔
6331
  if (TSDB_CODE_SUCCESS == code) {
18,903!
6332
    code = stbJoinOptCreateTagHashJoinNode(pJoin, pTagScanNodes, &pHJoinNode);
18,903✔
6333
  }
6334
  if (TSDB_CODE_SUCCESS == code) {
18,903!
6335
    code = stbJoinOptCreateTableScanNodes(pJoin, &pTbScanNodes, srcScan);
18,903✔
6336
  }
6337
  if (TSDB_CODE_SUCCESS == code) {
18,903!
6338
    code = stbJoinOptCreateGroupCacheNode(getLogicNodeRootNode(pJoin), pTbScanNodes, &pGrpCacheNode);
18,903✔
6339
  }
6340
  if (TSDB_CODE_SUCCESS == code) {
18,903!
6341
    code = stbJoinOptCreateMergeJoinNode(pJoin, pGrpCacheNode, &pMJoinNode);
18,903✔
6342
  }
6343
  if (TSDB_CODE_SUCCESS == code) {
18,903!
6344
    code = stbJoinOptCreateDynQueryCtrlNode(getLogicNodeRootNode(pJoin), pHJoinNode, pMJoinNode, srcScan, &pDynNode);
18,903✔
6345
  }
6346
  if (TSDB_CODE_SUCCESS == code) {
18,903!
6347
    code = replaceLogicNode(pLogicSubplan, pJoin, (SLogicNode*)pDynNode);
18,903✔
6348
  }
6349
  if (TSDB_CODE_SUCCESS == code) {
18,903!
6350
    nodesDestroyNode((SNode*)pJoin);
18,903✔
6351
    pCxt->optimized = true;
18,903✔
6352
  }
6353
  return code;
18,903✔
6354
}
6355

6356
static int32_t stableJoinOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
1,703,671✔
6357
  SLogicNode* pNode = optFindPossibleNode(pLogicSubplan->pNode, stbJoinOptShouldBeOptimized, NULL);
1,703,671✔
6358
  if (NULL == pNode) {
1,703,677✔
6359
    return TSDB_CODE_SUCCESS;
1,684,775✔
6360
  }
6361

6362
  return stbJoinOptRewriteStableJoin(pCxt, pNode, pLogicSubplan);
18,902✔
6363
}
6364

6365
static bool grpJoinOptShouldBeOptimized(SLogicNode* pNode, void* pCtx) {
7,652,121✔
6366
  if (QUERY_NODE_LOGIC_PLAN_JOIN != nodeType(pNode)) {
7,652,121✔
6367
    return false;
7,378,610✔
6368
  }
6369

6370
  SJoinLogicNode* pJoin = (SJoinLogicNode*)pNode;
273,511✔
6371
  if (JOIN_STYPE_ASOF != pJoin->subType && JOIN_STYPE_WIN != pJoin->subType) {
273,511✔
6372
    return false;
270,335✔
6373
  }
6374

6375
  if (NULL == pJoin->pLeftEqNodes || pJoin->grpJoin) {
3,176✔
6376
    return false;
2,651✔
6377
  }
6378

6379
  return true;
525✔
6380
}
6381

6382
static int32_t grpJoinOptCreatePartitionNode(SLogicNode* pParent, SLogicNode* pChild, bool leftChild, SLogicNode** pNew) {
1,050✔
6383
  SPartitionLogicNode* pPartition = NULL;
1,050✔
6384
  int32_t code = nodesMakeNode(QUERY_NODE_LOGIC_PLAN_PARTITION, (SNode**)&pPartition);
1,050✔
6385
  if (NULL == pPartition) {
1,050!
6386
    return code;
×
6387
  }
6388

6389
  pPartition->node.groupAction = GROUP_ACTION_SET;
1,050✔
6390
  pPartition->node.requireDataOrder = DATA_ORDER_LEVEL_GLOBAL;
1,050✔
6391
  pPartition->node.resultDataOrder = DATA_ORDER_LEVEL_IN_GROUP;
1,050✔
6392

6393
  pPartition->node.pTargets = NULL;
1,050✔
6394
  code = nodesCloneList(pChild->pTargets, &pPartition->node.pTargets);
1,050✔
6395
  if (NULL == pPartition->node.pTargets) {
1,050!
6396
    nodesDestroyNode((SNode*)pPartition);
×
6397
    return code;
×
6398
  }
6399

6400
  SJoinLogicNode* pJoin = (SJoinLogicNode*)pParent;
1,050✔
6401
  pPartition->pPartitionKeys = NULL;
1,050✔
6402
  code = nodesCloneList(leftChild ? pJoin->pLeftEqNodes : pJoin->pRightEqNodes, &pPartition->pPartitionKeys);
1,050✔
6403
  if (TSDB_CODE_SUCCESS  != code) {
1,050!
6404
    nodesDestroyNode((SNode*)pPartition);
×
6405
    return code;
×
6406
  }
6407
  code = nodesListMakeStrictAppend(&pPartition->node.pChildren, (SNode *)pChild);
1,050✔
6408
  if (TSDB_CODE_SUCCESS  == code) {
1,050!
6409
    *pNew = (SLogicNode*)pPartition;
1,050✔
6410
    pChild->pParent = (SLogicNode*)pPartition;
1,050✔
6411
    pPartition->node.pParent = pParent;
1,050✔
6412
  } else {
6413
    nodesDestroyNode((SNode*)pPartition);
×
6414
  }
6415
  return code;
1,050✔
6416
}
6417

6418
static int32_t grpJoinOptInsertPartitionNode(SLogicNode* pJoin) {
525✔
6419
  int32_t code = TSDB_CODE_SUCCESS;
525✔
6420
  SNode* pNode = NULL;
525✔
6421
  SNode* pNew = NULL;
525✔
6422
  bool leftChild = true;
525✔
6423
  FOREACH(pNode, pJoin->pChildren) {
1,575!
6424
    code = grpJoinOptCreatePartitionNode(pJoin, (SLogicNode*)pNode, leftChild, (SLogicNode**)&pNew);
1,050✔
6425
    if (code) {
1,050!
6426
      break;
×
6427
    }
6428
    REPLACE_NODE(pNew);
1,050✔
6429
    leftChild = false;
1,050✔
6430
  }
6431

6432
  return code;
525✔
6433
}
6434

6435
static int32_t grpJoinOptPartByTags(SLogicNode* pNode) {
×
6436
  int32_t code = TSDB_CODE_SUCCESS;
×
6437
  SNode* pChild = NULL;
×
6438
  SNode* pNew = NULL;
×
6439
  bool leftChild = true;
×
6440
  SJoinLogicNode* pJoin = (SJoinLogicNode*)pNode;
×
6441
  FOREACH(pChild, pNode->pChildren) {
×
6442
    if (QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(pChild)) {
×
6443
      return TSDB_CODE_PLAN_INTERNAL_ERROR;
×
6444
    }
6445

6446
    SScanLogicNode* pScan = (SScanLogicNode*)pChild;
×
6447
    SNodeList* pNewList = NULL;
×
6448
    code = nodesCloneList(pJoin->pLeftEqNodes, &pNewList);
×
6449
    if (TSDB_CODE_SUCCESS == code) {
×
6450
      if (leftChild) {
×
6451
        code = nodesListMakeStrictAppendList(&pScan->pGroupTags, pNewList);
×
6452
        leftChild = false;
×
6453
      } else {
6454
        code = nodesListMakeStrictAppendList(&pScan->pGroupTags, pNewList);
×
6455
      }
6456
    }
6457
    if (TSDB_CODE_SUCCESS != code) {
×
6458
      break;
×
6459
    }
6460
    
6461
    pScan->groupSort = true;
×
6462
    pScan->groupOrderScan = true;
×
6463
  }
6464

6465
  return code;
×
6466
}
6467

6468
static int32_t grpJoinOptRewriteGroupJoin(SOptimizeContext* pCxt, SLogicNode* pNode, SLogicSubplan* pLogicSubplan) {
525✔
6469
  SJoinLogicNode* pJoin = (SJoinLogicNode*)pNode;
525✔
6470
  int32_t code = (pJoin->allEqTags && !pJoin->hasSubQuery && !pJoin->batchScanHint) ? grpJoinOptPartByTags(pNode) : grpJoinOptInsertPartitionNode(pNode);
525!
6471
  if (TSDB_CODE_SUCCESS == code) {
525!
6472
    pJoin->grpJoin = true;
525✔
6473
    pCxt->optimized = true;
525✔
6474
  }
6475
  return code;
525✔
6476
}
6477

6478

6479
static int32_t groupJoinOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
1,684,768✔
6480
  SLogicNode* pNode = optFindPossibleNode(pLogicSubplan->pNode, grpJoinOptShouldBeOptimized, NULL);
1,684,768✔
6481
  if (NULL == pNode) {
1,684,772✔
6482
    return TSDB_CODE_SUCCESS;
1,684,247✔
6483
  }
6484

6485
  return grpJoinOptRewriteGroupJoin(pCxt, pNode, pLogicSubplan);
525✔
6486
}
6487

6488
static bool partColOptShouldBeOptimized(SLogicNode* pNode, void* pCtx) {
2,709,431✔
6489
  if (QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pNode)) {
2,709,431✔
6490
    SPartitionLogicNode* pPartition = (SPartitionLogicNode*)pNode;
19,690✔
6491
    if (keysHasCol(pPartition->pPartitionKeys)) return true;
19,690✔
6492
  }
6493
  return false;
2,703,178✔
6494
}
6495

6496
static int32_t partColOptCreateSort(SPartitionLogicNode* pPartition, SSortLogicNode** ppSort) {
484✔
6497
  SNode*          node;
6498
  int32_t         code = TSDB_CODE_SUCCESS;
484✔
6499
  SSortLogicNode* pSort = NULL;
484✔
6500
  code = nodesMakeNode(QUERY_NODE_LOGIC_PLAN_SORT, (SNode**)&pSort);
484✔
6501
  if (pSort) {
484!
6502
    bool alreadyPartByPKTs = false;
484✔
6503
    pSort->groupSort = false;
484✔
6504
    FOREACH(node, pPartition->pPartitionKeys) {
1,220!
6505
      SOrderByExprNode* pOrder = NULL;
736✔
6506
      code = nodesMakeNode(QUERY_NODE_ORDER_BY_EXPR, (SNode**)&pOrder);
736✔
6507
      if (TSDB_CODE_SUCCESS  != code) {
736!
6508
        break;
×
6509
      }
6510
      if (QUERY_NODE_COLUMN == nodeType(node) && ((SColumnNode*)node)->colId == pPartition->pkTsColId &&
736✔
6511
          ((SColumnNode*)node)->tableId == pPartition->pkTsColTbId)
12!
6512
        alreadyPartByPKTs = true;
12✔
6513
      code = nodesListMakeStrictAppend(&pSort->pSortKeys, (SNode*)pOrder);
736✔
6514
      if (TSDB_CODE_SUCCESS  == code) {
736!
6515
        pOrder->order = ORDER_ASC;
736✔
6516
        pOrder->pExpr = NULL;
736✔
6517
        pOrder->nullOrder = NULL_ORDER_FIRST;
736✔
6518
        code = nodesCloneNode(node, &pOrder->pExpr);
736✔
6519
      }
6520
      if (TSDB_CODE_SUCCESS  != code) {
736!
6521
        break;
×
6522
      }
6523
    }
6524
    if (TSDB_CODE_SUCCESS != code) {
484!
6525
      nodesDestroyNode((SNode*)pSort);
×
6526
      return code;
×
6527
    }
6528

6529
    if (pPartition->needBlockOutputTsOrder && !alreadyPartByPKTs) {
484!
6530
      SOrderByExprNode* pOrder = NULL;
252✔
6531
      code = nodesMakeNode(QUERY_NODE_ORDER_BY_EXPR, (SNode**)&pOrder);
252✔
6532
      if (pOrder) {
252!
6533
        pSort->excludePkCol = true;
252✔
6534
        code = nodesListMakeStrictAppend(&pSort->pSortKeys, (SNode*)pOrder);
252✔
6535
        if (TSDB_CODE_SUCCESS  == code) {
252!
6536
          pOrder->order = ORDER_ASC;
252✔
6537
          pOrder->pExpr = 0;
252✔
6538
          FOREACH(node, pPartition->node.pTargets) {
252!
6539
            if (nodeType(node) == QUERY_NODE_COLUMN) {
252!
6540
              SColumnNode* pCol = (SColumnNode*)node;
252✔
6541
              if (pCol->colId == pPartition->pkTsColId && pCol->tableId == pPartition->pkTsColTbId) {
252!
6542
                pOrder->pExpr = NULL;
252✔
6543
                code = nodesCloneNode((SNode*)pCol, &pOrder->pExpr);
252✔
6544
                break;
252✔
6545
              }
6546
            }
6547
          }
6548
        }
6549
      }
6550
    }
6551
  }
6552
  if (code != TSDB_CODE_SUCCESS) {
484!
6553
    nodesDestroyNode((SNode*)pSort);
×
6554
    pSort = NULL;
×
6555
  } else {
6556
    *ppSort = pSort;
484✔
6557
  }
6558
  return code;
484✔
6559
}
6560

6561
static int32_t partitionColsOpt(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
770,159✔
6562
  SNode*               node;
6563
  int32_t              code = TSDB_CODE_SUCCESS;
770,159✔
6564
  SPartitionLogicNode* pNode =
6565
      (SPartitionLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, partColOptShouldBeOptimized, NULL);
770,159✔
6566
  if (NULL == pNode) return TSDB_CODE_SUCCESS;
770,165✔
6567
  SLogicNode* pRootNode = getLogicNodeRootNode((SLogicNode*)pNode);
6,253✔
6568

6569
  if (pRootNode->pHint && getSortForGroupOptHint(pRootNode->pHint)) {
6,253✔
6570
    // replace with sort node
6571
    SSortLogicNode* pSort = NULL;
484✔
6572
    code = partColOptCreateSort(pNode, &pSort);
484✔
6573
    if (!pSort) {
484!
6574
      // if sort create failed, we eat the error, skip the optimization
6575
      code = TSDB_CODE_SUCCESS;
×
6576
    } else {
6577
      TSWAP(pSort->node.pChildren, pNode->node.pChildren);
484✔
6578
      TSWAP(pSort->node.pTargets, pNode->node.pTargets);
484✔
6579
      optResetParent((SLogicNode*)pSort);
484✔
6580
      pSort->calcGroupId = true;
484✔
6581
      code = replaceLogicNode(pLogicSubplan, (SLogicNode*)pNode, (SLogicNode*)pSort);
484✔
6582
      if (code == TSDB_CODE_SUCCESS) {
484!
6583
        nodesDestroyNode((SNode*)pNode);
484✔
6584
        pCxt->optimized = true;
484✔
6585
      } else {
6586
        nodesDestroyNode((SNode*)pSort);
×
6587
      }
6588
    }
6589
    return code;
484✔
6590
  } else if (pNode->node.pParent && nodeType(pNode->node.pParent) == QUERY_NODE_LOGIC_PLAN_AGG &&
5,769✔
6591
             !getOptHint(pRootNode->pHint, HINT_PARTITION_FIRST)) {
1,981✔
6592
    // Check if we can delete partition node
6593
    SAggLogicNode* pAgg = (SAggLogicNode*)pNode->node.pParent;
1,973✔
6594
    FOREACH(node, pNode->pPartitionKeys) {
4,934!
6595
      SGroupingSetNode* pgsNode = NULL;
2,961✔
6596
      code = nodesMakeNode(QUERY_NODE_GROUPING_SET, (SNode**)&pgsNode);
2,961✔
6597
      if (code == TSDB_CODE_SUCCESS) {
2,961!
6598
        pgsNode->groupingSetType = GP_TYPE_NORMAL;
2,961✔
6599
        pgsNode->pParameterList = NULL;
2,961✔
6600
        code = nodesMakeList(&pgsNode->pParameterList);
2,961✔
6601
      }
6602
      if (code == TSDB_CODE_SUCCESS) {
2,961!
6603
        SNode* pNew = NULL;
2,961✔
6604
        code = nodesCloneNode(node, &pNew);
2,961✔
6605
        if (TSDB_CODE_SUCCESS == code) {
2,961!
6606
          code = nodesListStrictAppend(pgsNode->pParameterList, pNew);
2,961✔
6607
        }
6608
      }
6609
      if (code == TSDB_CODE_SUCCESS) {
2,961!
6610
        // Now we are using hash agg
6611
        code = nodesListMakeAppend(&pAgg->pGroupKeys, (SNode*)pgsNode);
2,961✔
6612
      }
6613
      if (code != TSDB_CODE_SUCCESS) {
2,961!
6614
        nodesDestroyNode((SNode*)pgsNode);
×
6615
        break;
×
6616
      }
6617
    }
6618

6619
    if (code == TSDB_CODE_SUCCESS) {
1,973!
6620
      code =
6621
          replaceLogicNode(pLogicSubplan, (SLogicNode*)pNode, (SLogicNode*)nodesListGetNode(pNode->node.pChildren, 0));
1,973✔
6622
      NODES_CLEAR_LIST(pNode->node.pChildren);
1,973✔
6623
    }
6624
    if (code == TSDB_CODE_SUCCESS) {
1,973!
6625
      // For hash agg, nonblocking mode is meaningless, slimit is useless, so we reset it
6626
      pAgg->node.forceCreateNonBlockingOptr = false;
1,973✔
6627
      nodesDestroyNode(pAgg->node.pSlimit);
1,973✔
6628
      pAgg->node.pSlimit = NULL;
1,973✔
6629
      nodesDestroyNode((SNode*)pNode);
1,973✔
6630
      pCxt->optimized = true;
1,973✔
6631
    }
6632
    return code;
1,973✔
6633
  }
6634

6635
  return code;
3,796✔
6636
}
6637

6638
static bool tsmaOptMayBeOptimized(SLogicNode* pNode, void* pCtx) {
2,708,924✔
6639
  if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pNode)) {
2,708,924✔
6640
    SNode*          pTmpNode;
6641
    SNodeList*      pFuncs = NULL;
998,002✔
6642
    SScanLogicNode* pScan = (SScanLogicNode*)pNode;
998,002✔
6643
    SLogicNode*     pParent = pScan->node.pParent;
998,002✔
6644
    SNode*          pConds = pScan->node.pConditions;
998,002✔
6645

6646
    if (pScan->scanType != SCAN_TYPE_TABLE || !pParent || pConds) return false;
998,002✔
6647
    if (!pScan->pTsmas || pScan->pTsmas->size <= 0) {
526,399!
6648
      return false;
515,868✔
6649
    }
6650

6651
    switch (nodeType(pParent)) {
10,531!
6652
      case QUERY_NODE_LOGIC_PLAN_WINDOW: {
5,871✔
6653
        SWindowLogicNode* pWindow = (SWindowLogicNode*)pParent;
5,871✔
6654
        // only time window interval supported
6655
        if (pWindow->winType != WINDOW_TYPE_INTERVAL) return false;
5,871!
6656
        pFuncs = pWindow->pFuncs;
5,871✔
6657
      } break;
5,871✔
6658
      case QUERY_NODE_LOGIC_PLAN_AGG: {
4,660✔
6659
        SAggLogicNode* pAgg = (SAggLogicNode*)pParent;
4,660✔
6660
        // group/partition by normal cols not supported
6661
        if (pAgg->pGroupKeys) return false;
4,660✔
6662
        pFuncs = pAgg->pAggFuncs;
4,624✔
6663
      } break;
4,624✔
6664
      default:
×
6665
        return false;
×
6666
    }
6667

6668
    FOREACH(pTmpNode, pFuncs) {
169,350!
6669
      SFunctionNode* pFunc = (SFunctionNode*)pTmpNode;
158,903✔
6670
      if (!fmIsTSMASupportedFunc(pFunc->funcId) && !fmIsPseudoColumnFunc(pFunc->funcId) &&
158,903✔
6671
          !fmIsGroupKeyFunc(pFunc->funcId)) {
7,738✔
6672
        return false;
48✔
6673
      }
6674
    }
6675

6676
    return true;
10,447✔
6677
  }
6678
  return false;
1,710,922✔
6679
}
6680

6681
typedef struct STSMAOptUsefulTsma {
6682
  const STableTSMAInfo* pTsma;          // NULL if no tsma available, which will use original data for calculation
6683
  STimeWindow           scanRange;      // scan time range for this tsma
6684
  SArray*               pTsmaScanCols;  // SArray<int32_t> index of tsmaFuncs array
6685
  char                  targetTbName[TSDB_TABLE_NAME_LEN];  // the scanning table name, used only when pTsma is not NULL
6686
  uint64_t              targetTbUid;                        // the scanning table uid, used only when pTsma is not NULL
6687
  int8_t                precision;
6688
} STSMAOptUsefulTsma;
6689

6690
typedef struct STSMAOptCtx {
6691
  // input
6692
  SScanLogicNode*    pScan;
6693
  SLogicNode*        pParent;  // parent of Table Scan, Agg or Interval
6694
  const SNodeList*   pAggFuncs;
6695
  const STimeWindow* pTimeRange;
6696
  const SArray*      pTsmas;
6697
  SInterval*         queryInterval;  // not null with window logic node
6698
  int8_t             precision;
6699

6700
  // output
6701
  SArray*        pUsefulTsmas;  // SArray<STSMAOptUseFulTsma>, sorted by tsma interval from long to short
6702
  SArray*        pUsedTsmas;
6703
  SLogicSubplan* generatedSubPlans[2];
6704
  SNodeList**    ppParentTsmaSubplans;
6705
} STSMAOptCtx;
6706

6707
static int32_t fillTSMAOptCtx(STSMAOptCtx* pTsmaOptCtx, SScanLogicNode* pScan) {
10,443✔
6708
  int32_t code = 0;
10,443✔
6709
  pTsmaOptCtx->pScan = pScan;
10,443✔
6710
  pTsmaOptCtx->pParent = pScan->node.pParent;
10,443✔
6711
  pTsmaOptCtx->pTsmas = pScan->pTsmas;
10,443✔
6712
  pTsmaOptCtx->pTimeRange = &pScan->scanRange;
10,443✔
6713
  pTsmaOptCtx->precision = pScan->node.precision;
10,443✔
6714

6715
  if (nodeType(pTsmaOptCtx->pParent) == QUERY_NODE_LOGIC_PLAN_WINDOW) {
10,443✔
6716
    pTsmaOptCtx->queryInterval = taosMemoryCalloc(1, sizeof(SInterval));
5,867✔
6717
    if (!pTsmaOptCtx->queryInterval) return terrno;
5,867!
6718

6719
    SWindowLogicNode* pWindow = (SWindowLogicNode*)pTsmaOptCtx->pParent;
5,867✔
6720
    pTsmaOptCtx->queryInterval->interval = pWindow->interval;
5,867✔
6721
    pTsmaOptCtx->queryInterval->intervalUnit = pWindow->intervalUnit;
5,867✔
6722
    pTsmaOptCtx->queryInterval->offset = pWindow->offset;
5,867✔
6723
    pTsmaOptCtx->queryInterval->offsetUnit = pWindow->intervalUnit;
5,867✔
6724
    pTsmaOptCtx->queryInterval->sliding = pWindow->sliding;
5,867✔
6725
    pTsmaOptCtx->queryInterval->slidingUnit = pWindow->slidingUnit;
5,867✔
6726
    pTsmaOptCtx->queryInterval->precision = pWindow->node.precision;
5,867✔
6727
    pTsmaOptCtx->queryInterval->tz = tsTimezone;
5,867✔
6728
    pTsmaOptCtx->pAggFuncs = pWindow->pFuncs;
5,867✔
6729
    pTsmaOptCtx->ppParentTsmaSubplans = &pWindow->pTsmaSubplans;
5,867✔
6730
  } else {
6731
    SAggLogicNode* pAgg = (SAggLogicNode*)pTsmaOptCtx->pParent;
4,576✔
6732
    pTsmaOptCtx->pAggFuncs = pAgg->pAggFuncs;
4,576✔
6733
    pTsmaOptCtx->ppParentTsmaSubplans = &pAgg->pTsmaSubplans;
4,576✔
6734
  }
6735
  pTsmaOptCtx->pUsefulTsmas = taosArrayInit(pScan->pTsmas->size, sizeof(STSMAOptUsefulTsma));
10,443✔
6736
  pTsmaOptCtx->pUsedTsmas = taosArrayInit(3, sizeof(STSMAOptUsefulTsma));
10,443✔
6737
  if (!pTsmaOptCtx->pUsefulTsmas || !pTsmaOptCtx->pUsedTsmas) {
10,443!
6738
    code = terrno;
×
6739
  }
6740
  return code;
10,443✔
6741
}
6742

6743
static void tsmaOptFreeUsefulTsma(void* p) {
14,581✔
6744
  STSMAOptUsefulTsma* pTsma = p;
14,581✔
6745
  taosArrayDestroy(pTsma->pTsmaScanCols);
14,581✔
6746
}
14,581✔
6747

6748
static void clearTSMAOptCtx(STSMAOptCtx* pTsmaOptCtx) {
10,443✔
6749
  taosArrayDestroyEx(pTsmaOptCtx->pUsefulTsmas, tsmaOptFreeUsefulTsma);
10,443✔
6750
  taosArrayDestroy(pTsmaOptCtx->pUsedTsmas);
10,443✔
6751
  taosMemoryFreeClear(pTsmaOptCtx->queryInterval);
10,443✔
6752
}
10,443✔
6753

6754
static bool tsmaOptCheckValidInterval(int64_t tsmaInterval, int8_t unit, const STSMAOptCtx* pTsmaOptCtx) {
18,249✔
6755
  if (!pTsmaOptCtx->queryInterval) return true;
18,249✔
6756

6757
  bool validInterval = checkRecursiveTsmaInterval(tsmaInterval, unit, pTsmaOptCtx->queryInterval->interval,
9,975✔
6758
                                                  pTsmaOptCtx->queryInterval->intervalUnit,
9,975✔
6759
                                                  pTsmaOptCtx->queryInterval->precision, false);
9,975✔
6760
  bool validSliding =
6761
      checkRecursiveTsmaInterval(tsmaInterval, unit, pTsmaOptCtx->queryInterval->sliding,
9,975✔
6762
                                 pTsmaOptCtx->queryInterval->slidingUnit, pTsmaOptCtx->queryInterval->precision, false);
9,975✔
6763
  bool validOffset =
9,975✔
6764
      pTsmaOptCtx->queryInterval->offset == 0 ||
10,023✔
6765
      checkRecursiveTsmaInterval(tsmaInterval, unit, pTsmaOptCtx->queryInterval->offset,
48✔
6766
                                 pTsmaOptCtx->queryInterval->offsetUnit, pTsmaOptCtx->queryInterval->precision, false);
48✔
6767
  return validInterval && validSliding && validOffset;
9,975!
6768
}
6769

6770
static int32_t tsmaOptCheckValidFuncs(const SArray* pTsmaFuncs, const SNodeList* pQueryFuncs, SArray* pTsmaScanCols,
14,678✔
6771
                                      bool* pIsValid) {
6772
  SNode*  pNode;
6773
  bool    failed = false, found = false;
14,678✔
6774

6775
  taosArrayClear(pTsmaScanCols);
14,678✔
6776
  FOREACH(pNode, pQueryFuncs) {
104,080!
6777
    SFunctionNode* pQueryFunc = (SFunctionNode*)pNode;
89,487✔
6778
    if (fmIsPseudoColumnFunc(pQueryFunc->funcId) || fmIsGroupKeyFunc(pQueryFunc->funcId)) continue;
89,487✔
6779
    if (nodeType(pQueryFunc->pParameterList->pHead->pNode) != QUERY_NODE_COLUMN) {
66,877✔
6780
      failed = true;
8✔
6781
      break;
8✔
6782
    }
6783
    int32_t queryColId = ((SColumnNode*)pQueryFunc->pParameterList->pHead->pNode)->colId;
66,869✔
6784
    found = false;
66,869✔
6785
    int32_t notMyStateFuncId = -1;
66,869✔
6786
    // iterate funcs
6787
    for (int32_t i = 0; i < pTsmaFuncs->size; i++) {
66,367,795✔
6788
      STableTSMAFuncInfo* pTsmaFuncInfo = taosArrayGet(pTsmaFuncs, i);
66,367,718✔
6789
      if (pTsmaFuncInfo->funcId == notMyStateFuncId) continue;
66,367,718✔
6790

6791
      if (!fmIsMyStateFunc(pQueryFunc->funcId, pTsmaFuncInfo->funcId)) {
16,729,954✔
6792
        notMyStateFuncId = pTsmaFuncInfo->funcId;
83,570✔
6793
        continue;
83,570✔
6794
      }
6795

6796
      if (queryColId != pTsmaFuncInfo->colId) {
16,646,384✔
6797
        continue;
16,579,592✔
6798
      }
6799
      found = true;
66,792✔
6800
      if (NULL == taosArrayPush(pTsmaScanCols, &i)) {
66,792!
6801
        return terrno;
×
6802
      }
6803
      break;
66,792✔
6804
    }
6805
    if (failed || !found) {
66,869!
6806
      break;
6807
    }
6808
  }
6809
  *pIsValid = found;
14,678✔
6810
  return TSDB_CODE_SUCCESS;
14,678✔
6811
}
6812

6813
typedef struct STsmaOptTagCheckCtx {
6814
  const STableTSMAInfo* pTsma;
6815
  bool  ok;
6816
} STsmaOptTagCheckCtx;
6817

6818
static EDealRes tsmaOptTagCheck(SNode* pNode, void* pContext) {
60,802✔
6819
  bool found = false;
60,802✔
6820
  if (nodeType(pNode) == QUERY_NODE_COLUMN) {
60,802✔
6821
    SColumnNode* pCol = (SColumnNode*)pNode;
27,483✔
6822
    if (pCol->colType == COLUMN_TYPE_TAG) {
27,483!
6823
      STsmaOptTagCheckCtx* pCtx = pContext;
27,483✔
6824
      for (int32_t i = 0; i < pCtx->pTsma->pTags->size; ++i) {
219,864✔
6825
        SSchema* pSchema = taosArrayGet(pCtx->pTsma->pTags, i);
192,381✔
6826
        if (strcmp(pSchema->name, pCol->colName) == 0) {
192,381✔
6827
          found = true;
27,471✔
6828
        }
6829
      }
6830
      if (!found) {
27,483✔
6831
        pCtx->ok = false;
12✔
6832
        return DEAL_RES_END;
12✔
6833
      }
6834
    }
6835
  }
6836
  return DEAL_RES_CONTINUE;
60,790✔
6837
}
6838

6839
static bool tsmaOptCheckTags(STSMAOptCtx* pCtx, const STableTSMAInfo* pTsma) {
14,593✔
6840
  const SScanLogicNode* pScan = pCtx->pScan;
14,593✔
6841
  STsmaOptTagCheckCtx ctx = {.pTsma = pTsma, .ok = true};
14,593✔
6842
  nodesWalkExpr(pScan->pTagCond, tsmaOptTagCheck, &ctx);
14,593✔
6843
  if (!ctx.ok) return false;
14,593✔
6844
  nodesWalkExprs(pScan->pScanPseudoCols, tsmaOptTagCheck, &ctx);
14,589✔
6845
  if (!ctx.ok) return false;
14,589✔
6846
  nodesWalkExprs(pScan->pGroupTags, tsmaOptTagCheck, &ctx);
14,581✔
6847
  return ctx.ok;
14,581✔
6848
}
6849

6850
static int32_t tsmaOptFilterTsmas(STSMAOptCtx* pTsmaOptCtx) {
10,443✔
6851
  STSMAOptUsefulTsma usefulTsma = {
10,443✔
6852
      .pTsma = NULL, .scanRange = {.skey = TSKEY_MIN, .ekey = TSKEY_MAX}, .precision = pTsmaOptCtx->precision};
10,443✔
6853
  SArray*            pTsmaScanCols = NULL;
10,443✔
6854
  int32_t            code = 0;
10,443✔
6855

6856
  for (int32_t i = 0; i < pTsmaOptCtx->pTsmas->size; ++i) {
29,283✔
6857
    if (!pTsmaScanCols) {
18,840✔
6858
      pTsmaScanCols = taosArrayInit(pTsmaOptCtx->pAggFuncs->length, sizeof(int32_t));
17,410✔
6859
      if (!pTsmaScanCols) return terrno;
17,410!
6860
    }
6861
    if (pTsmaOptCtx->pScan->tableType == TSDB_CHILD_TABLE || pTsmaOptCtx->pScan->tableType == TSDB_NORMAL_TABLE) {
18,840✔
6862
      const STsmaTargetTbInfo* ptbInfo = taosArrayGet(pTsmaOptCtx->pScan->pTsmaTargetTbInfo, i);
11,558✔
6863
      if (ptbInfo->uid == 0) continue; // tsma res table meta not found, skip this tsma, this is possible when there is no data in this ctb
15,805✔
6864
    }
6865

6866
    STableTSMAInfo* pTsma = taosArrayGetP(pTsmaOptCtx->pTsmas, i);
18,828✔
6867
    if (!pTsma->fillHistoryFinished || tsMaxTsmaCalcDelay * 1000 < (pTsma->rspTs - pTsma->reqTs) + pTsma->delayDuration) {
18,828!
6868
      continue;
579✔
6869
    }
6870
    // filter with interval
6871
    if (!tsmaOptCheckValidInterval(pTsma->interval, pTsma->unit, pTsmaOptCtx)) {
18,249✔
6872
      continue;
3,571✔
6873
    }
6874
    // filter with funcs, note that tsma funcs has been sorted by funcId and ColId
6875
    bool valid = false;
14,678✔
6876
    int32_t code = tsmaOptCheckValidFuncs(pTsma->pFuncs, pTsmaOptCtx->pAggFuncs, pTsmaScanCols, &valid);
14,678✔
6877
    if (TSDB_CODE_SUCCESS != code)  break;
14,678!
6878
    if (!valid) continue;
14,678✔
6879

6880
    if (!tsmaOptCheckTags(pTsmaOptCtx, pTsma)) continue;
14,593✔
6881
    usefulTsma.pTsma = pTsma;
14,581✔
6882
    usefulTsma.pTsmaScanCols = pTsmaScanCols;
14,581✔
6883
    pTsmaScanCols = NULL;
14,581✔
6884
    if (NULL == taosArrayPush(pTsmaOptCtx->pUsefulTsmas, &usefulTsma)) {
29,162!
6885
      if (pTsmaScanCols) {
×
6886
        taosArrayDestroy(pTsmaScanCols);
×
6887
      }
6888
      return terrno;
×
6889
    }
6890
  }
6891
  if (pTsmaScanCols) taosArrayDestroy(pTsmaScanCols);
10,443✔
6892
  return code;
10,443✔
6893
}
6894

6895
static int32_t tsmaInfoCompWithIntervalDesc(const void* pLeft, const void* pRight) {
6,287✔
6896
  const int64_t factors[3] = {NANOSECOND_PER_MSEC, NANOSECOND_PER_USEC, 1};
6,287✔
6897
  const STSMAOptUsefulTsma *p = pLeft, *q = pRight;
6,287✔
6898
  int64_t                   pInterval = p->pTsma->interval, qInterval = q->pTsma->interval;
6,287✔
6899
  int8_t                    pUnit = p->pTsma->unit, qUnit = q->pTsma->unit;
6,287✔
6900
  if (TIME_UNIT_MONTH == pUnit) {
6,287!
6901
    pInterval = pInterval * 31 * (NANOSECOND_PER_DAY / factors[p->precision]);
×
6902
  } else if (TIME_UNIT_YEAR == pUnit){
6,287✔
6903
    pInterval = pInterval * 365 * (NANOSECOND_PER_DAY / factors[p->precision]);
320✔
6904
  }
6905
  if (TIME_UNIT_MONTH == qUnit) {
6,287✔
6906
    qInterval = qInterval * 31 * (NANOSECOND_PER_DAY / factors[q->precision]);
746✔
6907
  } else if (TIME_UNIT_YEAR == qUnit){
5,541✔
6908
    qInterval = qInterval * 365 * (NANOSECOND_PER_DAY / factors[q->precision]);
324✔
6909
  }
6910

6911
  if (pInterval > qInterval) return -1;
6,287✔
6912
  if (pInterval < qInterval) return 1;
5,949!
6913
  return 0;
×
6914
}
6915

6916
static void tsmaOptInitIntervalFromTsma(SInterval* pInterval, const STableTSMAInfo* pTsma, int8_t precision) {
18,093✔
6917
  pInterval->interval = pTsma->interval;
18,093✔
6918
  pInterval->intervalUnit = pTsma->unit;
18,093✔
6919
  pInterval->sliding = pTsma->interval;
18,093✔
6920
  pInterval->slidingUnit = pTsma->unit;
18,093✔
6921
  pInterval->offset = 0;
18,093✔
6922
  pInterval->offsetUnit = pTsma->unit;
18,093✔
6923
  pInterval->precision = precision;
18,093✔
6924
}
18,093✔
6925

6926
static const STSMAOptUsefulTsma* tsmaOptFindUsefulTsma(const SArray* pUsefulTsmas, int32_t startIdx,
7,376✔
6927
                                                       int64_t startAlignInterval, int64_t endAlignInterval,
6928
                                                       int8_t precision) {
6929
  SInterval tsmaInterval;
6930
  for (int32_t i = startIdx; i < pUsefulTsmas->size; ++i) {
12,215✔
6931
    const STSMAOptUsefulTsma* pUsefulTsma = taosArrayGet(pUsefulTsmas, i);
5,051✔
6932
    tsmaOptInitIntervalFromTsma(&tsmaInterval, pUsefulTsma->pTsma, precision);
5,051✔
6933
    if (taosTimeTruncate(startAlignInterval, &tsmaInterval) == startAlignInterval &&
7,376✔
6934
        taosTimeTruncate(endAlignInterval, &tsmaInterval) == endAlignInterval) {
2,325✔
6935
      return pUsefulTsma;
212✔
6936
    }
6937
  }
6938
  return NULL;
7,164✔
6939
}
6940

6941
static int32_t tsmaOptSplitWindows(STSMAOptCtx* pTsmaOptCtx, const STimeWindow* pScanRange) {
8,618✔
6942
  bool                      needTailWindow = false;
8,618✔
6943
  bool                      isSkeyAlignedWithTsma = true, isEkeyAlignedWithTsma = true;
8,618✔
6944
  int32_t                   code = 0;
8,618✔
6945
  int64_t                   winSkey = TSKEY_MIN, winEkey = TSKEY_MAX;
8,618✔
6946
  int64_t                   startOfSkeyFirstWin = pScanRange->skey, endOfSkeyFirstWin;
8,618✔
6947
  int64_t                   startOfEkeyFirstWin = pScanRange->ekey, endOfEkeyFirstWin;
8,618✔
6948
  SInterval                 interval, tsmaInterval;
6949
  STimeWindow               scanRange = *pScanRange;
8,618✔
6950
  const SInterval*          pInterval = pTsmaOptCtx->queryInterval;
8,618✔
6951
  const STSMAOptUsefulTsma* pUsefulTsma = taosArrayGet(pTsmaOptCtx->pUsefulTsmas, 0);
8,618✔
6952
  const STableTSMAInfo*     pTsma = pUsefulTsma->pTsma;
8,618✔
6953

6954
  if (pScanRange->ekey <= pScanRange->skey) return code;
8,618✔
6955

6956
  if (!pInterval) {
8,539✔
6957
    tsmaOptInitIntervalFromTsma(&interval, pTsma, pTsmaOptCtx->precision);
4,503✔
6958
    pInterval = &interval;
4,503✔
6959
  }
6960

6961
  tsmaOptInitIntervalFromTsma(&tsmaInterval, pTsma, pTsmaOptCtx->precision);
8,539✔
6962

6963
  // check for head windows
6964
  if (pScanRange->skey != TSKEY_MIN) {
8,539✔
6965
    startOfSkeyFirstWin = taosTimeTruncate(pScanRange->skey, pInterval);
4,661✔
6966
    endOfSkeyFirstWin =
6967
        taosTimeAdd(startOfSkeyFirstWin, pInterval->interval, pInterval->intervalUnit, pTsmaOptCtx->precision);
4,661✔
6968
    isSkeyAlignedWithTsma = taosTimeTruncate(pScanRange->skey, &tsmaInterval) == pScanRange->skey;
4,661✔
6969
  } else {
6970
    endOfSkeyFirstWin = TSKEY_MIN;
3,878✔
6971
  }
6972

6973
  // check for tail windows
6974
  if (pScanRange->ekey != TSKEY_MAX) {
8,539✔
6975
    startOfEkeyFirstWin = taosTimeTruncate(pScanRange->ekey, pInterval);
4,581✔
6976
    endOfEkeyFirstWin =
6977
        taosTimeAdd(startOfEkeyFirstWin, pInterval->interval, pInterval->intervalUnit, pTsmaOptCtx->precision);
4,581✔
6978
    isEkeyAlignedWithTsma = taosTimeTruncate(pScanRange->ekey + 1, &tsmaInterval) == (pScanRange->ekey + 1);
4,581✔
6979
    if (startOfEkeyFirstWin > startOfSkeyFirstWin) {
4,581✔
6980
      needTailWindow = true;
3,903✔
6981
    }
6982
  }
6983

6984
  // add head tsma if possible
6985
  if (!isSkeyAlignedWithTsma) {
8,539✔
6986
    scanRange.ekey = TMIN(
3,943✔
6987
        scanRange.ekey,
6988
        taosTimeAdd(startOfSkeyFirstWin, pInterval->interval * 1, pInterval->intervalUnit, pTsmaOptCtx->precision) - 1);
6989
    const STSMAOptUsefulTsma* pTsmaFound =
6990
        tsmaOptFindUsefulTsma(pTsmaOptCtx->pUsefulTsmas, 1, scanRange.skey, scanRange.ekey + 1, pTsmaOptCtx->precision);
3,943✔
6991
    STSMAOptUsefulTsma usefulTsma = {.pTsma = pTsmaFound ? pTsmaFound->pTsma : NULL,
3,943✔
6992
                                     .scanRange = scanRange,
6993
                                     .pTsmaScanCols = pTsmaFound ? pTsmaFound->pTsmaScanCols : NULL};
3,943✔
6994
    if (NULL == taosArrayPush(pTsmaOptCtx->pUsedTsmas, &usefulTsma))
7,886!
6995
      return terrno;
×
6996
  }
6997

6998
  // the main tsma
6999
  if (endOfSkeyFirstWin < startOfEkeyFirstWin || (endOfSkeyFirstWin == startOfEkeyFirstWin && (isSkeyAlignedWithTsma || isEkeyAlignedWithTsma))) {
8,539✔
7000
    scanRange.ekey =
7,550✔
7001
        TMIN(pScanRange->ekey, isEkeyAlignedWithTsma ? pScanRange->ekey : startOfEkeyFirstWin - 1);
7,550✔
7002
    if (!isSkeyAlignedWithTsma) {
7,550✔
7003
      scanRange.skey = endOfSkeyFirstWin;
3,064✔
7004
    }
7005
    STSMAOptUsefulTsma usefulTsma = {
7,550✔
7006
        .pTsma = pTsma, .scanRange = scanRange, .pTsmaScanCols = pUsefulTsma->pTsmaScanCols};
7,550✔
7007
    if (NULL == taosArrayPush(pTsmaOptCtx->pUsedTsmas, &usefulTsma))
15,100!
7008
      return terrno;
×
7009
  }
7010

7011
  // add tail tsma if possible
7012
  if (!isEkeyAlignedWithTsma && needTailWindow) {
8,539✔
7013
    scanRange.skey = startOfEkeyFirstWin;
3,433✔
7014
    scanRange.ekey = pScanRange->ekey;
3,433✔
7015
    const STSMAOptUsefulTsma* pTsmaFound =
7016
        tsmaOptFindUsefulTsma(pTsmaOptCtx->pUsefulTsmas, 1, scanRange.skey - startOfEkeyFirstWin,
3,433✔
7017
                              scanRange.ekey + 1 - startOfEkeyFirstWin, pTsmaOptCtx->precision);
3,433✔
7018
    STSMAOptUsefulTsma usefulTsma = {.pTsma = pTsmaFound ? pTsmaFound->pTsma : NULL,
3,433✔
7019
                                     .scanRange = scanRange,
7020
                                     .pTsmaScanCols = pTsmaFound ? pTsmaFound->pTsmaScanCols : NULL};
3,433✔
7021
    if (NULL == taosArrayPush(pTsmaOptCtx->pUsedTsmas, &usefulTsma))
6,866!
7022
      return terrno;
×
7023
  }
7024
  return code;
8,539✔
7025
}
7026

7027
int32_t tsmaOptCreateTsmaScanCols(const STSMAOptUsefulTsma* pTsma, const SNodeList* pAggFuncs, SNodeList** ppList) {
7,762✔
7028
  if (!pTsma->pTsma || !pTsma->pTsmaScanCols) {
7,762!
7029
    return TSDB_CODE_PLAN_INTERNAL_ERROR;
×
7030
  }
7031
  int32_t    code;
7032
  SNode*     pNode;
7033
  SNodeList* pScanCols = NULL;
7,762✔
7034

7035
  int32_t i = 0;
7,762✔
7036

7037
  FOREACH(pNode, pAggFuncs) {
69,083!
7038
    SFunctionNode* pFunc = (SFunctionNode*)pNode;
61,321✔
7039
    if (fmIsPseudoColumnFunc(pFunc->funcId) || fmIsGroupKeyFunc(pFunc->funcId)) {
61,321✔
7040
      continue;
11,108✔
7041
    }
7042
    const int32_t* idx = taosArrayGet(pTsma->pTsmaScanCols, i);
50,213✔
7043
    SColumnNode*   pCol = NULL;
50,213✔
7044
    code = nodesMakeNode(QUERY_NODE_COLUMN, (SNode**)&pCol);
50,213✔
7045
    if (pCol) {
50,213!
7046
      pCol->colId = *idx + 2;
50,213✔
7047
      pCol->tableType = TSDB_SUPER_TABLE;
50,213✔
7048
      pCol->tableId = pTsma->targetTbUid;
50,213✔
7049
      pCol->colType = COLUMN_TYPE_COLUMN;
50,213✔
7050
      strcpy(pCol->tableName, pTsma->targetTbName);
50,213✔
7051
      strcpy(pCol->dbName, pTsma->pTsma->targetDbFName);
50,213✔
7052
      strcpy(pCol->colName, pFunc->node.aliasName);
50,213✔
7053
      strcpy(pCol->node.aliasName, pFunc->node.aliasName);
50,213✔
7054
      pCol->node.resType.type = TSDB_DATA_TYPE_BINARY;
50,213✔
7055
      code = nodesListMakeStrictAppend(&pScanCols, (SNode*)pCol);
50,213✔
7056
    }
7057
    if (code) break;
50,213!
7058
    ++i;
50,213✔
7059
  }
7060

7061
  if (code) {
7,762!
7062
    nodesDestroyList(pScanCols);
×
7063
    pScanCols = NULL;
×
7064
  } else {
7065
    *ppList = pScanCols;
7,762✔
7066
  }
7067
  return code;
7,762✔
7068
}
7069

7070
static int32_t tsmaOptRewriteTag(const STSMAOptCtx* pTsmaOptCtx, const STSMAOptUsefulTsma* pTsma,
17,600✔
7071
                                 SColumnNode* pTagCol) {
7072
  bool found = false;
17,600✔
7073
  if (pTagCol->colType != COLUMN_TYPE_TAG) return 0;
17,600!
7074
  for (int32_t i = 0; i < pTsma->pTsma->pTags->size; ++i) {
59,524!
7075
    const SSchema* pSchema = taosArrayGet(pTsma->pTsma->pTags, i);
59,524✔
7076
    if (strcmp(pTagCol->colName, pSchema->name) == 0) {
59,524✔
7077
      strcpy(pTagCol->tableName, pTsma->targetTbName);
17,600✔
7078
      strcpy(pTagCol->tableAlias, pTsma->targetTbName);
17,600✔
7079
      pTagCol->tableId = pTsma->targetTbUid;
17,600✔
7080
      pTagCol->tableType = TSDB_SUPER_TABLE;
17,600✔
7081
      pTagCol->colId = pSchema->colId;
17,600✔
7082
      found = true;
17,600✔
7083
      break;
17,600✔
7084
    }
7085
  }
7086
  return found ? TSDB_CODE_SUCCESS : TSDB_CODE_PLAN_INTERNAL_ERROR;
17,600!
7087
}
7088

7089
static int32_t tsmaOptRewriteTbname(const STSMAOptCtx* pTsmaOptCtx, SNode** pTbNameNode,
8,528✔
7090
                                    const STSMAOptUsefulTsma* pTsma) {
7091
  int32_t     code = 0;
8,528✔
7092
  SExprNode*  pRewrittenFunc = NULL;
8,528✔
7093
  code = nodesMakeNode(pTsma ? QUERY_NODE_COLUMN : QUERY_NODE_FUNCTION, (SNode**)&pRewrittenFunc);
8,528✔
7094
  SValueNode* pValue = NULL;
8,528✔
7095
  if (code == TSDB_CODE_SUCCESS) {
8,528!
7096
    pRewrittenFunc->resType = ((SExprNode*)(*pTbNameNode))->resType;
8,528✔
7097
  }
7098

7099
  if (pTsma && code == TSDB_CODE_SUCCESS) {
8,528!
7100
    nodesDestroyNode(*pTbNameNode);
6,846✔
7101
    SColumnNode* pCol = (SColumnNode*)pRewrittenFunc;
6,846✔
7102
    const SSchema* pSchema = taosArrayGet(pTsma->pTsma->pTags, pTsma->pTsma->pTags->size - 1);
6,846✔
7103
    strcpy(pCol->tableName, pTsma->targetTbName);
6,846✔
7104
    strcpy(pCol->tableAlias, pTsma->targetTbName);
6,846✔
7105
    pCol->tableId = pTsma->targetTbUid;
6,846✔
7106
    pCol->tableType = TSDB_SUPER_TABLE;
6,846✔
7107
    pCol->colId = pSchema->colId;
6,846✔
7108
    pCol->colType = COLUMN_TYPE_TAG;
6,846✔
7109
  } else if (code == TSDB_CODE_SUCCESS) {
1,682!
7110
    // if no tsma, we replace func tbname with concat('', tbname)
7111
    SFunctionNode* pFunc = (SFunctionNode*)pRewrittenFunc;
1,682✔
7112
    pFunc->funcId = fmGetFuncId("concat");
1,682✔
7113
    snprintf(pFunc->functionName, TSDB_FUNC_NAME_LEN, "concat");
1,682✔
7114
    code = nodesMakeNode(QUERY_NODE_VALUE, (SNode**)&pValue);
1,682✔
7115
    if (!pValue) code = TSDB_CODE_OUT_OF_MEMORY;
1,682!
7116

7117
    if (code == TSDB_CODE_SUCCESS) {
1,682!
7118
      pValue->translate = true;
1,682✔
7119
      pValue->node.resType = ((SExprNode*)(*pTbNameNode))->resType;
1,682✔
7120
      pValue->literal = taosMemoryCalloc(1, TSDB_TABLE_FNAME_LEN + 1);
1,682✔
7121
      pValue->datum.p = taosMemoryCalloc(1, TSDB_TABLE_FNAME_LEN + 1 + VARSTR_HEADER_SIZE);
1,682✔
7122
      if (!pValue->literal || !pValue->datum.p) code = terrno;
1,682!
7123
    }
7124

7125
    if (code == TSDB_CODE_SUCCESS) {
1,682!
7126
      code = nodesListMakeStrictAppend(&pFunc->pParameterList, (SNode*)pValue);
1,682✔
7127
      pValue = NULL;
1,682✔
7128
    }
7129
    if (code == TSDB_CODE_SUCCESS) {
1,682!
7130
      code = nodesListStrictAppend(pFunc->pParameterList, *pTbNameNode);
1,682✔
7131
    }
7132
  }
7133

7134
  if (code == TSDB_CODE_SUCCESS) {
8,528!
7135
    *pTbNameNode = (SNode*)pRewrittenFunc;
8,528✔
7136
  } else {
7137
    nodesDestroyNode((SNode*)pRewrittenFunc);
×
7138
    if (pValue) nodesDestroyNode((SNode*)pValue);
×
7139
  }
7140

7141
  return code;
8,528✔
7142
}
7143

7144
struct TsmaOptRewriteCtx {
7145
  const STSMAOptCtx*        pTsmaOptCtx;
7146
  const STSMAOptUsefulTsma* pTsma;
7147
  bool                      rewriteTag;
7148
  bool                      rewriteTbname;
7149
  int32_t                   code;
7150
};
7151

7152
EDealRes tsmaOptNodeRewriter(SNode** ppNode, void* ctx) {
56,884✔
7153
  SNode*                    pNode = *ppNode;
56,884✔
7154
  int32_t                   code = 0;
56,884✔
7155
  struct TsmaOptRewriteCtx* pCtx = ctx;
56,884✔
7156
  if (pCtx->rewriteTag && nodeType(pNode) == QUERY_NODE_COLUMN && ((SColumnNode*)pNode)->colType == COLUMN_TYPE_TAG) {
56,884✔
7157
    code = tsmaOptRewriteTag(pCtx->pTsmaOptCtx, pCtx->pTsma, (SColumnNode*)pNode);
17,600✔
7158
  } else if (pCtx->rewriteTbname &&
39,284!
7159
             ((nodeType(pNode) == QUERY_NODE_FUNCTION && ((SFunctionNode*)pNode)->funcType == FUNCTION_TYPE_TBNAME) ||
39,284✔
7160
              (nodeType(pNode) == QUERY_NODE_COLUMN && ((SColumnNode*)pNode)->colType == COLUMN_TYPE_TBNAME))) {
32,914✔
7161
    code = tsmaOptRewriteTbname(pCtx->pTsmaOptCtx, ppNode, pCtx->pTsma);
8,528✔
7162
    if (code == TSDB_CODE_SUCCESS) return DEAL_RES_IGNORE_CHILD;
8,528!
7163
  }
7164
  if (code) {
48,356!
7165
    pCtx->code = code;
×
7166
    return DEAL_RES_ERROR;
×
7167
  }
7168
  return DEAL_RES_CONTINUE;
48,356✔
7169
}
7170

7171
static int32_t tsmaOptRewriteNode(SNode** pNode, STSMAOptCtx* pCtx, const STSMAOptUsefulTsma* pTsma, bool rewriteTbName, bool rewriteTag) {
21,676✔
7172
  struct TsmaOptRewriteCtx ctx = {
21,676✔
7173
      .pTsmaOptCtx = pCtx, .pTsma = pTsma, .rewriteTag = rewriteTag, .rewriteTbname = rewriteTbName, .code = 0};
7174
  SNode* pOut = *pNode;
21,676✔
7175
  nodesRewriteExpr(&pOut, tsmaOptNodeRewriter, &ctx);
21,676✔
7176
  if (ctx.code == TSDB_CODE_SUCCESS) *pNode = pOut;
21,676!
7177
  return ctx.code;
21,676✔
7178
}
7179

7180
static int32_t tsmaOptRewriteNodeList(SNodeList* pNodes, STSMAOptCtx* pCtx, const STSMAOptUsefulTsma* pTsma,
15,524✔
7181
                                      bool rewriteTbName, bool rewriteTag) {
7182
  int32_t code = 0;
15,524✔
7183
  SNode*  pNode;
7184
  FOREACH(pNode, pNodes) {
29,438✔
7185
    SNode* pOut = pNode;
13,914✔
7186
    code = tsmaOptRewriteNode(&pOut, pCtx, pTsma, rewriteTbName, rewriteTag);
13,914✔
7187
    if (TSDB_CODE_SUCCESS != code) break;
13,914!
7188
    REPLACE_NODE(pOut);
13,914✔
7189
  }
7190
  return code;
15,524✔
7191
}
7192

7193
static int32_t tsmaOptRewriteScan(STSMAOptCtx* pTsmaOptCtx, SScanLogicNode* pNewScan, const STSMAOptUsefulTsma* pTsma) {
13,780✔
7194
  SNode*  pNode;
7195
  int32_t code = 0;
13,780✔
7196

7197
  pNewScan->scanRange.skey = pTsma->scanRange.skey;
13,780✔
7198
  pNewScan->scanRange.ekey = pTsma->scanRange.ekey;
13,780✔
7199

7200
  if (pTsma->pTsma) {
13,780✔
7201
    // PK col
7202
    SColumnNode* pPkTsCol = NULL;
7,762✔
7203
    FOREACH(pNode, pNewScan->pScanCols) {
9,338!
7204
      SColumnNode* pCol = (SColumnNode*)pNode;
9,338✔
7205
      if (pCol->colId == PRIMARYKEY_TIMESTAMP_COL_ID) {
9,338✔
7206
        pPkTsCol = NULL;
7,762✔
7207
        code = nodesCloneNode((SNode*)pCol, (SNode**)&pPkTsCol);
7,762✔
7208
        break;
7,762✔
7209
      }
7210
    }
7211
    if (code == TSDB_CODE_SUCCESS) {
7,762!
7212
      nodesDestroyList(pNewScan->pScanCols);
7,762✔
7213
      // normal cols
7214
      pNewScan->pScanCols = NULL;
7,762✔
7215
      code = tsmaOptCreateTsmaScanCols(pTsma, pTsmaOptCtx->pAggFuncs, &pNewScan->pScanCols);
7,762✔
7216
    }
7217
    if (code == TSDB_CODE_SUCCESS && pPkTsCol) {
7,762!
7218
      tstrncpy(pPkTsCol->tableName, pTsma->targetTbName, TSDB_TABLE_NAME_LEN);
7,762✔
7219
      tstrncpy(pPkTsCol->tableAlias, pTsma->targetTbName, TSDB_TABLE_NAME_LEN);
7,762✔
7220
      pPkTsCol->tableId = pTsma->targetTbUid;
7,762✔
7221
      code = nodesListMakeStrictAppend(&pNewScan->pScanCols, (SNode*)pPkTsCol);
7,762✔
7222
    } else if (pPkTsCol){
×
7223
      nodesDestroyNode((SNode*)pPkTsCol);
×
7224
    }
7225
    if (code == TSDB_CODE_SUCCESS) {
7,762!
7226
      pNewScan->stableId = pTsma->pTsma->destTbUid;
7,762✔
7227
      pNewScan->tableId = pTsma->targetTbUid;
7,762✔
7228
      strcpy(pNewScan->tableName.tname, pTsma->targetTbName);
7,762✔
7229
    }
7230
    if (code == TSDB_CODE_SUCCESS) {
7,762!
7231
      code = tsmaOptRewriteNodeList(pNewScan->pScanPseudoCols, pTsmaOptCtx, pTsma, true, true);
7,762✔
7232
    }
7233
    if (code == TSDB_CODE_SUCCESS) {
7,762!
7234
      code = tsmaOptRewriteNode(&pNewScan->pTagCond, pTsmaOptCtx, pTsma, true, true);
7,762✔
7235
    }
7236
    if (code == TSDB_CODE_SUCCESS) {
7,762!
7237
      code = tsmaOptRewriteNodeList(pNewScan->pGroupTags, pTsmaOptCtx, pTsma, true, true);
7,762✔
7238
    }
7239
    if (TSDB_CODE_SUCCESS == code) {
7,762!
7240
      pTsmaOptCtx->pScan->dataRequired = FUNC_DATA_REQUIRED_DATA_LOAD;
7,762✔
7241
      if (pTsmaOptCtx->pScan->pTsmaTargetTbVgInfo && pTsmaOptCtx->pScan->pTsmaTargetTbVgInfo->size > 0) {
7,762!
7242
        for (int32_t i = 0; i < taosArrayGetSize(pTsmaOptCtx->pScan->pTsmas); ++i) {
8,564!
7243
          STableTSMAInfo* pTsmaInfo = taosArrayGetP(pTsmaOptCtx->pScan->pTsmas, i);
8,564✔
7244
          if (pTsmaInfo == pTsma->pTsma) {
8,564✔
7245
            const SVgroupsInfo* pVgpsInfo = taosArrayGetP(pTsmaOptCtx->pScan->pTsmaTargetTbVgInfo, i);
5,398✔
7246
            taosMemoryFreeClear(pNewScan->pVgroupList);
5,398!
7247
            int32_t len = sizeof(int32_t) + sizeof(SVgroupInfo) * pVgpsInfo->numOfVgroups;
5,398✔
7248
            pNewScan->pVgroupList = taosMemoryCalloc(1, len);
5,398✔
7249
            if (!pNewScan->pVgroupList) {
5,398!
7250
              code = terrno;
×
7251
              break;
×
7252
            }
7253
            memcpy(pNewScan->pVgroupList, pVgpsInfo, len);
5,398✔
7254
            break;
5,398✔
7255
          }
7256
        }
7257
      }
7258
    }
7259
  } else {
7260
    FOREACH(pNode, pNewScan->pGroupTags) {
11,260✔
7261
      // rewrite tbname recursively
7262
      struct TsmaOptRewriteCtx ctx = {
5,242✔
7263
          .pTsmaOptCtx = pTsmaOptCtx, .pTsma = NULL, .rewriteTag = false, .rewriteTbname = true, .code = 0};
7264
      nodesRewriteExpr(&pNode, tsmaOptNodeRewriter, &ctx);
5,242✔
7265
      if (ctx.code) {
5,242!
7266
        code = ctx.code;
×
7267
      } else {
7268
        REPLACE_NODE(pNode);
5,242✔
7269
      }
7270
    }
7271
  }
7272
  return code;
13,780✔
7273
}
7274

7275
static int32_t tsmaOptCreateWStart(int8_t precision, SFunctionNode** pWStartOut) {
×
7276
  SFunctionNode* pWStart = NULL;
×
7277
  int32_t code = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&pWStart);
×
7278
  if (NULL == pWStart) {
×
7279
    return code;
×
7280
  }
7281
  strcpy(pWStart->functionName, "_wstart");
×
7282
  int64_t pointer = (int64_t)pWStart;
×
7283
  char    name[TSDB_COL_NAME_LEN + TSDB_POINTER_PRINT_BYTES + TSDB_NAME_DELIMITER_LEN + 1] = {0};
×
7284
  int32_t len = tsnprintf(name, sizeof(name) - 1, "%s.%" PRId64 "", pWStart->functionName, pointer);
×
7285
  (void)taosHashBinary(name, len);
7286
  strncpy(pWStart->node.aliasName, name, TSDB_COL_NAME_LEN - 1);
×
7287
  pWStart->node.resType.precision = precision;
×
7288

7289
  code = fmGetFuncInfo(pWStart, NULL, 0);
×
7290
  if (code) {
×
7291
    nodesDestroyNode((SNode*)pWStart);
×
7292
  } else {
7293
    *pWStartOut = pWStart;
×
7294
  }
7295
  return code;
×
7296
}
7297

7298
static int32_t tsmaOptRewriteParent(STSMAOptCtx* pTsmaOptCtx, SLogicNode* pParent, SScanLogicNode* pScan,
7,762✔
7299
                                  const STSMAOptUsefulTsma* pTsma) {
7300
  int32_t           code = 0;
7,762✔
7301
  SColumnNode*      pColNode;
7302
  SWindowLogicNode* pWindow = NULL;
7,762✔
7303
  SAggLogicNode*    pAgg;
7304
  SNodeList*        pAggFuncs;
7305
  SListCell*        pScanListCell;
7306
  SNode*            pAggFuncNode;
7307
  SNodeList*        pAggStateFuncs = NULL;
7,762✔
7308
  bool              isFirstMergeNode = pTsmaOptCtx->pScan == pScan;
7,762✔
7309
  SFunctionNode *   pPartial = NULL, *pMerge = NULL;
7,762✔
7310

7311
  if (nodeType(pParent) == QUERY_NODE_LOGIC_PLAN_WINDOW) {
7,762✔
7312
    pWindow = (SWindowLogicNode*)pParent;
3,536✔
7313
    pAggFuncs = pWindow->pFuncs;
3,536✔
7314
  } else {
7315
    pAgg = (SAggLogicNode*)pParent;
4,226✔
7316
    pAggFuncs = pAgg->pAggFuncs;
4,226✔
7317
  }
7318
  pScanListCell = pScan->pScanCols->pHead;
7,762✔
7319

7320
  FOREACH(pAggFuncNode, pAggFuncs) {
69,083!
7321
    SFunctionNode* pAggFunc = (SFunctionNode*)pAggFuncNode;
61,321✔
7322
    if (fmIsGroupKeyFunc(pAggFunc->funcId)) {
61,321✔
7323
      struct TsmaOptRewriteCtx ctx = {
5,772✔
7324
          .pTsmaOptCtx = pTsmaOptCtx, .pTsma = pTsma, .rewriteTag = true, .rewriteTbname = true, .code = 0};
7325
      nodesRewriteExpr(&pAggFuncNode, tsmaOptNodeRewriter, &ctx);
5,772✔
7326
      if (ctx.code) {
5,772!
7327
        code = ctx.code;
×
7328
        break;
×
7329
      } else {
7330
        REPLACE_NODE(pAggFuncNode);
5,772✔
7331
      }
7332
      continue;
5,772✔
7333
    } else if (fmIsPseudoColumnFunc(pAggFunc->funcId)) {
55,549✔
7334
      continue;
5,336✔
7335
    }
7336
    code = fmGetDistMethod(pAggFunc, &pPartial, NULL, &pMerge);
50,213✔
7337
    if (code) break;
50,213!
7338

7339
    pColNode = (SColumnNode*)pScanListCell->pNode;
50,213✔
7340
    pScanListCell = pScanListCell->pNext;
50,213✔
7341
    pColNode->node.resType = pPartial->node.resType;
50,213✔
7342
    // currently we assume that the first parameter must be the scan column
7343
    (void)nodesListErase(pMerge->pParameterList, pMerge->pParameterList->pHead);
50,213✔
7344
    SNode* pNew = NULL;
50,213✔
7345
    code = nodesCloneNode((SNode*)pColNode, &pNew);
50,213✔
7346
    if (TSDB_CODE_SUCCESS  == code) {
50,213!
7347
      code = nodesListPushFront(pMerge->pParameterList, pNew);
50,213✔
7348
    }
7349
    nodesDestroyNode((SNode*)pPartial);
50,213✔
7350
    if (TSDB_CODE_SUCCESS != code) {
50,213!
7351
      nodesDestroyNode(pNew);
×
7352
      break;
×
7353
    }
7354

7355
    REPLACE_NODE(pMerge);
50,213✔
7356
  }
7357

7358
  if (code == TSDB_CODE_SUCCESS && pWindow) {
7,762!
7359
    SColumnNode* pCol = (SColumnNode*)pScan->pScanCols->pTail->pNode;
3,536✔
7360
    nodesDestroyNode(pWindow->pTspk);
3,536✔
7361
    pWindow->pTspk = NULL;
3,536✔
7362
    code = nodesCloneNode((SNode*)pCol, &pWindow->pTspk);
3,536✔
7363
  }
7364

7365
  if (code == TSDB_CODE_SUCCESS) {
7,762!
7366
    nodesDestroyList(pScan->node.pTargets);
7,762✔
7367
    code = createColumnByRewriteExprs(pScan->pScanCols, &pScan->node.pTargets);
7,762✔
7368
  }
7369
  if (code == TSDB_CODE_SUCCESS) {
7,762!
7370
    code = createColumnByRewriteExprs(pScan->pScanPseudoCols, &pScan->node.pTargets);
7,762✔
7371
  }
7372

7373
  return code;
7,762✔
7374
}
7375

7376
static int32_t tsmaOptGeneratePlan(STSMAOptCtx* pTsmaOptCtx) {
7,574✔
7377
  int32_t                   code = 0;
7,574✔
7378
  const STSMAOptUsefulTsma* pTsma = NULL;
7,574✔
7379
  SNodeList*                pAggFuncs = NULL;
7,574✔
7380
  bool                      hasSubPlan = false;
7,574✔
7381

7382
  for (int32_t i = 0; i < pTsmaOptCtx->pUsedTsmas->size; ++i) {
21,354✔
7383
    STSMAOptUsefulTsma* pTsma = taosArrayGet(pTsmaOptCtx->pUsedTsmas, i);
13,780✔
7384
    if (!pTsma->pTsma) continue;
13,780✔
7385
    if (pTsmaOptCtx->pScan->tableType == TSDB_CHILD_TABLE || pTsmaOptCtx->pScan->tableType == TSDB_NORMAL_TABLE) {
7,762✔
7386
      for (int32_t j = 0; j < pTsmaOptCtx->pScan->pTsmas->size; ++j) {
13,726✔
7387
        if (taosArrayGetP(pTsmaOptCtx->pScan->pTsmas, j) == pTsma->pTsma) {
8,658✔
7388
          const STsmaTargetTbInfo* ptbInfo = taosArrayGet(pTsmaOptCtx->pScan->pTsmaTargetTbInfo, j);
5,068✔
7389
          strcpy(pTsma->targetTbName, ptbInfo->tableName);
5,068✔
7390
          pTsma->targetTbUid = ptbInfo->uid;
5,068✔
7391
        }
7392
      }
7393
    } else {
7394
      strcpy(pTsma->targetTbName, pTsma->pTsma->targetTb);
2,694✔
7395
      pTsma->targetTbUid = pTsma->pTsma->destTbUid;
2,694✔
7396
    }
7397
  }
7398

7399
  for (int32_t i = 1; i < pTsmaOptCtx->pUsedTsmas->size && code == TSDB_CODE_SUCCESS; ++i) {
13,780!
7400
    pTsma = taosArrayGet(pTsmaOptCtx->pUsedTsmas, i);
6,206✔
7401
    SLogicSubplan* pSubplan = NULL;
6,206✔
7402
    code = nodesMakeNode(QUERY_NODE_LOGIC_SUBPLAN, (SNode**)&pSubplan);
6,206✔
7403
    if (!pSubplan) {
6,206!
7404
      break;
×
7405
    }
7406
    pSubplan->subplanType = SUBPLAN_TYPE_SCAN;
6,206✔
7407
    pTsmaOptCtx->generatedSubPlans[i - 1] = pSubplan;
6,206✔
7408
    hasSubPlan = true;
6,206✔
7409
    SLogicNode* pParent = NULL;
6,206✔
7410
    code = nodesCloneNode((SNode*)pTsmaOptCtx->pParent, (SNode**)&pParent);
6,206✔
7411
    if (!pParent) {
6,206!
7412
      break;
×
7413
    }
7414
    pSubplan->pNode = pParent;
6,206✔
7415
    pParent->pParent = NULL;
6,206✔
7416
    pParent->groupAction = GROUP_ACTION_KEEP;
6,206✔
7417
    SScanLogicNode* pScan = (SScanLogicNode*)pParent->pChildren->pHead->pNode;
6,206✔
7418
    code = tsmaOptRewriteScan(pTsmaOptCtx, pScan, pTsma);
6,206✔
7419
    if (code == TSDB_CODE_SUCCESS && pTsma->pTsma) {
6,206!
7420
      code = tsmaOptRewriteParent(pTsmaOptCtx, pParent, pScan, pTsma);
3,184✔
7421
    }
7422
  }
7423

7424
  if (code == TSDB_CODE_SUCCESS) {
7,574!
7425
    pTsma = taosArrayGet(pTsmaOptCtx->pUsedTsmas, 0);
7,574✔
7426
    pTsmaOptCtx->pScan->needSplit = hasSubPlan;
7,574✔
7427
    code = tsmaOptRewriteScan(pTsmaOptCtx, pTsmaOptCtx->pScan, pTsma);
7,574✔
7428
    if (code == TSDB_CODE_SUCCESS && pTsma->pTsma) {
7,574!
7429
      code = tsmaOptRewriteParent(pTsmaOptCtx, pTsmaOptCtx->pParent, pTsmaOptCtx->pScan, pTsma);
4,578✔
7430
    }
7431
  }
7432

7433
  return code;
7,574✔
7434
}
7435

7436
static bool tsmaOptIsUsingTsmas(STSMAOptCtx* pCtx) {
8,618✔
7437
  if (pCtx->pUsedTsmas->size == 0) {
8,618✔
7438
    return false;
189✔
7439
  }
7440
  for (int32_t i = 0; i < pCtx->pUsedTsmas->size; ++i) {
12,571✔
7441
    const STSMAOptUsefulTsma*pTsma = taosArrayGet(pCtx->pUsedTsmas, i);
11,716✔
7442
    if (pTsma->pTsma) return true;
11,716✔
7443
  }
7444
  return false;
855✔
7445
}
7446

7447
static int32_t tsmaOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
767,703✔
7448
  int32_t         code = 0;
767,703✔
7449
  STSMAOptCtx     tsmaOptCtx = {0};
767,703✔
7450
  SScanLogicNode* pScan = (SScanLogicNode*)optFindPossibleNode(pLogicSubplan->pNode, tsmaOptMayBeOptimized, NULL);
767,703✔
7451
  if (!pScan) return code;
767,709✔
7452

7453
  SLogicNode* pRootNode = getLogicNodeRootNode((SLogicNode*)pScan);
10,447✔
7454
  if (getOptHint(pRootNode->pHint, HINT_SKIP_TSMA)) return code;
10,447✔
7455

7456
  code = fillTSMAOptCtx(&tsmaOptCtx, pScan);
10,443✔
7457
  if (code == TSDB_CODE_SUCCESS) {
10,443!
7458
    // 1. extract useful tsmas
7459
    code = tsmaOptFilterTsmas(&tsmaOptCtx);
10,443✔
7460

7461
    if (code == TSDB_CODE_SUCCESS && tsmaOptCtx.pUsefulTsmas->size > 0) {
10,443!
7462
      // 2. sort useful tsmas with interval
7463
      taosArraySort(tsmaOptCtx.pUsefulTsmas, tsmaInfoCompWithIntervalDesc);
8,618✔
7464
      // 3. split windows
7465
      code = tsmaOptSplitWindows(&tsmaOptCtx, tsmaOptCtx.pTimeRange);
8,618✔
7466
      if (TSDB_CODE_SUCCESS == code && tsmaOptIsUsingTsmas(&tsmaOptCtx)) {
8,618!
7467
        // 4. create logic plan
7468
        code = tsmaOptGeneratePlan(&tsmaOptCtx);
7,574✔
7469

7470
        if (TSDB_CODE_SUCCESS == code) {
7,574!
7471
          for (int32_t i = 0; i < 2 && (TSDB_CODE_SUCCESS == code); i++) {
22,722!
7472
            SLogicSubplan* pSubplan = tsmaOptCtx.generatedSubPlans[i];
15,148✔
7473
            if (!pSubplan) continue;
15,148✔
7474
            pSubplan->subplanType = SUBPLAN_TYPE_SCAN;
6,206✔
7475
            code = nodesListMakeAppend(tsmaOptCtx.ppParentTsmaSubplans, (SNode*)pSubplan);
6,206✔
7476
          }
7477
          pCxt->optimized = true;
7,574✔
7478
        }
7479
      }
7480
    }
7481
  }
7482
  pScan->pTsmas = NULL;
10,443✔
7483
  clearTSMAOptCtx(&tsmaOptCtx);
10,443✔
7484
  return code;
10,443✔
7485
}
7486

7487
// clang-format off
7488
static const SOptimizeRule optimizeRuleSet[] = {
7489
  {.pName = "ScanPath",                   .optimizeFunc = scanPathOptimize},
7490
  {.pName = "PushDownCondition",          .optimizeFunc = pdcOptimize},
7491
  {.pName = "EliminateNotNullCond",       .optimizeFunc = eliminateNotNullCondOptimize},
7492
  {.pName = "JoinCondOptimize",           .optimizeFunc = joinCondOptimize},
7493
  {.pName = "HashJoin",                   .optimizeFunc = hashJoinOptimize},
7494
  {.pName = "StableJoin",                 .optimizeFunc = stableJoinOptimize},
7495
  {.pName = "GroupJoin",                  .optimizeFunc = groupJoinOptimize},
7496
  {.pName = "sortNonPriKeyOptimize",      .optimizeFunc = sortNonPriKeyOptimize},
7497
  {.pName = "SortPrimaryKey",             .optimizeFunc = sortPrimaryKeyOptimize},
7498
  {.pName = "SortForjoin",                .optimizeFunc = sortForJoinOptimize},
7499
  {.pName = "SmaIndex",                   .optimizeFunc = smaIndexOptimize},
7500
  {.pName = "PushDownLimit",              .optimizeFunc = pushDownLimitOptimize},
7501
  {.pName = "PartitionTags",              .optimizeFunc = partTagsOptimize},
7502
  {.pName = "MergeProjects",              .optimizeFunc = mergeProjectsOptimize},
7503
  {.pName = "RewriteTail",                .optimizeFunc = rewriteTailOptimize},
7504
  {.pName = "RewriteUnique",              .optimizeFunc = rewriteUniqueOptimize},
7505
  {.pName = "splitCacheLastFunc",         .optimizeFunc = splitCacheLastFuncOptimize},
7506
  {.pName = "LastRowScan",                .optimizeFunc = lastRowScanOptimize},
7507
  {.pName = "TagScan",                    .optimizeFunc = tagScanOptimize},
7508
  {.pName = "TableCountScan",             .optimizeFunc = tableCountScanOptimize},
7509
  {.pName = "EliminateProject",           .optimizeFunc = eliminateProjOptimize},
7510
  {.pName = "EliminateSetOperator",       .optimizeFunc = eliminateSetOpOptimize},
7511
  {.pName = "PartitionCols",              .optimizeFunc = partitionColsOpt},
7512
  {.pName = "Tsma",                       .optimizeFunc = tsmaOptimize},
7513
};
7514
// clang-format on
7515

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

7518
static int32_t dumpLogicSubplan(const char* pRuleName, SLogicSubplan* pSubplan) {
3,033,960✔
7519
  int32_t code = 0;
3,033,960✔
7520
  if (!tsQueryPlannerTrace) {
3,033,960!
7521
    return code;
3,033,964✔
7522
  }
7523
  char* pStr = NULL;
×
7524
  code = nodesNodeToString((SNode*)pSubplan, false, &pStr, NULL);
×
7525
  if (TSDB_CODE_SUCCESS == code) {
×
7526
    if (NULL == pRuleName) {
×
7527
      qDebugL("before optimize, JsonPlan: %s", pStr);
×
7528
    } else {
7529
      qDebugL("apply optimize %s rule, JsonPlan: %s", pRuleName, pStr);
×
7530
    }
7531
    taosMemoryFree(pStr);
×
7532
  }
7533
  return code;
×
7534
}
7535

7536
static int32_t applyOptimizeRule(SPlanContext* pCxt, SLogicSubplan* pLogicSubplan) {
761,029✔
7537
  SOptimizeContext cxt = {.pPlanCxt = pCxt, .optimized = false};
761,029✔
7538
  bool             optimized = false;
761,029✔
7539
  int32_t code = dumpLogicSubplan(NULL, pLogicSubplan);
761,029✔
7540
  if (TSDB_CODE_SUCCESS != code) {
761,033!
7541
    return code;
×
7542
  }
7543
  do {
7544
    optimized = false;
3,033,967✔
7545
    for (int32_t i = 0; i < optimizeRuleNum; ++i) {
35,482,993✔
7546
      cxt.optimized = false;
34,722,897✔
7547
      int32_t code = optimizeRuleSet[i].optimizeFunc(&cxt, pLogicSubplan);
34,722,897✔
7548
      if (TSDB_CODE_SUCCESS != code) {
34,722,855✔
7549
        return code;
896✔
7550
      }
7551
      if (cxt.optimized) {
34,721,959✔
7552
        optimized = true;
2,272,933✔
7553
        code = dumpLogicSubplan(optimizeRuleSet[i].pName, pLogicSubplan);
2,272,933✔
7554
        break;
2,272,934✔
7555
      }
7556
    }
7557
  } while (optimized && (TSDB_CODE_SUCCESS == code));
3,033,030!
7558
  return code;
760,096✔
7559
}
7560

7561
int32_t optimizeLogicPlan(SPlanContext* pCxt, SLogicSubplan* pLogicSubplan) {
2,457,647✔
7562
  if (SUBPLAN_TYPE_MODIFY == pLogicSubplan->subplanType && NULL == pLogicSubplan->pNode->pChildren) {
2,457,647✔
7563
    return TSDB_CODE_SUCCESS;
1,696,621✔
7564
  }
7565
  return applyOptimizeRule(pCxt, pLogicSubplan);
761,026✔
7566
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc