Coverage Report

Created: 2026-07-30 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tdengine/source/libs/planner/src/planSpliter.c
Line
Count
Source
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 "functionMgt.h"
17
#include "planInt.h"
18
#include "taoserror.h"
19
#include "tglobal.h"
20
21
0
#define SPLIT_FLAG_MASK(n) (1 << n)
22
23
0
#define SPLIT_FLAG_STABLE_SPLIT SPLIT_FLAG_MASK(0)
24
0
#define SPLIT_FLAG_INSERT_SPLIT SPLIT_FLAG_MASK(1)
25
26
0
#define SPLIT_FLAG_SET_MASK(val, mask)  (val) |= (mask)
27
0
#define SPLIT_FLAG_TEST_MASK(val, mask) (((val) & (mask)) != 0)
28
29
typedef struct SSplitContext {
30
  SPlanContext* pPlanCxt;
31
  uint64_t      queryId;
32
  int32_t       groupId;
33
  bool          split;
34
} SSplitContext;
35
36
typedef int32_t (*FSplit)(SSplitContext* pCxt, SLogicSubplan* pSubplan);
37
38
typedef struct SSplitRule {
39
  char*  pName;
40
  FSplit splitFunc;
41
} SSplitRule;
42
43
typedef struct SFindSplitNodeCtx {
44
  const SSplitContext* pSplitCtx;
45
  const SLogicSubplan* pSubplan;
46
} SFindSplitNodeCtx;
47
48
typedef bool (*FSplFindSplitNode)(SSplitContext* pCxt, SLogicSubplan* pSubplan, SLogicNode* pNode, void* pInfo);
49
50
0
static int32_t cloneVgroups(SVgroupsInfo **pDst, SVgroupsInfo* pSrc) {
51
0
  if (pSrc == NULL) {
52
0
    *pDst = NULL;
53
0
    return TSDB_CODE_SUCCESS;
54
0
  }
55
0
  int32_t len = VGROUPS_INFO_SIZE(pSrc);
56
0
  *pDst = taosMemoryMalloc(len);
57
0
  if (NULL == *pDst) {
58
0
    return terrno;
59
0
  }
60
0
  memcpy(*pDst, pSrc, len);
61
0
  return TSDB_CODE_SUCCESS;
62
0
}
63
64
static int32_t stbSplCreateMergeKeys(SNodeList* pSortKeys, SNodeList* pTargets, SNodeList** pOutput);
65
static int32_t stbSplCreateMergeKeysByExpr(SNode* pExpr, EOrder order, SNodeList** pMergeKeys);
66
67
0
static void splSetSubplanVgroups(SLogicSubplan* pSubplan, SLogicNode* pNode) {
68
0
  if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pNode)) {
69
0
    TSWAP(pSubplan->pVgroupList, ((SScanLogicNode*)pNode)->pVgroupList);
70
0
  } else if (QUERY_NODE_LOGIC_PLAN_VIRTUAL_TABLE_SCAN == nodeType(pNode)) {
71
    // do nothing, since virtual table scan node is SUBPLAN_TYPE_MERGE
72
0
  } else if (QUERY_NODE_LOGIC_PLAN_DYN_QUERY_CTRL == nodeType(pNode) && ((SDynQueryCtrlLogicNode *)pNode)->qType == DYN_QTYPE_VTB_SCAN) {
73
0
    TSWAP(pSubplan->pVgroupList, ((SDynQueryCtrlLogicNode*)pNode)->vtbScan.pVgroupList);
74
0
  } else {
75
0
    if (1 == LIST_LENGTH(pNode->pChildren)) {
76
0
      splSetSubplanVgroups(pSubplan, (SLogicNode*)nodesListGetNode(pNode->pChildren, 0));
77
0
    }
78
0
  }
79
0
}
80
81
0
static SLogicSubplan* splCreateScanSubplan(SSplitContext* pCxt, SLogicNode* pNode, int32_t flag) {
82
0
  SLogicSubplan* pSubplan = NULL;
83
0
  terrno = nodesMakeNode(QUERY_NODE_LOGIC_SUBPLAN, (SNode**)&pSubplan);
84
0
  if (NULL == pSubplan) {
85
0
    return NULL;
86
0
  }
87
0
  pSubplan->id.queryId = pCxt->queryId;
88
0
  pSubplan->id.groupId = pCxt->groupId;
89
  // TODO(smj):refact here.
90
0
  pSubplan->subplanType = nodeType(pNode) == QUERY_NODE_LOGIC_PLAN_VIRTUAL_TABLE_SCAN ? SUBPLAN_TYPE_MERGE : SUBPLAN_TYPE_SCAN;
91
0
  pSubplan->pNode = pNode;
92
0
  pSubplan->pNode->pParent = NULL;
93
0
  splSetSubplanVgroups(pSubplan, pNode);
94
0
  SPLIT_FLAG_SET_MASK(pSubplan->splitFlag, flag);
95
0
  return pSubplan;
96
0
}
97
98
0
static bool splHasScan(SLogicNode* pNode) {
99
0
  if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pNode)) {
100
0
    return true;
101
0
  }
102
103
0
  SNode* pChild = NULL;
104
0
  FOREACH(pChild, pNode->pChildren) {
105
0
    if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pChild)) {
106
0
      return true;
107
0
    }
108
0
    return splHasScan((SLogicNode*)pChild);
109
0
  }
110
111
0
  return false;
112
0
}
113
114
0
static void splSetSubplanType(SLogicSubplan* pSubplan) {
115
0
  pSubplan->subplanType = splHasScan(pSubplan->pNode) ? SUBPLAN_TYPE_SCAN : SUBPLAN_TYPE_MERGE;
116
0
}
117
118
0
static int32_t splCreateSubplan(SSplitContext* pCxt, SLogicNode* pNode, SLogicSubplan** ppSubplan) {
119
0
  SLogicSubplan* pSubplan = NULL;
120
0
  int32_t code = nodesMakeNode(QUERY_NODE_LOGIC_SUBPLAN, (SNode**)&pSubplan);
121
0
  if (NULL == pSubplan) {
122
0
    return code;
123
0
  }
124
0
  pSubplan->id.queryId = pCxt->queryId;
125
0
  pSubplan->id.groupId = pCxt->groupId;
126
0
  pSubplan->pNode = pNode;
127
0
  pNode->pParent = NULL;
128
0
  splSetSubplanType(pSubplan);
129
0
  *ppSubplan = pSubplan;
130
0
  return code;
131
0
}
132
133
0
static int32_t splCreateExchangeNode(SSplitContext* pCxt, SLogicNode* pChild, SExchangeLogicNode** pOutput) {
134
0
  SExchangeLogicNode* pExchange = NULL;
135
0
  int32_t code = TSDB_CODE_SUCCESS;
136
137
0
  PLAN_ERR_JRET(nodesMakeNode(QUERY_NODE_LOGIC_PLAN_EXCHANGE, (SNode**)&pExchange));
138
139
0
  pExchange->srcStartGroupId = pCxt->groupId;
140
0
  pExchange->srcEndGroupId = pCxt->groupId;
141
0
  pExchange->node.precision = pChild->precision;
142
0
  pExchange->node.dynamicOp = pChild->dynamicOp;
143
0
  pExchange->node.pTargets = NULL;
144
0
  PLAN_ERR_JRET(nodesCloneList(pChild->pTargets, &pExchange->node.pTargets));
145
146
0
  if (NULL != pChild->pLimit) {
147
0
    pExchange->node.pLimit = NULL;
148
0
    PLAN_ERR_JRET(nodesCloneNode(pChild->pLimit, &pExchange->node.pLimit));
149
0
    if (((SLimitNode*)pChild->pLimit)->limit && ((SLimitNode*)pChild->pLimit)->offset) {
150
0
      ((SLimitNode*)pChild->pLimit)->limit->datum.i += ((SLimitNode*)pChild->pLimit)->offset->datum.i;
151
0
    }
152
0
    if (((SLimitNode*)pChild->pLimit)->offset) {
153
0
      ((SLimitNode*)pChild->pLimit)->offset->datum.i = 0;
154
0
    }
155
0
  }
156
157
0
  *pOutput = pExchange;
158
159
0
  return code;
160
0
_return:
161
0
  planError("failed to create exchange node, code:%d", code);
162
0
  nodesDestroyNode((SNode*)pExchange);
163
0
  return code;
164
0
}
165
166
static int32_t splCreateExchangeNodeForSubplan(SSplitContext* pCxt, SLogicSubplan* pSubplan, SLogicNode* pSplitNode,
167
0
                                               ESubplanType subplanType, bool seqScan) {
168
0
  SExchangeLogicNode* pExchange = NULL;
169
0
  int32_t             code = TSDB_CODE_SUCCESS;
170
171
0
  PLAN_ERR_JRET(splCreateExchangeNode(pCxt, pSplitNode, &pExchange));
172
173
0
  pExchange->dynTbname = nodeType(pSplitNode) == QUERY_NODE_LOGIC_PLAN_SCAN ? ((SScanLogicNode*)pSplitNode)->phTbnameScan : false;
174
0
  pExchange->seqRecvData = seqScan;
175
176
0
  PLAN_ERR_JRET(replaceLogicNode(pSubplan, pSplitNode, (SLogicNode*)pExchange));
177
0
  pSubplan->subplanType = subplanType;
178
179
0
  return code;
180
181
0
_return:
182
0
  planError("failed to create exchange node for subplan, code:%d", code);
183
0
  nodesDestroyNode((SNode*)pExchange);
184
0
  return code;
185
0
}
186
187
0
static bool splIsChildSubplan(SLogicNode* pLogicNode, int32_t groupId) {
188
0
  if (QUERY_NODE_LOGIC_PLAN_EXCHANGE == nodeType(pLogicNode)) {
189
0
    return groupId >= ((SExchangeLogicNode*)pLogicNode)->srcStartGroupId &&
190
0
           groupId <= ((SExchangeLogicNode*)pLogicNode)->srcEndGroupId;
191
0
  }
192
193
0
  if (QUERY_NODE_LOGIC_PLAN_MERGE == nodeType(pLogicNode)) {
194
0
    return ((SMergeLogicNode*)pLogicNode)->srcGroupId <= groupId &&
195
0
           ((SMergeLogicNode*)pLogicNode)->srcEndGroupId >= groupId;
196
0
  }
197
198
0
  SNode* pChild;
199
0
  FOREACH(pChild, pLogicNode->pChildren) {
200
0
    bool isChild = splIsChildSubplan((SLogicNode*)pChild, groupId);
201
0
    if (isChild) {
202
0
      return isChild;
203
0
    }
204
0
  }
205
0
  return false;
206
0
}
207
208
0
static int32_t splMountSubplan(SLogicSubplan* pParent, SNodeList* pChildren) {
209
0
  SNode* pChild = NULL;
210
0
  WHERE_EACH(pChild, pChildren) {
211
0
    if (splIsChildSubplan(pParent->pNode, ((SLogicSubplan*)pChild)->id.groupId)) {
212
0
      int32_t code = nodesListMakeAppend(&pParent->pChildren, pChild);
213
0
      if (TSDB_CODE_SUCCESS == code) {
214
0
        REPLACE_NODE(NULL);
215
0
        ERASE_NODE(pChildren);
216
0
        continue;
217
0
      } else {
218
0
        return code;
219
0
      }
220
0
    }
221
0
    WHERE_NEXT;
222
0
  }
223
0
  return TSDB_CODE_SUCCESS;
224
0
}
225
226
static bool splMatchByNode(SSplitContext* pCxt, SLogicSubplan* pSubplan, SLogicNode* pNode, FSplFindSplitNode func,
227
0
                           void* pInfo) {
228
0
  if (!pNode->splitDone && func(pCxt, pSubplan, pNode, pInfo)) {
229
0
    return true;
230
0
  }
231
0
  SNode* pChild;
232
0
  FOREACH(pChild, pNode->pChildren) {
233
0
    if (splMatchByNode(pCxt, pSubplan, (SLogicNode*)pChild, func, pInfo)) {
234
0
      return true;
235
0
    }
236
0
  }
237
0
  return false;
238
0
}
239
240
0
static bool splMatch(SSplitContext* pCxt, SLogicSubplan* pSubplan, int32_t flag, FSplFindSplitNode func, void* pInfo) {
241
0
  if (!SPLIT_FLAG_TEST_MASK(pSubplan->splitFlag, flag)) {
242
0
    if (splMatchByNode(pCxt, pSubplan, pSubplan->pNode, func, pInfo)) {
243
0
      return true;
244
0
    }
245
0
  }
246
0
  SNode* pChild;
247
0
  FOREACH(pChild, pSubplan->pChildren) {
248
0
    if (splMatch(pCxt, (SLogicSubplan*)pChild, flag, func, pInfo)) {
249
0
      return true;
250
0
    }
251
0
  }
252
0
  return false;
253
0
}
254
255
0
static void splSetParent(SLogicNode* pNode) {
256
0
  SNode* pChild = NULL;
257
0
  FOREACH(pChild, pNode->pChildren) { ((SLogicNode*)pChild)->pParent = pNode; }
258
0
}
259
260
typedef struct SStableSplitInfo {
261
  SLogicNode*    pSplitNode;
262
  SLogicSubplan* pSubplan;
263
} SStableSplitInfo;
264
265
0
static bool stbSplHasGatherExecFunc(const SNodeList* pFuncs) {
266
0
  SNode* pFunc = NULL;
267
0
  FOREACH(pFunc, pFuncs) {
268
0
    if (!fmIsWindowPseudoColumnFunc(((SFunctionNode*)pFunc)->funcId) &&
269
0
        !fmIsDistExecFunc(((SFunctionNode*)pFunc)->funcId)) {
270
0
      return true;
271
0
    }
272
0
  }
273
0
  return false;
274
0
}
275
276
0
static bool stbSplIsMultiTbScan(SScanLogicNode* pScan) {
277
0
  return ((NULL != pScan->pVgroupList && pScan->pVgroupList->numOfVgroups > 1) || pScan->needSplit) &&
278
0
         pScan->placeholderType != SP_PARTITION_TBNAME &&
279
0
         pScan->placeholderType != SP_PARTITION_ROWS &&
280
0
         !pScan->phTbnameScan && !pScan->virtualStableScan;
281
0
}
282
283
0
static bool stbSplHasMultiTbScan(SLogicNode* pNode) {
284
0
  if (1 != LIST_LENGTH(pNode->pChildren)) {
285
0
    return false;
286
0
  }
287
0
  SNode* pChild = nodesListGetNode(pNode->pChildren, 0);
288
0
  if (QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pChild)) {
289
0
    if (1 != LIST_LENGTH(((SLogicNode*)pChild)->pChildren)) {
290
0
      return false;
291
0
    }
292
0
    pChild = nodesListGetNode(((SLogicNode*)pChild)->pChildren, 0);
293
0
  }
294
0
  if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pChild) && stbSplIsMultiTbScan((SScanLogicNode*)pChild)) {
295
0
    return true;
296
0
  }
297
298
0
  if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pChild)) {
299
0
    if (QUERY_NODE_LOGIC_PLAN_AGG == nodeType(pNode) || (QUERY_NODE_LOGIC_PLAN_WINDOW == nodeType(pNode) &&
300
0
                                                         ((SWindowLogicNode*)pNode)->winType == WINDOW_TYPE_INTERVAL)) {
301
0
      return ((SScanLogicNode*)pChild)->needSplit;
302
0
    }
303
0
  }
304
0
  if (QUERY_NODE_LOGIC_PLAN_WINDOW == nodeType(pChild) &&
305
0
      ((SWindowLogicNode*)pChild)->winType == WINDOW_TYPE_EXTERNAL) {
306
0
    return stbSplHasMultiTbScan((SLogicNode*)pChild);
307
0
  }
308
0
  return false;
309
0
}
310
311
0
static bool stbSplIsMultiTbScanChild(SLogicNode* pNode) {
312
0
  if (1 != LIST_LENGTH(pNode->pChildren)) {
313
0
    return false;
314
0
  }
315
0
  SNode* pChild = nodesListGetNode(pNode->pChildren, 0);
316
0
  return (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pChild) && stbSplIsMultiTbScan((SScanLogicNode*)pChild));
317
0
}
318
319
0
static bool stbSplNeedSplitWindow(SLogicNode* pNode) {
320
0
  SWindowLogicNode* pWindow = (SWindowLogicNode*)pNode;
321
0
  if (WINDOW_TYPE_INTERVAL == pWindow->winType) {
322
0
    return !stbSplHasGatherExecFunc(pWindow->pFuncs) && stbSplHasMultiTbScan(pNode);
323
0
  }
324
325
0
  if (WINDOW_TYPE_EXTERNAL == pWindow->winType) {
326
0
    return pWindow->pFuncs && !stbSplHasGatherExecFunc(pWindow->pFuncs) && stbSplHasMultiTbScan(pNode);
327
0
  }
328
329
0
  if (WINDOW_TYPE_SESSION == pWindow->winType || WINDOW_TYPE_STATE == pWindow->winType || WINDOW_TYPE_COUNT == pWindow->winType || WINDOW_TYPE_EVENT == pWindow->winType) {
330
0
    return stbSplHasMultiTbScan(pNode);
331
0
  }
332
333
0
  return false;
334
0
}
335
336
0
static bool stbSplNeedSplitJoin(SJoinLogicNode* pJoin) {
337
0
  if (pJoin->isSingleTableJoin || JOIN_ALGO_HASH == pJoin->joinAlgo) {
338
0
    return false;
339
0
  }
340
0
  SNode* pChild = NULL;
341
0
  FOREACH(pChild, pJoin->node.pChildren) {
342
0
    if (QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(pChild) && QUERY_NODE_LOGIC_PLAN_JOIN != nodeType(pChild)) {
343
0
      return false;
344
0
    }
345
0
  }
346
0
  return true;
347
0
}
348
349
0
static bool stbSplIsTableCountQuery(SLogicNode* pNode) {
350
0
  if (1 != LIST_LENGTH(pNode->pChildren)) {
351
0
    return false;
352
0
  }
353
0
  SNode* pChild = nodesListGetNode(pNode->pChildren, 0);
354
0
  if (QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pChild)) {
355
0
    if (1 != LIST_LENGTH(((SLogicNode*)pChild)->pChildren)) {
356
0
      return false;
357
0
    }
358
0
    pChild = nodesListGetNode(((SLogicNode*)pChild)->pChildren, 0);
359
0
  }
360
0
  return QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pChild) && SCAN_TYPE_TABLE_COUNT == ((SScanLogicNode*)pChild)->scanType;
361
0
}
362
363
0
static bool stbSplNeedSplit(SFindSplitNodeCtx* pCtx, SLogicNode* pNode) {
364
0
  switch (nodeType(pNode)) {
365
0
    case QUERY_NODE_LOGIC_PLAN_SCAN:
366
0
      return stbSplIsMultiTbScan((SScanLogicNode*)pNode);
367
0
    case QUERY_NODE_LOGIC_PLAN_JOIN:
368
0
      return stbSplNeedSplitJoin((SJoinLogicNode*)pNode);
369
0
    case QUERY_NODE_LOGIC_PLAN_PARTITION:
370
0
      return stbSplIsMultiTbScanChild(pNode);
371
0
    case QUERY_NODE_LOGIC_PLAN_AGG:
372
0
      return (!stbSplHasGatherExecFunc(((SAggLogicNode*)pNode)->pAggFuncs) ||
373
0
              isPartTableAgg((SAggLogicNode*)pNode)) &&
374
0
             (stbSplHasMultiTbScan(pNode) && !stbSplIsTableCountQuery(pNode));
375
0
    case QUERY_NODE_LOGIC_PLAN_WINDOW:
376
0
      return stbSplNeedSplitWindow(pNode);
377
0
    case QUERY_NODE_LOGIC_PLAN_SORT:
378
0
      if (1 == LIST_LENGTH(pNode->pChildren)) {
379
0
        SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pNode->pChildren, 0);
380
0
        if (QUERY_NODE_LOGIC_PLAN_WINDOW == nodeType(pChild) &&
381
0
            WINDOW_TYPE_EXTERNAL == ((SWindowLogicNode*)pChild)->winType &&
382
0
            !((SWindowLogicNode*)pChild)->calcWithPartition &&
383
0
            stbSplNeedSplitWindow(pChild)) {
384
0
          return false;
385
0
        }
386
0
      }
387
0
      return stbSplHasMultiTbScan(pNode);
388
389
0
    default:
390
0
      break;
391
0
  }
392
0
  return false;
393
0
}
394
395
static bool stbSplFindSplitNode(SSplitContext* pCxt, SLogicSubplan* pSubplan, SLogicNode* pNode,
396
0
                                SStableSplitInfo* pInfo) {
397
0
  SFindSplitNodeCtx ctx = {.pSplitCtx = pCxt, .pSubplan = pSubplan};
398
0
  if (stbSplNeedSplit(&ctx, pNode)) {
399
0
    pInfo->pSplitNode = pNode;
400
0
    pInfo->pSubplan = pSubplan;
401
0
    return true;
402
0
  }
403
0
  return false;
404
0
}
405
406
0
static int32_t stbSplRewriteFuns(const SNodeList* pFuncs, SNodeList** pPartialFuncs, SNodeList** pMidFuncs, SNodeList** pMergeFuncs) {
407
0
  SNode* pNode = NULL;
408
0
  FOREACH(pNode, pFuncs) {
409
0
    SFunctionNode* pPartFunc = NULL;
410
0
    SFunctionNode* pMidFunc = NULL;
411
0
    SFunctionNode* pMergeFunc = NULL;
412
0
    int32_t        code = TSDB_CODE_SUCCESS;
413
414
0
    if (nodeType(pNode) != QUERY_NODE_FUNCTION) {
415
0
      planError("%s failed, expect function node in function list, actual nodeType:%d", __FUNCTION__, nodeType(pNode));
416
0
      return TSDB_CODE_PLAN_INTERNAL_ERROR;
417
0
    } else {
418
0
      SFunctionNode* pFunc = (SFunctionNode*)pNode;
419
0
      if (fmIsWindowPseudoColumnFunc(pFunc->funcId) || fmIsPlaceHolderFunc(pFunc->funcId)) {
420
0
        code = nodesCloneNode(pNode, (SNode**)&pPartFunc);
421
0
        if (TSDB_CODE_SUCCESS == code) {
422
0
          code = nodesCloneNode(pNode, (SNode**)&pMergeFunc);
423
0
        }
424
0
        if (TSDB_CODE_SUCCESS == code && pMidFuncs != NULL) {
425
0
          code = nodesCloneNode(pNode, (SNode**)&pMidFunc);
426
0
          if (NULL == pMidFunc) {
427
0
            nodesDestroyNode((SNode*)pMidFunc);
428
0
          }
429
0
        }
430
0
      } else {
431
0
        code = fmGetDistMethod(pFunc, &pPartFunc, &pMidFunc, &pMergeFunc);
432
0
      }
433
0
    }
434
435
0
    if (TSDB_CODE_SUCCESS == code) {
436
0
      code = nodesListMakeStrictAppend(pPartialFuncs, (SNode*)pPartFunc);
437
0
    }
438
0
    if (TSDB_CODE_SUCCESS == code) {
439
0
      if (pMidFuncs != NULL) {
440
0
        code = nodesListMakeStrictAppend(pMidFuncs, (SNode*)pMidFunc);
441
0
      } else {
442
0
        nodesDestroyNode((SNode*)pMidFunc);
443
0
      }
444
0
    }
445
0
    if (TSDB_CODE_SUCCESS == code) {
446
0
      code = nodesListMakeStrictAppend(pMergeFuncs, (SNode*)pMergeFunc);
447
0
    }
448
0
    if (TSDB_CODE_SUCCESS != code) {
449
0
      nodesDestroyNode((SNode*)pPartFunc);
450
0
      nodesDestroyNode((SNode*)pMidFunc);
451
0
      nodesDestroyNode((SNode*)pMergeFunc);
452
0
      return code;
453
0
    }
454
0
  }
455
0
  return TSDB_CODE_SUCCESS;
456
0
}
457
458
0
static int32_t stbSplAppendWStart(SNodeList** pFuncs, int32_t* pIndex, uint8_t precision) {
459
0
  int32_t index = 0;
460
0
  SNode*  pFunc = NULL;
461
0
  FOREACH(pFunc, *pFuncs) {
462
0
    if (nodeType(pFunc) == QUERY_NODE_FUNCTION && FUNCTION_TYPE_WSTART == ((SFunctionNode*)pFunc)->funcType) {
463
0
      *pIndex = index;
464
0
      return TSDB_CODE_SUCCESS;
465
0
    }
466
0
    ++index;
467
0
  }
468
469
0
  SFunctionNode* pWStart = NULL;
470
0
  int32_t code = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&pWStart);
471
0
  if (NULL == pWStart) {
472
0
    return code;
473
0
  }
474
0
  tstrncpy(pWStart->functionName, "_wstart", TSDB_FUNC_NAME_LEN);
475
0
  int64_t pointer = (int64_t)pWStart;
476
0
  char name[TSDB_COL_NAME_LEN + TSDB_POINTER_PRINT_BYTES + TSDB_NAME_DELIMITER_LEN + 1] = {0};
477
0
  int32_t len = snprintf(name, sizeof(name) - 1, "%s.%" PRId64, pWStart->functionName, pointer);
478
0
  (void)taosHashBinary(name, len, sizeof(name));
479
0
  tstrncpy(pWStart->node.aliasName, name, TSDB_COL_NAME_LEN);
480
0
  pWStart->node.resType.precision = precision;
481
482
0
  code = fmGetFuncInfo(pWStart, NULL, 0);
483
0
  if (TSDB_CODE_SUCCESS == code) {
484
0
    code = nodesListMakeStrictAppend(pFuncs, (SNode*)pWStart);
485
0
  }
486
0
  if (TSDB_CODE_SUCCESS == code) {
487
0
    *pIndex = index;
488
0
  } else {
489
0
    nodesDestroyNode((SNode*)pWStart);
490
0
  }
491
0
  return code;
492
0
}
493
494
0
static int32_t stbSplAppendWEnd(SWindowLogicNode* pWin, int32_t* pIndex) {
495
0
  int32_t index = 0;
496
0
  SNode*  pFunc = NULL;
497
0
  FOREACH(pFunc, pWin->pFuncs) {
498
0
    if (FUNCTION_TYPE_WEND == ((SFunctionNode*)pFunc)->funcType) {
499
0
      *pIndex = index;
500
0
      return TSDB_CODE_SUCCESS;
501
0
    }
502
0
    ++index;
503
0
  }
504
0
505
0
  SFunctionNode* pWEnd = NULL;
506
0
  int32_t code = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&pWEnd);
507
0
  if (NULL == pWEnd) {
508
0
    return code;
509
0
  }
510
0
  tstrncpy(pWEnd->functionName, "_wend", TSDB_FUNC_NAME_LEN);
511
0
  int64_t pointer = (int64_t)pWEnd;
512
0
  char name[TSDB_COL_NAME_LEN + TSDB_POINTER_PRINT_BYTES + TSDB_NAME_DELIMITER_LEN + 1] = {0};
513
0
  int32_t len = snprintf(name, sizeof(name) - 1, "%s.%" PRId64, pWEnd->functionName, pointer);
514
0
  (void)taosHashBinary(name, len, sizeof(name));
515
0
  tstrncpy(pWEnd->node.aliasName, name, TSDB_COL_NAME_LEN);
516
0
517
0
  code = fmGetFuncInfo(pWEnd, NULL, 0);
518
0
  if (TSDB_CODE_SUCCESS == code) {
519
0
    code = nodesListStrictAppend(pWin->pFuncs, (SNode*)pWEnd);
520
0
  }
521
0
  *pIndex = index;
522
0
  if (TSDB_CODE_SUCCESS == code) {
523
0
    code = createColumnByRewriteExpr(nodesListGetNode(pWin->pFuncs, index), &pWin->node.pTargets);
524
0
  }
525
0
  return code;
526
0
}
527
528
0
static int32_t stbSplAppendPlaceHolder(SNodeList* pFuncs, int32_t* pIndex, uint8_t precision, ENodeType winType) {
529
0
  int32_t index = 0;
530
0
  SNode*  pFunc = NULL;
531
0
  FOREACH(pFunc, pFuncs) {
532
0
    if (FUNCTION_TYPE_TWSTART == ((SFunctionNode*)pFunc)->funcType ||
533
0
        FUNCTION_TYPE_TPREV_TS == ((SFunctionNode*)pFunc)->funcType ||
534
0
        FUNCTION_TYPE_TPREV_LOCALTIME == ((SFunctionNode*)pFunc)->funcType ||
535
0
        FUNCTION_TYPE_TIDLESTART == ((SFunctionNode*)pFunc)->funcType) {
536
0
      *pIndex = index;
537
0
      return TSDB_CODE_SUCCESS;
538
0
    }
539
0
    ++index;
540
0
  }
541
542
0
  int32_t        code = TSDB_CODE_SUCCESS;
543
0
  bool           needFreeExtra = false;
544
0
  SNode*         extraValue = NULL;
545
0
  SFunctionNode* pPlaceHolder = NULL;
546
547
0
  PLAN_ERR_JRET(nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&pPlaceHolder));
548
549
0
  switch(winType) {
550
0
    case QUERY_NODE_SLIDING_WINDOW:
551
0
      tstrncpy(pPlaceHolder->functionName, "_tprev_ts", TSDB_FUNC_NAME_LEN);
552
0
      break;
553
0
    case QUERY_NODE_INTERVAL_WINDOW:
554
0
    case QUERY_NODE_STATE_WINDOW:
555
0
    case QUERY_NODE_EVENT_WINDOW:
556
0
    case QUERY_NODE_SESSION_WINDOW:
557
0
    case QUERY_NODE_COUNT_WINDOW:
558
0
      tstrncpy(pPlaceHolder->functionName, "_twstart", TSDB_FUNC_NAME_LEN);
559
0
      break;
560
0
    case QUERY_NODE_PERIOD_WINDOW:
561
0
      tstrncpy(pPlaceHolder->functionName, "_tprev_localtime", TSDB_FUNC_NAME_LEN);
562
0
      break;
563
0
    default:
564
0
      break;
565
0
  }
566
567
0
  int64_t pointer = (int64_t)pPlaceHolder;
568
0
  char name[TSDB_COL_NAME_LEN + TSDB_POINTER_PRINT_BYTES + TSDB_NAME_DELIMITER_LEN + 1] = {0};
569
0
  int32_t len = snprintf(name, sizeof(name) - 1, "%s.%" PRId64, pPlaceHolder->functionName, pointer);
570
0
  (void)taosHashBinary(name, len, sizeof(name));
571
0
  tstrncpy(pPlaceHolder->node.aliasName, name, TSDB_COL_NAME_LEN);
572
0
  pPlaceHolder->node.resType.precision = precision;
573
574
0
  PLAN_ERR_JRET(fmGetFuncInfo(pPlaceHolder, NULL, 0));
575
0
  PLAN_ERR_RET(nodesMakeValueNodeFromTimestamp(0, &extraValue));
576
0
  needFreeExtra = true;
577
0
  ((SValueNode*)extraValue)->notReserved = true;
578
0
  PLAN_ERR_JRET(nodesListMakePushFront(&pPlaceHolder->pParameterList, extraValue));
579
0
  needFreeExtra = false;
580
0
  PLAN_ERR_JRET(nodesListStrictAppend(pFuncs, (SNode*)pPlaceHolder));
581
0
  *pIndex = index;
582
0
  return code;
583
0
_return:
584
0
  nodesDestroyNode((SNode*)pPlaceHolder);
585
0
  if (needFreeExtra) {
586
0
    nodesDestroyNode(extraValue);
587
0
  }
588
0
  return code;
589
0
}
590
591
static int32_t stbSplCreatePartWindowNode(SSplitContext* pCxt, SWindowLogicNode* pMergeWindow,
592
0
                                          SLogicNode** pPartWindow, SNodeList** pMergeKeys) {
593
0
  int32_t    code = TSDB_CODE_SUCCESS;
594
0
  SNodeList* pFunc = pMergeWindow->pFuncs;
595
0
  pMergeWindow->pFuncs = NULL;
596
0
  SNodeList* pTargets = pMergeWindow->node.pTargets;
597
0
  pMergeWindow->node.pTargets = NULL;
598
0
  SNodeList* pChildren = pMergeWindow->node.pChildren;
599
0
  pMergeWindow->node.pChildren = NULL;
600
0
  SNode* pConditions = pMergeWindow->node.pConditions;
601
0
  pMergeWindow->node.pConditions = NULL;
602
603
0
  SWindowLogicNode* pPartWin = NULL;
604
0
  PLAN_ERR_JRET(nodesCloneNode((SNode*)pMergeWindow, (SNode**)&pPartWin));
605
606
0
  pPartWin->node.groupAction = GROUP_ACTION_KEEP;
607
0
  pMergeWindow->node.pTargets = pTargets;
608
0
  pMergeWindow->node.pConditions = pConditions;
609
0
  pPartWin->node.pChildren = pChildren;
610
0
  splSetParent((SLogicNode*)pPartWin);
611
612
0
  int32_t index = -1;
613
0
  int32_t indexExt = -1;
614
0
  const SColumnNode* pMergeTspk = (const SColumnNode*)pMergeWindow->pTspk;
615
0
  PLAN_ERR_JRET(stbSplRewriteFuns(pFunc, &pPartWin->pFuncs, NULL, &pMergeWindow->pFuncs));
616
0
  if (inStreamCalcClause(pCxt->pPlanCxt)) {
617
    /**
618
      For stream calc query, we need the _twstart or _tprev_ts placeholder
619
      in the part window to merge part results together.
620
    */
621
0
    PLAN_ERR_JRET(stbSplAppendPlaceHolder(pPartWin->pFuncs, &indexExt,
622
0
                                          pMergeTspk->node.resType.precision,
623
0
                                          pCxt->pPlanCxt->streamCxt.triggerWinType));
624
0
  }
625
0
  if (pMergeWindow->winType == WINDOW_TYPE_EXTERNAL && !inStreamCalcClause(pCxt->pPlanCxt)) {
626
    /**
627
      For external window query, we still need an explicit _wstart placeholder
628
      on the partial window output so merged external-window aggregation can
629
      bind pTspk to window-start, instead of accidentally using the first
630
      aggregate output column (e.g. count/sum).
631
    */
632
0
    PLAN_ERR_JRET(stbSplAppendWStart(&pPartWin->pFuncs, &index,
633
0
                                     pMergeTspk->node.resType.precision));
634
0
  } else if (!pCxt->pPlanCxt->streamCxt.hasExtWindow) {
635
    /**
636
      If the query is not an external window query, we need the _wstart
637
      placeholder for the merged INTERVAL window to do aggregation.
638
    */
639
0
    PLAN_ERR_JRET(stbSplAppendWStart(&pPartWin->pFuncs, &index,
640
0
                                     pMergeTspk->node.resType.precision));
641
0
  }
642
0
  if (index < 0 && indexExt < 0) {
643
0
    planError("%s failed since no pkts placeholder set", __FUNCTION__);
644
0
    code = TSDB_CODE_INTERNAL_ERROR;
645
0
    PLAN_ERR_JRET(code);
646
0
  }
647
648
0
  PLAN_ERR_JRET(createColumnByRewriteExprs(pPartWin->pFuncs, &pPartWin->node.pTargets));
649
0
  nodesDestroyNode(pMergeWindow->pTspk);
650
0
  pMergeWindow->pTspk = NULL;
651
0
  if (NULL != pMergeKeys) {
652
    /**
653
      Both _twstart and _wstart placeholders should be used as merge keys
654
      for INTERVAL window.
655
    */
656
0
    if (indexExt >= 0) {
657
0
      PLAN_ERR_JRET(stbSplCreateMergeKeysByExpr(nodesListGetNode(pPartWin->node.pTargets, indexExt),
658
0
                                                pMergeWindow->node.outputTsOrder, pMergeKeys));
659
0
    }
660
0
    if (index >= 0) {
661
0
      PLAN_ERR_JRET(stbSplCreateMergeKeysByExpr(nodesListGetNode(pPartWin->node.pTargets, index),
662
0
                                                pMergeWindow->node.outputTsOrder, pMergeKeys));
663
0
    }
664
0
  }
665
666
0
  int32_t indexPkts = index >= 0 ? index: indexExt;
667
0
  PLAN_ERR_JRET(nodesCloneNode(nodesListGetNode(pPartWin->node.pTargets, indexPkts),
668
0
                               &pMergeWindow->pTspk));
669
670
0
  nodesDestroyList(pFunc);
671
0
  *pPartWindow = (SLogicNode*)pPartWin;
672
673
0
  return code;
674
0
_return:
675
0
  nodesDestroyNode((SNode*)pPartWin);
676
0
  return code;
677
0
}
678
679
0
static int32_t stbSplGetNumOfVgroups(SLogicNode* pNode) {
680
0
  if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pNode)) {
681
0
    return ((SScanLogicNode*)pNode)->pVgroupList->numOfVgroups;
682
0
  } else {
683
0
    if (1 == LIST_LENGTH(pNode->pChildren)) {
684
0
      return stbSplGetNumOfVgroups((SLogicNode*)nodesListGetNode(pNode->pChildren, 0));
685
0
    }
686
0
  }
687
0
  return 0;
688
0
}
689
690
0
static int32_t stbSplRewriteFromMergeNode(SMergeLogicNode* pMerge, SLogicNode* pNode) {
691
0
  int32_t code = TSDB_CODE_SUCCESS;
692
0
  pMerge->node.inputTsOrder = pNode->outputTsOrder;
693
0
  pMerge->node.outputTsOrder = pNode->outputTsOrder;
694
695
0
  switch (nodeType(pNode)) {
696
0
    case QUERY_NODE_LOGIC_PLAN_PROJECT: {
697
0
      SProjectLogicNode *pLogicNode = (SProjectLogicNode*)pNode;
698
0
      if (pLogicNode->ignoreGroupId && (pMerge->node.pLimit || pMerge->node.pSlimit)) {
699
0
        pMerge->ignoreGroupId = true;
700
0
        pLogicNode->ignoreGroupId = false;
701
0
      }
702
0
      break;
703
0
    }
704
0
    case QUERY_NODE_LOGIC_PLAN_WINDOW: {
705
0
      SWindowLogicNode* pWindow = (SWindowLogicNode*)pNode;
706
0
      if (pMerge->node.pLimit) {
707
0
        nodesDestroyNode(pMerge->node.pLimit);
708
0
        pMerge->node.pLimit = NULL;
709
0
      }
710
0
      if (pMerge->node.pSlimit) {
711
0
        nodesDestroyNode(pMerge->node.pSlimit);
712
0
        pMerge->node.pSlimit = NULL;
713
0
      }
714
0
      break;
715
0
    }
716
0
    case QUERY_NODE_LOGIC_PLAN_SORT: {
717
0
      SSortLogicNode* pSort = (SSortLogicNode*)pNode;
718
0
      if (pSort->calcGroupId) pMerge->inputWithGroupId = true;
719
0
      break;
720
0
    }
721
0
    default:
722
0
      break;
723
0
  }
724
725
0
  return code;
726
0
}
727
728
static int32_t stbSplCreateMergeNode(SSplitContext* pCxt, SLogicSubplan* pSubplan, SLogicNode* pSplitNode,
729
0
                                     SNodeList* pMergeKeys, SLogicNode* pPartChild, bool groupSort, bool needSort) {
730
0
  SMergeLogicNode* pMerge = NULL;
731
0
  int32_t code = nodesMakeNode(QUERY_NODE_LOGIC_PLAN_MERGE, (SNode**)&pMerge);
732
0
  if (NULL == pMerge) {
733
0
    return code;
734
0
  }
735
0
  pMerge->needSort = needSort;
736
0
  pMerge->numOfChannels = stbSplGetNumOfVgroups(pPartChild);
737
0
  pMerge->srcGroupId = pCxt->groupId;
738
0
  pMerge->srcEndGroupId = pCxt->groupId;
739
0
  pMerge->node.precision = pPartChild->precision;
740
0
  pMerge->node.dynamicOp = pSplitNode->dynamicOp;
741
0
  if (!pMerge->node.dynamicOp && NULL != pSplitNode->pParent) {
742
0
    pMerge->node.dynamicOp = pSplitNode->pParent->dynamicOp;
743
0
  }
744
0
  pMerge->pMergeKeys = pMergeKeys;
745
0
  pMerge->groupSort = groupSort;
746
0
  pMerge->numOfSubplans = 1;
747
748
0
  pMerge->pInputs = NULL;
749
0
  code = nodesCloneList(pPartChild->pTargets, &pMerge->pInputs);
750
0
  if (TSDB_CODE_SUCCESS == code) {
751
    // NULL != pSubplan means 'merge node' replaces 'split node'.
752
0
    if (NULL == pSubplan) {
753
0
      code = nodesCloneList(pPartChild->pTargets, &pMerge->node.pTargets);
754
0
    } else {
755
0
      code = nodesCloneList(pSplitNode->pTargets, &pMerge->node.pTargets);
756
0
    }
757
0
  }
758
0
  if (TSDB_CODE_SUCCESS == code && NULL != pSplitNode->pLimit) {
759
0
    pMerge->node.pLimit = NULL;
760
0
    code = nodesCloneNode(pSplitNode->pLimit, &pMerge->node.pLimit);
761
0
    if (((SLimitNode*)pSplitNode->pLimit)->limit && ((SLimitNode*)pSplitNode->pLimit)->offset) {
762
0
      ((SLimitNode*)pSplitNode->pLimit)->limit->datum.i += ((SLimitNode*)pSplitNode->pLimit)->offset->datum.i;
763
0
    }
764
0
    if (((SLimitNode*)pSplitNode->pLimit)->offset) {
765
0
      ((SLimitNode*)pSplitNode->pLimit)->offset->datum.i = 0;
766
0
    }
767
0
  }
768
0
  if (TSDB_CODE_SUCCESS == code) {
769
0
    code = stbSplRewriteFromMergeNode(pMerge, pSplitNode);
770
0
  }
771
0
  if (TSDB_CODE_SUCCESS == code) {
772
0
    if (NULL == pSubplan) {
773
0
      code = nodesListMakeAppend(&pSplitNode->pChildren, (SNode*)pMerge);
774
0
    } else {
775
0
      code = replaceLogicNode(pSubplan, pSplitNode, (SLogicNode*)pMerge);
776
0
    }
777
0
  }
778
0
  if (TSDB_CODE_SUCCESS != code) {
779
0
    nodesDestroyNode((SNode*)pMerge);
780
0
  }
781
0
  return code;
782
0
}
783
784
0
static int32_t stbSplCreateExchangeNode(SSplitContext* pCxt, SLogicNode* pParent, SLogicNode* pPartChild) {
785
0
  SExchangeLogicNode* pExchange = NULL;
786
0
  int32_t             code = splCreateExchangeNode(pCxt, pPartChild, &pExchange);
787
0
  if (TSDB_CODE_SUCCESS == code) {
788
0
    pExchange->node.pParent = pParent;
789
0
    code = nodesListMakeAppend(&pParent->pChildren, (SNode*)pExchange);
790
0
  }
791
0
  return code;
792
0
}
793
794
0
static int32_t stbSplCreateMergeKeysByExpr(SNode* pExpr, EOrder order, SNodeList** pMergeKeys) {
795
0
  SOrderByExprNode* pOrderByExpr = NULL;
796
0
  int32_t code = nodesMakeNode(QUERY_NODE_ORDER_BY_EXPR, (SNode**)&pOrderByExpr);
797
0
  if (NULL == pOrderByExpr) {
798
0
    return code;
799
0
  }
800
0
  pOrderByExpr->pExpr = NULL;
801
0
  code = nodesCloneNode(pExpr, &pOrderByExpr->pExpr);
802
0
  if (NULL == pOrderByExpr->pExpr) {
803
0
    nodesDestroyNode((SNode*)pOrderByExpr);
804
0
    return code;
805
0
  }
806
0
  pOrderByExpr->order = order;
807
0
  pOrderByExpr->nullOrder = (order == ORDER_ASC) ? NULL_ORDER_FIRST : NULL_ORDER_LAST;
808
0
  return nodesListMakeStrictAppend(pMergeKeys, (SNode*)pOrderByExpr);
809
0
}
810
811
0
static int32_t stbSplCreateMergeKeysByPrimaryKey(SNode* pPrimaryKey, EOrder order, SNodeList** pMergeKeys) {
812
0
  return stbSplCreateMergeKeysByExpr(pPrimaryKey, order, pMergeKeys);
813
0
}
814
815
0
static int32_t stbSplSplitIntervalForBatch(SSplitContext* pCxt, SStableSplitInfo* pInfo) {
816
0
  SWindowLogicNode* pWindow = (SWindowLogicNode*)pInfo->pSplitNode;
817
0
  if (pWindow->winType == WINDOW_TYPE_EXTERNAL) {
818
0
    if (!pWindow->pFuncs) {
819
      // only have projection in external window.
820
0
      return TSDB_CODE_SUCCESS;
821
0
    }
822
0
  }
823
0
  SLogicNode* pPartWindow = NULL;
824
0
  SNodeList*  pMergeKeys = NULL;
825
0
  int32_t     code = stbSplCreatePartWindowNode(pCxt, pWindow,
826
0
                                                &pPartWindow, &pMergeKeys);
827
0
  if (TSDB_CODE_SUCCESS == code) {
828
0
    ((SWindowLogicNode*)pPartWindow)->windowAlgo = ((SWindowLogicNode*)pInfo->pSplitNode)->winType == WINDOW_TYPE_INTERVAL ? INTERVAL_ALGO_HASH : EXTERNAL_ALGO_HASH;
829
0
    ((SWindowLogicNode*)pInfo->pSplitNode)->windowAlgo = ((SWindowLogicNode*)pInfo->pSplitNode)->winType == WINDOW_TYPE_INTERVAL ? INTERVAL_ALGO_MERGE : EXTERNAL_ALGO_MERGE;
830
0
    code = stbSplCreateMergeNode(pCxt, NULL, pInfo->pSplitNode, pMergeKeys, pPartWindow, true, true);
831
0
    if (TSDB_CODE_SUCCESS != code) {
832
0
      nodesDestroyList(pMergeKeys);
833
0
    }
834
0
  }
835
0
  SLogicSubplan* pSplitSubPlan = NULL;
836
0
  if (TSDB_CODE_SUCCESS == code) {
837
0
    pSplitSubPlan = splCreateScanSubplan(pCxt, pPartWindow, SPLIT_FLAG_STABLE_SPLIT);
838
0
    if (!pSplitSubPlan) code = terrno;
839
0
  }
840
0
  if (code == TSDB_CODE_SUCCESS) {
841
0
    SNode* pNode;
842
0
    SMergeLogicNode* pMerge = (SMergeLogicNode*)pInfo->pSplitNode->pChildren->pHead->pNode;
843
0
    SWindowLogicNode* pWindow = (SWindowLogicNode*)pInfo->pSplitNode;
844
0
    if (LIST_LENGTH(pWindow->pTsmaSubplans) > 0) {
845
0
      FOREACH(pNode, pWindow->pTsmaSubplans) {
846
0
        ++(pCxt->groupId);
847
0
        SLogicSubplan* pSubplan = (SLogicSubplan*)pNode;
848
0
        pSubplan->id.groupId = pCxt->groupId;
849
0
        pSubplan->id.queryId = pCxt->queryId;
850
        //pSubplan->splitFlag = SPLIT_FLAG_STABLE_SPLIT;
851
0
        splSetSubplanVgroups(pSubplan, pSubplan->pNode);
852
0
        code = stbSplCreatePartWindowNode(pCxt, (SWindowLogicNode*)pSubplan->pNode, &pPartWindow, NULL);
853
0
        if (TSDB_CODE_SUCCESS == code) {
854
0
          nodesDestroyNode((SNode*)pSubplan->pNode);
855
0
          pSubplan->pNode = pPartWindow;
856
0
        }
857
0
      }
858
0
      code = nodesListMakeStrictAppendList(&pInfo->pSubplan->pChildren, pWindow->pTsmaSubplans);
859
0
      pMerge->numOfSubplans = LIST_LENGTH(pInfo->pSubplan->pChildren) + 1;
860
0
    }
861
0
    pMerge->srcEndGroupId = pCxt->groupId;
862
0
  }
863
0
  if (code == TSDB_CODE_SUCCESS) {
864
0
    code = nodesListMakePushFront(&pInfo->pSubplan->pChildren, (SNode*)pSplitSubPlan);
865
0
  }
866
0
  pInfo->pSubplan->subplanType = SUBPLAN_TYPE_MERGE;
867
0
  ++(pCxt->groupId);
868
0
  return code;
869
0
}
870
871
0
static void stbSplSetTableMergeScan(SLogicNode* pNode) {
872
0
  if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pNode)) {
873
0
    SScanLogicNode* pScan = (SScanLogicNode*)pNode;
874
0
    pScan->scanType = SCAN_TYPE_TABLE_MERGE;
875
0
    pScan->filesetDelimited = true;
876
0
    if (NULL != pScan->pGroupTags) {
877
0
      pScan->groupSort = true;
878
0
    }
879
0
  } else {
880
0
    if (1 == LIST_LENGTH(pNode->pChildren)) {
881
0
      stbSplSetTableMergeScan((SLogicNode*)nodesListGetNode(pNode->pChildren, 0));
882
0
    }
883
0
  }
884
0
}
885
886
0
static int32_t stbSplSplitSessionOrStateForBatch(SSplitContext* pCxt, SStableSplitInfo* pInfo) {
887
0
  SLogicNode* pWindow = pInfo->pSplitNode;
888
0
  SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pWindow->pChildren, 0);
889
890
0
  SNodeList* pMergeKeys = NULL;
891
0
  int32_t    code = stbSplCreateMergeKeysByPrimaryKey(((SWindowLogicNode*)pWindow)->pTspk,
892
0
                                                      ((SWindowLogicNode*)pWindow)->node.inputTsOrder, &pMergeKeys);
893
894
0
  if (TSDB_CODE_SUCCESS == code) {
895
0
    code = stbSplCreateMergeNode(pCxt, pInfo->pSubplan, pChild, pMergeKeys, (SLogicNode*)pChild, true, true);
896
0
  }
897
898
0
  if (TSDB_CODE_SUCCESS == code) {
899
0
    code = nodesListMakeStrictAppend(&pInfo->pSubplan->pChildren,
900
0
                                     (SNode*)splCreateScanSubplan(pCxt, pChild, SPLIT_FLAG_STABLE_SPLIT));
901
0
  }
902
903
0
  if (TSDB_CODE_SUCCESS == code) {
904
0
    stbSplSetTableMergeScan(pChild);
905
0
    pInfo->pSubplan->subplanType = SUBPLAN_TYPE_MERGE;
906
    //SPLIT_FLAG_SET_MASK(pInfo->pSubplan->splitFlag, SPLIT_FLAG_STABLE_SPLIT);
907
0
    ++(pCxt->groupId);
908
0
  } else {
909
0
    nodesDestroyList(pMergeKeys);
910
0
  }
911
912
0
  return code;
913
0
}
914
915
0
static int32_t stbSplSplitWindowForCrossTable(SSplitContext* pCxt, SStableSplitInfo* pInfo) {
916
0
  SWindowLogicNode* pWin = (SWindowLogicNode*)pInfo->pSplitNode;
917
0
  SNode*            pChild = nodesListGetNode(pWin->node.pChildren, 0);
918
919
0
  if (pChild && nodeType(pChild) == QUERY_NODE_LOGIC_PLAN_WINDOW &&
920
0
      ((SWindowLogicNode*)pChild)->winType == WINDOW_TYPE_EXTERNAL) {
921
0
    ((SWindowLogicNode*)pChild)->needGroupSort = true;
922
0
  }
923
924
0
  if (pWin->winType == WINDOW_TYPE_EXTERNAL) {
925
0
    pWin->extWinSplit = true;
926
0
    pWin->needGroupSort = pWin->calcWithPartition;
927
0
  }
928
929
0
  switch (pWin->winType) {
930
0
    case WINDOW_TYPE_INTERVAL:
931
0
    case WINDOW_TYPE_EXTERNAL:
932
0
      return stbSplSplitIntervalForBatch(pCxt, pInfo);
933
0
    case WINDOW_TYPE_SESSION:
934
0
    case WINDOW_TYPE_STATE:
935
0
    case WINDOW_TYPE_EVENT:
936
0
    case WINDOW_TYPE_COUNT:
937
0
    case WINDOW_TYPE_ANOMALY:
938
0
      return stbSplSplitSessionOrStateForBatch(pCxt, pInfo);
939
0
    default:
940
0
      break;
941
0
  }
942
0
  return TSDB_CODE_PLAN_INTERNAL_ERROR;
943
0
}
944
945
0
static bool stbSplNeedSeqRecvData(SLogicNode* pNode) {
946
0
  if (NULL == pNode) {
947
0
    return false;
948
0
  }
949
950
0
  if (NULL != pNode->pLimit || NULL != pNode->pSlimit) {
951
0
    return true;
952
0
  }
953
0
  return stbSplNeedSeqRecvData(pNode->pParent);
954
0
}
955
956
0
static int32_t stbSplSplitWindowForPartTable(SSplitContext* pCxt, SStableSplitInfo* pInfo) {
957
0
  if (NULL != pInfo->pSplitNode->pParent && QUERY_NODE_LOGIC_PLAN_FILL == nodeType(pInfo->pSplitNode->pParent)) {
958
0
    pInfo->pSplitNode = pInfo->pSplitNode->pParent;
959
0
  }
960
0
  SExchangeLogicNode* pExchange = NULL;
961
0
  int32_t             code = splCreateExchangeNode(pCxt, pInfo->pSplitNode, &pExchange);
962
0
  if (TSDB_CODE_SUCCESS == code && pExchange) {
963
0
    code = replaceLogicNode(pInfo->pSubplan, pInfo->pSplitNode, (SLogicNode*)pExchange);
964
0
  }
965
0
  if (TSDB_CODE_SUCCESS == code && pExchange) {
966
0
    pExchange->seqRecvData = stbSplNeedSeqRecvData((SLogicNode*)pExchange);
967
0
    pExchange->dynTbname = false;
968
0
    code = nodesListMakeStrictAppend(&pInfo->pSubplan->pChildren,
969
0
                                     (SNode*)splCreateScanSubplan(pCxt, pInfo->pSplitNode, SPLIT_FLAG_STABLE_SPLIT));
970
0
  }
971
0
  pInfo->pSubplan->subplanType = SUBPLAN_TYPE_MERGE;
972
0
  ++(pCxt->groupId);
973
0
  return code;
974
0
}
975
976
0
static int32_t stbSplSplitWindowNode(SSplitContext* pCxt, SStableSplitInfo* pInfo) {
977
0
  if (isPartTableWinodw((SWindowLogicNode*)pInfo->pSplitNode) &&
978
0
      (LIST_LENGTH(((SWindowLogicNode*)pInfo->pSplitNode)->pTsmaSubplans) == 0)) {
979
0
    return stbSplSplitWindowForPartTable(pCxt, pInfo);
980
0
  } else {
981
0
    return stbSplSplitWindowForCrossTable(pCxt, pInfo);
982
0
  }
983
0
}
984
985
0
static int32_t stbSplCreatePartAggNode(SAggLogicNode* pMergeAgg, SLogicNode** pOutput) {
986
0
  SNodeList* pFunc = pMergeAgg->pAggFuncs;
987
0
  pMergeAgg->pAggFuncs = NULL;
988
0
  SNodeList* pGroupKeys = pMergeAgg->pGroupKeys;
989
0
  pMergeAgg->pGroupKeys = NULL;
990
0
  SNodeList* pTargets = pMergeAgg->node.pTargets;
991
0
  pMergeAgg->node.pTargets = NULL;
992
0
  SNodeList* pChildren = pMergeAgg->node.pChildren;
993
0
  pMergeAgg->node.pChildren = NULL;
994
0
  SNode* pConditions = pMergeAgg->node.pConditions;
995
0
  pMergeAgg->node.pConditions = NULL;
996
997
0
  SAggLogicNode* pPartAgg = NULL;
998
0
  int32_t        code = TSDB_CODE_SUCCESS;
999
0
  int32_t        lino = 0;
1000
1001
0
  PLAN_ERR_JRET(nodesCloneNode((SNode*)pMergeAgg, (SNode**)&pPartAgg));
1002
1003
0
  pPartAgg->node.groupAction = GROUP_ACTION_KEEP;
1004
1005
0
  if (NULL != pGroupKeys) {
1006
0
    pPartAgg->pGroupKeys = pGroupKeys;
1007
0
    PLAN_ERR_JRET(createColumnByRewriteExprs(pPartAgg->pGroupKeys, &pPartAgg->node.pTargets));
1008
0
    pMergeAgg->pGroupKeys = NULL;
1009
0
    PLAN_ERR_JRET(nodesCloneList(pPartAgg->node.pTargets, &pMergeAgg->pGroupKeys));
1010
0
  }
1011
1012
0
  pMergeAgg->node.pConditions = pConditions;
1013
0
  pMergeAgg->node.pTargets = pTargets;
1014
0
  pPartAgg->node.pChildren = pChildren;
1015
0
  splSetParent((SLogicNode*)pPartAgg);
1016
1017
0
  PLAN_ERR_JRET(stbSplRewriteFuns(pFunc, &pPartAgg->pAggFuncs, NULL, &pMergeAgg->pAggFuncs));
1018
1019
0
  PLAN_ERR_JRET(createColumnByRewriteExprs(pPartAgg->pAggFuncs, &pPartAgg->node.pTargets));
1020
1021
0
  nodesDestroyList(pFunc);
1022
1023
0
  *pOutput = (SLogicNode*)pPartAgg;
1024
1025
0
  return code;
1026
0
_return:
1027
0
  if (code) {
1028
0
    planError("%s failed at line %d, code: %d", __func__, lino, code);
1029
0
    nodesDestroyNode((SNode*)pPartAgg);
1030
0
  }
1031
0
  nodesDestroyList(pFunc);
1032
0
  return code;
1033
0
}
1034
1035
0
static int32_t stbSplSplitAggNodeForPartTable(SSplitContext* pCxt, SStableSplitInfo* pInfo) {
1036
0
  int32_t code = splCreateExchangeNodeForSubplan(pCxt, pInfo->pSubplan, pInfo->pSplitNode, SUBPLAN_TYPE_MERGE, false);
1037
0
  if (TSDB_CODE_SUCCESS == code) {
1038
0
    code = nodesListMakeStrictAppend(&pInfo->pSubplan->pChildren,
1039
0
                                     (SNode*)splCreateScanSubplan(pCxt, pInfo->pSplitNode, SPLIT_FLAG_STABLE_SPLIT));
1040
0
  }
1041
0
  ++(pCxt->groupId);
1042
0
  return code;
1043
0
}
1044
1045
1046
/**
1047
 * @brief For pipelined agg node, add a SortMergeNode to merge result from vnodes.
1048
 *        For agg + partition, results are sorted by group id, use group sort.
1049
 *        For agg + sort for group, results are sorted by partition keys, not group id, merges keys should be the same
1050
 *            as partition keys
1051
 */
1052
0
static int32_t stbSplAggNodeCreateMerge(SSplitContext* pCtx, SStableSplitInfo* pInfo, SLogicNode* pChildAgg) {
1053
0
  bool       groupSort = true;
1054
0
  SNodeList* pMergeKeys = NULL;
1055
0
  int32_t    code = TSDB_CODE_SUCCESS;
1056
0
  bool       sortForGroup = false;
1057
1058
0
  if (pChildAgg->pChildren->length != 1) return TSDB_CODE_TSC_INTERNAL_ERROR;
1059
1060
0
  SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pChildAgg->pChildren, 0);
1061
0
  if (nodeType(pChild) == QUERY_NODE_LOGIC_PLAN_SORT) {
1062
0
    SSortLogicNode* pSort = (SSortLogicNode*)pChild;
1063
0
    if (pSort->calcGroupId) {
1064
0
      SNode *node, *node2;
1065
0
      groupSort = false;
1066
0
      sortForGroup = true;
1067
0
      SNodeList* extraAggFuncs = NULL;
1068
0
      uint32_t   originalLen = LIST_LENGTH(pSort->node.pTargets), idx = 0;
1069
0
      code = stbSplCreateMergeKeys(pSort->pSortKeys, pSort->node.pTargets, &pMergeKeys);
1070
0
      if (TSDB_CODE_SUCCESS != code) return code;
1071
1072
      // Create group_key func for all sort keys.
1073
      // We only need newly added nodes in pSort.node.pTargets when stbSplCreateMergeKeys
1074
0
      FOREACH(node, pSort->node.pTargets) {
1075
0
        if (idx++ < originalLen) continue;
1076
0
        SFunctionNode* pGroupKeyFunc = createGroupKeyAggFunc((SColumnNode*)node);
1077
0
        if (!pGroupKeyFunc) {
1078
0
          code = terrno;
1079
0
          break;
1080
0
        }
1081
0
        code = nodesListMakeStrictAppend(&extraAggFuncs, (SNode*)pGroupKeyFunc);
1082
0
        if (code != TSDB_CODE_SUCCESS) {
1083
0
          nodesDestroyNode((SNode*)pGroupKeyFunc);
1084
0
        }
1085
0
      }
1086
1087
0
      if (TSDB_CODE_SUCCESS == code) {
1088
        // add these extra group_key funcs into targets
1089
0
        code = createColumnByRewriteExprs(extraAggFuncs, &pChildAgg->pTargets);
1090
0
      }
1091
0
      if (code == TSDB_CODE_SUCCESS) {
1092
0
        code = nodesListAppendList(((SAggLogicNode*)pChildAgg)->pAggFuncs, extraAggFuncs);
1093
0
        extraAggFuncs = NULL;
1094
0
      }
1095
1096
0
      if (code == TSDB_CODE_SUCCESS) {
1097
0
        FOREACH(node, pMergeKeys) {
1098
0
          SOrderByExprNode* pOrder = (SOrderByExprNode*)node;
1099
0
          SColumnNode*      pCol = (SColumnNode*)pOrder->pExpr;
1100
0
          FOREACH(node2, ((SAggLogicNode*)pChildAgg)->pAggFuncs) {
1101
0
            SFunctionNode* pFunc = (SFunctionNode*)node2;
1102
0
            if (0 != strcmp(pFunc->functionName, "_group_key")) continue;
1103
0
            SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0);
1104
0
            if (!nodesEqualNode(pParam, (SNode*)pCol)) continue;
1105
1106
            // use the colName of group_key func to make sure finding the right slot id for merge keys.
1107
0
            tstrncpy(pCol->colName, pFunc->node.aliasName, TSDB_COL_NAME_LEN);
1108
0
            tstrncpy(pCol->node.aliasName, pFunc->node.aliasName, TSDB_COL_NAME_LEN);
1109
0
            memset(pCol->tableAlias, 0, TSDB_TABLE_NAME_LEN);
1110
0
            break;
1111
0
          }
1112
0
        }
1113
0
      }
1114
0
      if (TSDB_CODE_SUCCESS != code) {
1115
0
        nodesDestroyList(pMergeKeys);
1116
0
        nodesDestroyList(extraAggFuncs);
1117
0
      }
1118
0
    }
1119
0
  }
1120
0
  if (TSDB_CODE_SUCCESS == code) {
1121
0
    code = stbSplCreateMergeNode(pCtx, NULL, pInfo->pSplitNode, pMergeKeys, pChildAgg, groupSort, true);
1122
0
  }
1123
0
  if (TSDB_CODE_SUCCESS == code && sortForGroup) {
1124
0
    SMergeLogicNode* pMerge =
1125
0
        (SMergeLogicNode*)nodesListGetNode(pInfo->pSplitNode->pChildren, LIST_LENGTH(pInfo->pSplitNode->pChildren) - 1);
1126
0
    pMerge->inputWithGroupId = true;
1127
0
  }
1128
0
  return code;
1129
0
}
1130
1131
0
static int32_t stbSplSplitAggNodeForCrossTableMulSubplan(SSplitContext* pCxt, SStableSplitInfo* pInfo) {
1132
0
  SLogicNode*      pPartAgg = NULL;
1133
0
  bool             hasExchange = false;
1134
0
  SMergeLogicNode* pMergeNode = NULL;
1135
0
  SLogicSubplan*   pFirstScanSubplan = NULL;
1136
0
  int32_t          code = stbSplCreatePartAggNode((SAggLogicNode*)pInfo->pSplitNode, &pPartAgg);
1137
1138
0
  if (TSDB_CODE_SUCCESS == code) {
1139
0
    if (pInfo->pSplitNode->forceCreateNonBlockingOptr) {
1140
0
      code = stbSplAggNodeCreateMerge(pCxt, pInfo, pPartAgg);
1141
0
    } else {
1142
0
      hasExchange = true;
1143
0
      code = stbSplCreateMergeNode(pCxt, NULL, pInfo->pSplitNode, NULL, pPartAgg, false, false);
1144
0
    }
1145
0
    pMergeNode =
1146
0
        (SMergeLogicNode*)nodesListGetNode(pInfo->pSplitNode->pChildren, LIST_LENGTH(pInfo->pSplitNode->pChildren) - 1);
1147
0
  } else {
1148
0
    nodesDestroyNode((SNode*)pPartAgg);
1149
0
  }
1150
1151
0
  if (code == TSDB_CODE_SUCCESS) {
1152
0
    pFirstScanSubplan = splCreateScanSubplan(pCxt, pPartAgg, SPLIT_FLAG_STABLE_SPLIT);
1153
0
    if (!pFirstScanSubplan) code = terrno;
1154
0
  }
1155
1156
0
  if (code == TSDB_CODE_SUCCESS) {
1157
0
    SNode* pNode;
1158
0
    SAggLogicNode* pAgg = (SAggLogicNode*)pInfo->pSplitNode;
1159
0
    if (LIST_LENGTH(pAgg->pTsmaSubplans) > 0) {
1160
0
      FOREACH(pNode, pAgg->pTsmaSubplans) {
1161
0
        ++(pCxt->groupId);
1162
0
        SLogicSubplan* pSubplan = (SLogicSubplan*)pNode;
1163
0
        pSubplan->id.groupId = pCxt->groupId;
1164
0
        pSubplan->id.queryId = pCxt->queryId;
1165
        //pSubplan->splitFlag = SPLIT_FLAG_STABLE_SPLIT;
1166
0
        splSetSubplanVgroups(pSubplan, pSubplan->pNode);
1167
0
        code = stbSplCreatePartAggNode((SAggLogicNode*)pSubplan->pNode, &pPartAgg);
1168
0
        if (code) break;
1169
0
        nodesDestroyNode((SNode*)pSubplan->pNode);
1170
0
        pSubplan->pNode = pPartAgg;
1171
0
      }
1172
0
      code = nodesListMakeStrictAppendList(&pInfo->pSubplan->pChildren, pAgg->pTsmaSubplans);
1173
0
      pMergeNode->numOfSubplans = LIST_LENGTH(pInfo->pSubplan->pChildren) + 1;
1174
0
    }
1175
0
    pMergeNode->srcEndGroupId = pCxt->groupId;
1176
0
  }
1177
1178
0
  if (code == TSDB_CODE_SUCCESS) {
1179
0
    code = nodesListMakeAppend(&pInfo->pSubplan->pChildren, (SNode*)pFirstScanSubplan);
1180
0
  }
1181
1182
0
  if (code && pFirstScanSubplan) {
1183
0
    nodesDestroyNode((SNode*)pFirstScanSubplan);
1184
0
  }
1185
1186
0
  pInfo->pSubplan->subplanType = SUBPLAN_TYPE_MERGE;
1187
0
  ++(pCxt->groupId);
1188
0
  return code;
1189
0
}
1190
1191
0
static int32_t stbSplSplitAggNodeForCrossTable(SSplitContext* pCxt, SStableSplitInfo* pInfo) {
1192
0
  SLogicNode* pPartAgg = NULL;
1193
0
  int32_t     code = stbSplCreatePartAggNode((SAggLogicNode*)pInfo->pSplitNode, &pPartAgg);
1194
0
  if (TSDB_CODE_SUCCESS == code) {
1195
    // if slimit was pushed down to agg, agg will be pipelined mode, add sort merge before parent agg
1196
0
    if (pInfo->pSplitNode->forceCreateNonBlockingOptr)
1197
0
      code = stbSplAggNodeCreateMerge(pCxt, pInfo, pPartAgg);
1198
0
    else {
1199
0
      code = stbSplCreateExchangeNode(pCxt, pInfo->pSplitNode, pPartAgg);
1200
0
    }
1201
0
  } else {
1202
0
    nodesDestroyNode((SNode*)pPartAgg);
1203
0
  }
1204
1205
0
  SLogicSubplan* pScanSubplan = NULL;
1206
0
  if (TSDB_CODE_SUCCESS == code) {
1207
0
    pScanSubplan = splCreateScanSubplan(pCxt, pPartAgg, SPLIT_FLAG_STABLE_SPLIT);
1208
0
    if (!pScanSubplan) code = terrno;
1209
0
  }
1210
1211
0
  if (code == TSDB_CODE_SUCCESS) {
1212
0
    code = nodesListMakeStrictAppend(&pInfo->pSubplan->pChildren, (SNode*)pScanSubplan);
1213
0
  }
1214
1215
0
  pInfo->pSubplan->subplanType = SUBPLAN_TYPE_MERGE;
1216
0
  ++(pCxt->groupId);
1217
0
  return code;
1218
0
}
1219
1220
0
static int32_t stbSplSplitAggNode(SSplitContext* pCxt, SStableSplitInfo* pInfo) {
1221
0
  if (LIST_LENGTH(((SAggLogicNode*)pInfo->pSplitNode)->pTsmaSubplans) > 0) {
1222
0
    return stbSplSplitAggNodeForCrossTableMulSubplan(pCxt, pInfo);
1223
0
  }
1224
0
  if (isPartTableAgg((SAggLogicNode*)pInfo->pSplitNode)) {
1225
0
    return stbSplSplitAggNodeForPartTable(pCxt, pInfo);
1226
0
  }
1227
0
  return stbSplSplitAggNodeForCrossTable(pCxt, pInfo);
1228
0
}
1229
1230
0
static int32_t stbSplCreateColumnNode(SExprNode* pExpr, SNode** ppNode) {
1231
0
  SColumnNode* pCol = NULL;
1232
0
  int32_t code = nodesMakeNode(QUERY_NODE_COLUMN, (SNode**)&pCol);
1233
0
  if (NULL == pCol) {
1234
0
    return code;
1235
0
  }
1236
0
  if (QUERY_NODE_COLUMN == nodeType(pExpr)) {
1237
0
    tstrncpy(pCol->dbName, ((SColumnNode*)pExpr)->dbName, TSDB_DB_NAME_LEN);
1238
0
    tstrncpy(pCol->tableName, ((SColumnNode*)pExpr)->tableName, TSDB_TABLE_NAME_LEN);
1239
0
    tstrncpy(pCol->tableAlias, ((SColumnNode*)pExpr)->tableAlias, TSDB_TABLE_NAME_LEN);
1240
0
    tstrncpy(pCol->colName, ((SColumnNode*)pExpr)->colName, TSDB_COL_NAME_LEN);
1241
0
  } else {
1242
0
    tstrncpy(pCol->colName, pExpr->aliasName, TSDB_COL_NAME_LEN);
1243
0
  }
1244
0
  tstrncpy(pCol->node.aliasName, pExpr->aliasName, TSDB_COL_NAME_LEN);
1245
0
  tstrncpy(pCol->node.userAlias, pExpr->userAlias, TSDB_COL_NAME_LEN);
1246
0
  pCol->node.resType = pExpr->resType;
1247
0
  *ppNode = (SNode*)pCol;
1248
0
  return code;
1249
0
}
1250
1251
0
static int32_t stbSplCreateOrderByExpr(SOrderByExprNode* pSortKey, SNode* pCol, SNode** ppNode) {
1252
0
  SOrderByExprNode* pOutput = NULL;
1253
0
  int32_t code = nodesMakeNode(QUERY_NODE_ORDER_BY_EXPR, (SNode**)&pOutput);
1254
0
  if (NULL == pOutput) {
1255
0
    return code;
1256
0
  }
1257
0
  pOutput->pExpr = NULL;
1258
0
  code = nodesCloneNode(pCol, &pOutput->pExpr);
1259
0
  if (NULL == pOutput->pExpr) {
1260
0
    nodesDestroyNode((SNode*)pOutput);
1261
0
    return code;
1262
0
  }
1263
0
  pOutput->order = pSortKey->order;
1264
0
  pOutput->nullOrder = pSortKey->nullOrder;
1265
0
  *ppNode = (SNode*)pOutput;
1266
0
  return code;
1267
0
}
1268
1269
0
static int32_t stbSplCreateMergeKeys(SNodeList* pSortKeys, SNodeList* pTargets, SNodeList** pOutput) {
1270
0
  int32_t    code = TSDB_CODE_SUCCESS;
1271
0
  SNodeList* pMergeKeys = NULL;
1272
0
  SNode*     pNode = NULL;
1273
0
  FOREACH(pNode, pSortKeys) {
1274
0
    SOrderByExprNode* pSortKey = (SOrderByExprNode*)pNode;
1275
0
    SExprNode*        pSortExpr = (SExprNode*)pSortKey->pExpr;
1276
0
    SNode*            pTarget = NULL;
1277
0
    bool              found = false;
1278
0
    FOREACH(pTarget, pTargets) {
1279
0
      if ((QUERY_NODE_COLUMN == nodeType(pSortExpr) && nodesEqualNode((SNode*)pSortExpr, pTarget)) || 
1280
0
          (0 == strcmp(pSortExpr->aliasName, ((SColumnNode*)pTarget)->colName))) {
1281
0
        SNode* pNew = NULL;
1282
0
        code = stbSplCreateOrderByExpr(pSortKey, pTarget, &pNew);
1283
0
        if (TSDB_CODE_SUCCESS == code) {
1284
0
          code = nodesListMakeStrictAppend(&pMergeKeys, pNew);
1285
0
        }
1286
0
        if (TSDB_CODE_SUCCESS != code) {
1287
0
          break;
1288
0
        }
1289
0
        found = true;
1290
0
      }
1291
0
    }
1292
0
    if (TSDB_CODE_SUCCESS == code && !found) {
1293
0
      SNode* pCol = NULL;
1294
0
      code = stbSplCreateColumnNode(pSortExpr, &pCol);
1295
0
      if (TSDB_CODE_SUCCESS == code) {
1296
0
        SNode* pNew = NULL;
1297
0
        code = stbSplCreateOrderByExpr(pSortKey, pCol, &pNew);
1298
0
        if (TSDB_CODE_SUCCESS == code) {
1299
0
          code = nodesListMakeStrictAppend(&pMergeKeys, pNew);
1300
0
        }
1301
0
      }
1302
0
      if (TSDB_CODE_SUCCESS == code) {
1303
0
        code = nodesListStrictAppend(pTargets, pCol);
1304
0
      } else {
1305
0
        nodesDestroyNode(pCol);
1306
0
      }
1307
0
    }
1308
0
    if (TSDB_CODE_SUCCESS != code) {
1309
0
      break;
1310
0
    }
1311
0
  }
1312
0
  if (TSDB_CODE_SUCCESS == code) {
1313
0
    *pOutput = pMergeKeys;
1314
0
  } else {
1315
0
    nodesDestroyList(pMergeKeys);
1316
0
  }
1317
0
  return code;
1318
0
}
1319
1320
static int32_t stbSplCreatePartSortNode(SSortLogicNode* pSort, SLogicNode** pOutputPartSort,
1321
0
                                        SNodeList** pOutputMergeKeys) {
1322
0
  SNodeList* pSortKeys = pSort->pSortKeys;
1323
0
  pSort->pSortKeys = NULL;
1324
0
  SNodeList* pChildren = pSort->node.pChildren;
1325
0
  pSort->node.pChildren = NULL;
1326
1327
0
  int32_t         code = TSDB_CODE_SUCCESS;
1328
0
  SSortLogicNode* pPartSort = NULL;
1329
0
  code = nodesCloneNode((SNode*)pSort, (SNode**)&pPartSort);
1330
1331
0
  SNodeList* pMergeKeys = NULL;
1332
0
  if (TSDB_CODE_SUCCESS == code) {
1333
0
    pPartSort->node.pChildren = pChildren;
1334
0
    splSetParent((SLogicNode*)pPartSort);
1335
0
    pPartSort->pSortKeys = pSortKeys;
1336
0
    pPartSort->groupSort = pSort->groupSort;
1337
0
    code = stbSplCreateMergeKeys(pPartSort->pSortKeys, pPartSort->node.pTargets, &pMergeKeys);
1338
0
  }
1339
1340
0
  if (TSDB_CODE_SUCCESS == code) {
1341
0
    *pOutputPartSort = (SLogicNode*)pPartSort;
1342
0
    *pOutputMergeKeys = pMergeKeys;
1343
0
  } else {
1344
0
    nodesDestroyNode((SNode*)pPartSort);
1345
0
    nodesDestroyList(pMergeKeys);
1346
0
  }
1347
1348
0
  return code;
1349
0
}
1350
1351
0
static void stbSplSetScanPartSort(SLogicNode* pNode) {
1352
0
  if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pNode)) {
1353
0
    SScanLogicNode* pScan = (SScanLogicNode*)pNode;
1354
0
    if (NULL != pScan->pGroupTags) {
1355
0
      pScan->groupSort = true;
1356
0
    }
1357
0
  } else {
1358
0
    if (1 == LIST_LENGTH(pNode->pChildren)) {
1359
0
      stbSplSetScanPartSort((SLogicNode*)nodesListGetNode(pNode->pChildren, 0));
1360
0
    }
1361
0
  }
1362
0
}
1363
1364
0
static int32_t stbSplSplitSortNode(SSplitContext* pCxt, SStableSplitInfo* pInfo) {
1365
0
  SLogicNode* pPartSort = NULL;
1366
0
  SNodeList*  pMergeKeys = NULL;
1367
0
  bool        groupSort = ((SSortLogicNode*)pInfo->pSplitNode)->groupSort;
1368
0
  int32_t     code = stbSplCreatePartSortNode((SSortLogicNode*)pInfo->pSplitNode, &pPartSort, &pMergeKeys);
1369
0
  if (TSDB_CODE_SUCCESS == code) {
1370
0
    code = stbSplCreateMergeNode(pCxt, pInfo->pSubplan, pInfo->pSplitNode, pMergeKeys, pPartSort, groupSort, true);
1371
0
  }
1372
0
  if (TSDB_CODE_SUCCESS == code) {
1373
0
    nodesDestroyNode((SNode*)pInfo->pSplitNode);
1374
0
    pInfo->pSplitNode = NULL;
1375
0
    if (groupSort) {
1376
0
      stbSplSetScanPartSort(pPartSort);
1377
0
    }
1378
0
    code = nodesListMakeStrictAppend(&pInfo->pSubplan->pChildren,
1379
0
                                     (SNode*)splCreateScanSubplan(pCxt, pPartSort, SPLIT_FLAG_STABLE_SPLIT));
1380
0
  }
1381
0
  pInfo->pSubplan->subplanType = SUBPLAN_TYPE_MERGE;
1382
0
  ++(pCxt->groupId);
1383
0
  return code;
1384
0
}
1385
1386
0
static int32_t stbSplGetSplitNodeForScan(SStableSplitInfo* pInfo, SLogicNode** pSplitNode) {
1387
0
  *pSplitNode = pInfo->pSplitNode;
1388
0
  if (NULL != pInfo->pSplitNode->pParent && 
1389
0
      QUERY_NODE_LOGIC_PLAN_PROJECT == nodeType(pInfo->pSplitNode->pParent) &&
1390
0
      NULL == pInfo->pSplitNode->pParent->pLimit && NULL == pInfo->pSplitNode->pParent->pSlimit && 
1391
0
      !((SProjectLogicNode*)pInfo->pSplitNode->pParent)->inputIgnoreGroup) {
1392
0
    *pSplitNode = pInfo->pSplitNode->pParent;
1393
0
    if (NULL != pInfo->pSplitNode->pLimit) {
1394
0
      (*pSplitNode)->pLimit = NULL;
1395
0
      int32_t code = nodesCloneNode(pInfo->pSplitNode->pLimit, &(*pSplitNode)->pLimit);
1396
0
      if (NULL == (*pSplitNode)->pLimit) {
1397
0
        return code;
1398
0
      }
1399
0
      if (((SLimitNode*)pInfo->pSplitNode->pLimit)->limit && ((SLimitNode*)pInfo->pSplitNode->pLimit)->offset) {
1400
0
        ((SLimitNode*)pInfo->pSplitNode->pLimit)->limit->datum.i += ((SLimitNode*)pInfo->pSplitNode->pLimit)->offset->datum.i;
1401
0
      }
1402
0
      if (((SLimitNode*)pInfo->pSplitNode->pLimit)->offset) {
1403
0
        ((SLimitNode*)pInfo->pSplitNode->pLimit)->offset->datum.i = 0;
1404
0
      }
1405
0
    }
1406
0
  }
1407
0
  return TSDB_CODE_SUCCESS;
1408
0
}
1409
1410
0
static int32_t stbSplSplitScanNodeWithoutPartTags(SSplitContext* pCxt, SStableSplitInfo* pInfo) {
1411
0
  SLogicNode* pSplitNode = NULL;
1412
0
  int32_t     code = stbSplGetSplitNodeForScan(pInfo, &pSplitNode);
1413
0
  if (TSDB_CODE_SUCCESS == code) {
1414
0
    code = splCreateExchangeNodeForSubplan(pCxt, pInfo->pSubplan, pSplitNode, pInfo->pSubplan->subplanType, false);
1415
0
  }
1416
0
  if (TSDB_CODE_SUCCESS == code) {
1417
0
    splSetSubplanType(pInfo->pSubplan);
1418
0
    code = nodesListMakeStrictAppend(&pInfo->pSubplan->pChildren,
1419
0
                                     (SNode*)splCreateScanSubplan(pCxt, pSplitNode, SPLIT_FLAG_STABLE_SPLIT));
1420
0
  }
1421
0
  ++(pCxt->groupId);
1422
0
  return code;
1423
0
}
1424
1425
0
static int32_t stbSplSplitScanNodeWithPartTags(SSplitContext* pCxt, SStableSplitInfo* pInfo) {
1426
0
  SLogicNode* pSplitNode = NULL;
1427
0
  int32_t     code = stbSplGetSplitNodeForScan(pInfo, &pSplitNode);
1428
0
  if (TSDB_CODE_SUCCESS == code) {
1429
0
    bool needSort = true;
1430
0
    if (QUERY_NODE_LOGIC_PLAN_PROJECT == nodeType(pSplitNode) && !pSplitNode->pLimit && !pSplitNode->pSlimit) {
1431
0
      needSort = !((SProjectLogicNode*)pSplitNode)->ignoreGroupId;
1432
0
    }
1433
0
    code = stbSplCreateMergeNode(pCxt, pInfo->pSubplan, pSplitNode, NULL, pSplitNode, needSort, needSort);
1434
0
  }
1435
0
  if (TSDB_CODE_SUCCESS == code) {
1436
0
    code = nodesListMakeStrictAppend(&pInfo->pSubplan->pChildren,
1437
0
                                     (SNode*)splCreateScanSubplan(pCxt, pSplitNode, SPLIT_FLAG_STABLE_SPLIT));
1438
0
  }
1439
0
  pInfo->pSubplan->subplanType = SUBPLAN_TYPE_MERGE;
1440
0
  ++(pCxt->groupId);
1441
0
  return code;
1442
0
}
1443
1444
0
static int32_t stbSplFindPrimaryKeyFromScan(SScanLogicNode* pScan, SNode** ppNode) {
1445
0
  bool   find = false;
1446
0
  SNode* pCol = NULL;
1447
0
  FOREACH(pCol, pScan->pScanCols) {
1448
0
    if (PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pCol)->colId) {
1449
0
      find = true;
1450
0
      break;
1451
0
    }
1452
0
  }
1453
0
  if (!find) {
1454
0
    *ppNode = NULL;
1455
0
    return TSDB_CODE_SUCCESS;
1456
0
  }
1457
0
  SNode* pTarget = NULL;
1458
0
  FOREACH(pTarget, pScan->node.pTargets) {
1459
0
    if (nodesEqualNode(pTarget, pCol)) {
1460
0
      *ppNode = pCol;
1461
0
      return TSDB_CODE_SUCCESS;
1462
0
    }
1463
0
  }
1464
0
  SNode* pNew = NULL;
1465
0
  int32_t code = nodesCloneNode(pCol, &pNew);
1466
0
  if (TSDB_CODE_SUCCESS == code) {
1467
0
    code = nodesListStrictAppend(pScan->node.pTargets, pNew);
1468
0
  }
1469
0
  if (TSDB_CODE_SUCCESS == code) {
1470
0
    *ppNode = pCol;
1471
0
  }
1472
0
  return code;
1473
0
}
1474
1475
0
static int32_t stbSplFindPkFromScan(SScanLogicNode* pScan, SNode** ppNode) {
1476
0
  int32_t code = 0;
1477
0
  bool   find = false;
1478
0
  SNode* pCol = NULL;
1479
0
  FOREACH(pCol, pScan->pScanCols) {
1480
0
    if (((SColumnNode*)pCol)->isPk) {
1481
0
      find = true;
1482
0
      break;
1483
0
    }
1484
0
  }
1485
0
  if (!find) {
1486
0
    *ppNode = NULL;
1487
0
    return code;
1488
0
  }
1489
0
  SNode* pTarget = NULL;
1490
0
  FOREACH(pTarget, pScan->node.pTargets) {
1491
0
    if (nodesEqualNode(pTarget, pCol)) {
1492
0
      *ppNode = pCol;
1493
0
      return code;
1494
0
    }
1495
0
  }
1496
0
  SNode* pNew = NULL;
1497
0
  code = nodesCloneNode(pCol, &pNew);
1498
0
  if (TSDB_CODE_SUCCESS == code) {
1499
0
    code = nodesListStrictAppend(pScan->node.pTargets, pNew);
1500
0
  }
1501
0
  if (TSDB_CODE_SUCCESS == code) {
1502
0
    *ppNode = pCol;
1503
0
  }
1504
0
  return code;
1505
0
}
1506
1507
static int32_t stbSplCreateMergeScanNode(SScanLogicNode* pScan, SLogicNode** pOutputMergeScan,
1508
0
                                         SNodeList** pOutputMergeKeys) {
1509
0
  SNodeList* pChildren = pScan->node.pChildren;
1510
0
  pScan->node.pChildren = NULL;
1511
1512
0
  int32_t         code = TSDB_CODE_SUCCESS;
1513
0
  SScanLogicNode* pMergeScan = NULL;
1514
0
  code = nodesCloneNode((SNode*)pScan, (SNode**)&pMergeScan);
1515
1516
0
  SNodeList* pMergeKeys = NULL;
1517
0
  if (TSDB_CODE_SUCCESS == code) {
1518
0
    pMergeScan->scanType = SCAN_TYPE_TABLE_MERGE;
1519
0
    pMergeScan->filesetDelimited = true;
1520
0
    pMergeScan->node.pChildren = pChildren;
1521
0
    splSetParent((SLogicNode*)pMergeScan);
1522
1523
0
    SNode* pTs = NULL;
1524
0
    code = stbSplFindPrimaryKeyFromScan(pMergeScan, &pTs);
1525
0
    if (TSDB_CODE_SUCCESS == code) {
1526
0
      code = stbSplCreateMergeKeysByPrimaryKey(pTs, pMergeScan->scanSeq[0] > 0 ? ORDER_ASC : ORDER_DESC, &pMergeKeys);
1527
0
    }
1528
0
    SNode* pPk = NULL;
1529
0
    if (TSDB_CODE_SUCCESS == code) {
1530
0
      code = stbSplFindPkFromScan(pMergeScan, &pPk);
1531
0
    }
1532
0
    if (TSDB_CODE_SUCCESS == code && NULL != pPk) {
1533
0
      code = stbSplCreateMergeKeysByExpr(pPk, pMergeScan->scanSeq[0] > 0 ? ORDER_ASC : ORDER_DESC, &pMergeKeys);
1534
0
    }
1535
0
  }
1536
1537
0
  if (TSDB_CODE_SUCCESS == code) {
1538
0
    *pOutputMergeScan = (SLogicNode*)pMergeScan;
1539
0
    *pOutputMergeKeys = pMergeKeys;
1540
0
  } else {
1541
0
    nodesDestroyNode((SNode*)pMergeScan);
1542
0
    nodesDestroyList(pMergeKeys);
1543
0
  }
1544
1545
0
  return code;
1546
0
}
1547
1548
static int32_t stbSplSplitMergeScanNode(SSplitContext* pCxt, SLogicSubplan* pSubplan, SScanLogicNode* pScan,
1549
0
                                        bool groupSort, SStableSplitInfo* pInfo) {
1550
0
  SLogicNode* pMergeScan = NULL;
1551
0
  SNodeList*  pMergeKeys = NULL;
1552
0
  int32_t     code = stbSplCreateMergeScanNode(pScan, &pMergeScan, &pMergeKeys);
1553
0
  if (TSDB_CODE_SUCCESS == code) {
1554
0
    if (NULL != pMergeScan->pLimit) {
1555
0
      if (((SLimitNode*)pMergeScan->pLimit)->limit && ((SLimitNode*)pMergeScan->pLimit)->offset) {
1556
0
        ((SLimitNode*)pMergeScan->pLimit)->limit->datum.i += ((SLimitNode*)pMergeScan->pLimit)->offset->datum.i;
1557
0
      }
1558
0
      if (((SLimitNode*)pMergeScan->pLimit)->offset) {
1559
0
        ((SLimitNode*)pMergeScan->pLimit)->offset->datum.i = 0;
1560
0
      }
1561
0
    }
1562
0
    code = stbSplCreateMergeNode(pCxt, pSubplan, (SLogicNode*)pScan, pMergeKeys, pMergeScan, groupSort, true);
1563
0
  }
1564
0
  if (TSDB_CODE_SUCCESS == code) {
1565
0
    if ((void*)pInfo->pSplitNode == (void*)pScan) {
1566
0
      pInfo->pSplitNode = NULL;
1567
0
    }
1568
0
    nodesDestroyNode((SNode*)pScan);
1569
0
    code = nodesListMakeStrictAppend(&pSubplan->pChildren,
1570
0
                                     (SNode*)splCreateScanSubplan(pCxt, pMergeScan, SPLIT_FLAG_STABLE_SPLIT));
1571
0
  }
1572
0
  ++(pCxt->groupId);
1573
0
  return code;
1574
0
}
1575
1576
0
static int32_t stbSplSplitScanNode(SSplitContext* pCxt, SStableSplitInfo* pInfo) {
1577
0
  SScanLogicNode* pScan = (SScanLogicNode*)pInfo->pSplitNode;
1578
0
  if (SCAN_TYPE_TABLE_MERGE == pScan->scanType) {
1579
0
    pInfo->pSubplan->subplanType = SUBPLAN_TYPE_MERGE;
1580
0
    return stbSplSplitMergeScanNode(pCxt, pInfo->pSubplan, pScan, true, pInfo);
1581
0
  }
1582
0
  if (NULL != pScan->pGroupTags) {
1583
0
    return stbSplSplitScanNodeWithPartTags(pCxt, pInfo);
1584
0
  }
1585
0
  return stbSplSplitScanNodeWithoutPartTags(pCxt, pInfo);
1586
0
}
1587
1588
0
static int32_t stbSplSplitJoinNodeImpl(SSplitContext* pCxt, SLogicSubplan* pSubplan, SJoinLogicNode* pJoin, SStableSplitInfo* pInfo) {
1589
0
  int32_t code = TSDB_CODE_SUCCESS;
1590
0
  SNode*  pChild = NULL;
1591
0
  FOREACH(pChild, pJoin->node.pChildren) {
1592
0
    if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pChild)) {
1593
      //if (pJoin->node.dynamicOp) {
1594
      //  code = TSDB_CODE_SUCCESS;
1595
      //} else {
1596
0
        code = stbSplSplitMergeScanNode(pCxt, pSubplan, (SScanLogicNode*)pChild, pJoin->grpJoin ? true : false, pInfo);
1597
      //}
1598
0
    } else if (QUERY_NODE_LOGIC_PLAN_JOIN == nodeType(pChild)) {
1599
0
      code = stbSplSplitJoinNodeImpl(pCxt, pSubplan, (SJoinLogicNode*)pChild, pInfo);
1600
0
    } else {
1601
0
      code = TSDB_CODE_PLAN_INTERNAL_ERROR;
1602
0
    }
1603
0
    if (TSDB_CODE_SUCCESS != code) {
1604
0
      break;
1605
0
    }
1606
0
  }
1607
0
  return code;
1608
0
}
1609
1610
0
static int32_t stbSplSplitJoinNode(SSplitContext* pCxt, SStableSplitInfo* pInfo) {
1611
0
  int32_t code = stbSplSplitJoinNodeImpl(pCxt, pInfo->pSubplan, (SJoinLogicNode*)pInfo->pSplitNode, pInfo);
1612
0
  if (TSDB_CODE_SUCCESS == code) {
1613
    //if (!pInfo->pSplitNode->dynamicOp) {
1614
0
      pInfo->pSubplan->subplanType = SUBPLAN_TYPE_MERGE;
1615
    //}
1616
    //SPLIT_FLAG_SET_MASK(pInfo->pSubplan->splitFlag, SPLIT_FLAG_STABLE_SPLIT);
1617
0
    pInfo->pSplitNode->splitDone = true;
1618
0
  }
1619
0
  return code;
1620
0
}
1621
1622
0
static int32_t stbSplCreateMergeKeysForPartitionNode(SLogicNode* pPart, SNodeList** pMergeKeys) {
1623
0
  SScanLogicNode* pScan = (SScanLogicNode*)nodesListGetNode(pPart->pChildren, 0);
1624
0
  SNode*          pPK = NULL;
1625
0
  SNode*          pPrimaryKey = NULL;
1626
0
  int32_t code = stbSplFindPrimaryKeyFromScan(pScan, &pPK);
1627
0
  if (TSDB_CODE_SUCCESS == code) {
1628
0
    code = nodesCloneNode(pPK, &pPrimaryKey);
1629
0
  }
1630
0
  if (NULL == pPrimaryKey) {
1631
0
    return code;
1632
0
  }
1633
0
  code = nodesListStrictAppend(pPart->pTargets, pPrimaryKey);
1634
0
  if (TSDB_CODE_SUCCESS == code) {
1635
0
    code = stbSplCreateMergeKeysByPrimaryKey(pPrimaryKey, pScan->scanSeq[0] > 0 ? ORDER_ASC : ORDER_DESC, pMergeKeys);
1636
0
  }
1637
0
  return code;
1638
0
}
1639
1640
0
static int32_t stbSplSplitPartitionNode(SSplitContext* pCxt, SStableSplitInfo* pInfo) {
1641
0
  int32_t    code = TSDB_CODE_SUCCESS;
1642
0
  SNodeList* pMergeKeys = NULL;
1643
0
  if (pInfo->pSplitNode->requireDataOrder >= DATA_ORDER_LEVEL_IN_GROUP) {
1644
0
    code = stbSplCreateMergeKeysForPartitionNode(pInfo->pSplitNode, &pMergeKeys);
1645
0
  }
1646
0
  if (TSDB_CODE_SUCCESS == code) {
1647
0
    code = stbSplCreateMergeNode(pCxt, pInfo->pSubplan, pInfo->pSplitNode, pMergeKeys, pInfo->pSplitNode, true, true);
1648
0
  }
1649
0
  if (TSDB_CODE_SUCCESS == code) {
1650
0
    code = nodesListMakeStrictAppend(&pInfo->pSubplan->pChildren,
1651
0
                                     (SNode*)splCreateScanSubplan(pCxt, pInfo->pSplitNode, SPLIT_FLAG_STABLE_SPLIT));
1652
0
  }
1653
0
  pInfo->pSubplan->subplanType = SUBPLAN_TYPE_MERGE;
1654
0
  ++(pCxt->groupId);
1655
0
  return code;
1656
0
}
1657
1658
0
static int32_t stableSplit(SSplitContext* pCxt, SLogicSubplan* pSubplan) {
1659
0
  if (pCxt->pPlanCxt->rSmaQuery) {
1660
0
    return TSDB_CODE_SUCCESS;
1661
0
  }
1662
1663
0
  SStableSplitInfo info = {0};
1664
0
  if (!splMatch(pCxt, pSubplan, SPLIT_FLAG_STABLE_SPLIT, (FSplFindSplitNode)stbSplFindSplitNode, &info)) {
1665
0
    return TSDB_CODE_SUCCESS;
1666
0
  }
1667
1668
0
  int32_t code = TSDB_CODE_SUCCESS;
1669
0
  switch (nodeType(info.pSplitNode)) {
1670
0
    case QUERY_NODE_LOGIC_PLAN_SCAN:
1671
0
      code = stbSplSplitScanNode(pCxt, &info);
1672
0
      break;
1673
0
    case QUERY_NODE_LOGIC_PLAN_JOIN:
1674
0
      code = stbSplSplitJoinNode(pCxt, &info);
1675
0
      break;
1676
0
    case QUERY_NODE_LOGIC_PLAN_PARTITION:
1677
0
      code = stbSplSplitPartitionNode(pCxt, &info);
1678
0
      break;
1679
0
    case QUERY_NODE_LOGIC_PLAN_AGG:
1680
0
      code = stbSplSplitAggNode(pCxt, &info);
1681
0
      break;
1682
0
    case QUERY_NODE_LOGIC_PLAN_WINDOW:
1683
0
      code = stbSplSplitWindowNode(pCxt, &info);
1684
0
      break;
1685
0
    case QUERY_NODE_LOGIC_PLAN_SORT:
1686
0
      code = stbSplSplitSortNode(pCxt, &info);
1687
0
      break;
1688
0
    default:
1689
0
      break;
1690
0
  }
1691
1692
0
  if (info.pSplitNode && !inStreamTriggerClause(pCxt->pPlanCxt) && !inStreamCalcClause(pCxt->pPlanCxt)) {
1693
0
    info.pSplitNode->splitDone = true;
1694
0
  }
1695
0
  pCxt->split = true;
1696
0
  return code;
1697
0
}
1698
1699
typedef struct SSigTbJoinSplitInfo {
1700
  SJoinLogicNode* pJoin;
1701
  SLogicNode*     pSplitNode;
1702
  SLogicSubplan*  pSubplan;
1703
} SSigTbJoinSplitInfo;
1704
1705
0
static bool sigTbJoinSplNeedSplit(SLogicNode* pNode) {
1706
0
  if (QUERY_NODE_LOGIC_PLAN_JOIN != nodeType(pNode)) {
1707
0
    return false;
1708
0
  }
1709
1710
0
  SJoinLogicNode* pJoin = (SJoinLogicNode*)pNode;
1711
0
  if (!pJoin->isSingleTableJoin) {
1712
0
    return false;
1713
0
  }
1714
0
  return QUERY_NODE_LOGIC_PLAN_EXCHANGE != nodeType(nodesListGetNode(pJoin->node.pChildren, 0)) &&
1715
0
         QUERY_NODE_LOGIC_PLAN_EXCHANGE != nodeType(nodesListGetNode(pJoin->node.pChildren, 1));
1716
0
}
1717
1718
static bool sigTbJoinSplFindSplitNode(SSplitContext* pCxt, SLogicSubplan* pSubplan, SLogicNode* pNode,
1719
0
                                      SSigTbJoinSplitInfo* pInfo) {
1720
0
  if (sigTbJoinSplNeedSplit(pNode)) {
1721
0
    pInfo->pJoin = (SJoinLogicNode*)pNode;
1722
0
    pInfo->pSplitNode = (SLogicNode*)nodesListGetNode(pNode->pChildren, 1);
1723
0
    pInfo->pSubplan = pSubplan;
1724
0
    return true;
1725
0
  }
1726
0
  return false;
1727
0
}
1728
1729
0
static int32_t singleTableJoinSplit(SSplitContext* pCxt, SLogicSubplan* pSubplan) {
1730
0
  SSigTbJoinSplitInfo info = {0};
1731
0
  if (!splMatch(pCxt, pSubplan, 0, (FSplFindSplitNode)sigTbJoinSplFindSplitNode, &info)) {
1732
0
    return TSDB_CODE_SUCCESS;
1733
0
  }
1734
0
  bool hasScan = checkScanLogicNode((SLogicNode*)nodesListGetNode(info.pJoin->node.pChildren, 0));
1735
0
  int32_t code = splCreateExchangeNodeForSubplan(pCxt, info.pSubplan, info.pSplitNode, hasScan ? SUBPLAN_TYPE_SCAN : SUBPLAN_TYPE_MERGE, false);
1736
0
  if (TSDB_CODE_SUCCESS == code) {
1737
0
    code = nodesListMakeStrictAppend(&info.pSubplan->pChildren, (SNode*)splCreateScanSubplan(pCxt, info.pSplitNode, 0));
1738
0
  }
1739
0
  ++(pCxt->groupId);
1740
0
  pCxt->split = true;
1741
0
  return code;
1742
0
}
1743
1744
0
static int32_t unionSplitSubplan(SSplitContext* pCxt, SLogicSubplan* pUnionSubplan, SLogicNode* pSplitNode) {
1745
0
  SNodeList* pSubplanChildren = pUnionSubplan->pChildren;
1746
0
  pUnionSubplan->pChildren = NULL;
1747
1748
0
  int32_t code = TSDB_CODE_SUCCESS;
1749
1750
0
  SNode* pChild = NULL;
1751
0
  FOREACH(pChild, pSplitNode->pChildren) {
1752
0
    SLogicSubplan* pNewSubplan = NULL;
1753
0
    code = splCreateSubplan(pCxt, (SLogicNode*)pChild, &pNewSubplan);
1754
0
    if (TSDB_CODE_SUCCESS == code) {
1755
0
      code = nodesListMakeStrictAppend(&pUnionSubplan->pChildren, (SNode*)pNewSubplan);
1756
0
    }
1757
0
    if (TSDB_CODE_SUCCESS == code) {
1758
0
      REPLACE_NODE(NULL);
1759
0
      code = splMountSubplan(pNewSubplan, pSubplanChildren);
1760
0
    }
1761
0
    if (TSDB_CODE_SUCCESS != code) {
1762
0
      break;
1763
0
    }
1764
0
    ++(pCxt->groupId);
1765
0
  }
1766
0
  if (TSDB_CODE_SUCCESS == code) {
1767
0
    if (NULL != pSubplanChildren) {
1768
0
      if (pSubplanChildren->length > 0) {
1769
0
        code = nodesListMakeStrictAppendList(&pUnionSubplan->pChildren, pSubplanChildren);
1770
0
      } else {
1771
0
        nodesDestroyList(pSubplanChildren);
1772
0
      }
1773
0
    }
1774
0
    NODES_DESTORY_LIST(pSplitNode->pChildren);
1775
0
  }
1776
0
  return code;
1777
0
}
1778
1779
typedef struct SUnionAllSplitInfo {
1780
  SProjectLogicNode* pProject;
1781
  SLogicSubplan*     pSubplan;
1782
} SUnionAllSplitInfo;
1783
1784
static bool unAllSplFindSplitNode(SSplitContext* pCxt, SLogicSubplan* pSubplan, SLogicNode* pNode,
1785
0
                                  SUnionAllSplitInfo* pInfo) {
1786
0
  if (QUERY_NODE_LOGIC_PLAN_PROJECT == nodeType(pNode) && LIST_LENGTH(pNode->pChildren) > 1) {
1787
0
    pInfo->pProject = (SProjectLogicNode*)pNode;
1788
0
    pInfo->pSubplan = pSubplan;
1789
0
    return true;
1790
0
  }
1791
0
  return false;
1792
0
}
1793
1794
static int32_t unAllSplCreateExchangeNode(SSplitContext* pCxt, int32_t startGroupId, SLogicSubplan* pSubplan,
1795
0
                                          SProjectLogicNode* pProject) {
1796
0
  SExchangeLogicNode* pExchange = NULL;
1797
0
  int32_t code = nodesMakeNode(QUERY_NODE_LOGIC_PLAN_EXCHANGE, (SNode**)&pExchange);
1798
0
  if (NULL == pExchange) {
1799
0
    return code;
1800
0
  }
1801
0
  pExchange->srcStartGroupId = startGroupId;
1802
0
  pExchange->srcEndGroupId = pCxt->groupId - 1;
1803
0
  pExchange->node.precision = pProject->node.precision;
1804
0
  pExchange->node.pTargets = NULL;
1805
0
  code = nodesCloneList(pProject->node.pTargets, &pExchange->node.pTargets);
1806
0
  if (TSDB_CODE_SUCCESS != code) {
1807
0
    nodesDestroyNode((SNode*)pExchange);
1808
0
    return code;
1809
0
  }
1810
0
  pExchange->node.pConditions = NULL;
1811
0
  code = nodesCloneNode(pProject->node.pConditions, &pExchange->node.pConditions);
1812
0
  if (TSDB_CODE_SUCCESS != code) {
1813
0
    nodesDestroyNode((SNode*)pExchange);
1814
0
    return code;
1815
0
  }
1816
0
  TSWAP(pExchange->node.pLimit, pProject->node.pLimit);
1817
1818
0
  pSubplan->subplanType = SUBPLAN_TYPE_MERGE;
1819
1820
0
  if (NULL == pProject->node.pParent) {
1821
0
    pSubplan->pNode = (SLogicNode*)pExchange;
1822
0
    nodesDestroyNode((SNode*)pProject);
1823
0
    return TSDB_CODE_SUCCESS;
1824
0
  }
1825
1826
0
  SNode* pNode;
1827
0
  FOREACH(pNode, pProject->node.pParent->pChildren) {
1828
0
    if (nodesEqualNode(pNode, (SNode*)pProject)) {
1829
0
      REPLACE_NODE(pExchange);
1830
0
      nodesDestroyNode(pNode);
1831
0
      return TSDB_CODE_SUCCESS;
1832
0
    }
1833
0
  }
1834
0
  nodesDestroyNode((SNode*)pExchange);
1835
0
  return TSDB_CODE_PLAN_INTERNAL_ERROR;
1836
0
}
1837
1838
0
static int32_t unionAllSplit(SSplitContext* pCxt, SLogicSubplan* pSubplan) {
1839
0
  SUnionAllSplitInfo info = {0};
1840
0
  if (!splMatch(pCxt, pSubplan, 0, (FSplFindSplitNode)unAllSplFindSplitNode, &info)) {
1841
0
    return TSDB_CODE_SUCCESS;
1842
0
  }
1843
1844
0
  int32_t startGroupId = pCxt->groupId;
1845
0
  int32_t code = unionSplitSubplan(pCxt, info.pSubplan, (SLogicNode*)info.pProject);
1846
0
  if (TSDB_CODE_SUCCESS == code) {
1847
0
    code = unAllSplCreateExchangeNode(pCxt, startGroupId, info.pSubplan, info.pProject);
1848
0
  }
1849
0
  pCxt->split = true;
1850
0
  return code;
1851
0
}
1852
1853
typedef struct SUnionDistinctSplitInfo {
1854
  SAggLogicNode* pAgg;
1855
  SLogicSubplan* pSubplan;
1856
} SUnionDistinctSplitInfo;
1857
1858
static int32_t unDistSplCreateExchangeNode(SSplitContext* pCxt, int32_t startGroupId, SLogicSubplan* pSubplan,
1859
0
                                           SAggLogicNode* pAgg) {
1860
0
  SExchangeLogicNode* pExchange = NULL;
1861
0
  int32_t code = nodesMakeNode(QUERY_NODE_LOGIC_PLAN_EXCHANGE, (SNode**)&pExchange);
1862
0
  if (NULL == pExchange) {
1863
0
    return code;
1864
0
  }
1865
0
  pExchange->srcStartGroupId = startGroupId;
1866
0
  pExchange->srcEndGroupId = pCxt->groupId - 1;
1867
0
  pExchange->node.precision = pAgg->node.precision;
1868
0
  pExchange->node.pTargets = NULL;
1869
0
  code = nodesCloneList(pAgg->pGroupKeys, &pExchange->node.pTargets);
1870
0
  if (NULL == pExchange->node.pTargets) {
1871
0
    nodesDestroyNode((SNode*)pExchange);
1872
0
    return code;
1873
0
  }
1874
1875
0
  pSubplan->subplanType = SUBPLAN_TYPE_MERGE;
1876
1877
0
  return nodesListMakeStrictAppend(&pAgg->node.pChildren, (SNode*)pExchange);
1878
0
}
1879
1880
static bool unDistSplFindSplitNode(SSplitContext* pCxt, SLogicSubplan* pSubplan, SLogicNode* pNode,
1881
0
                                   SUnionDistinctSplitInfo* pInfo) {
1882
0
  if (QUERY_NODE_LOGIC_PLAN_AGG == nodeType(pNode) && LIST_LENGTH(pNode->pChildren) > 1) {
1883
0
    pInfo->pAgg = (SAggLogicNode*)pNode;
1884
0
    if (!pInfo->pAgg->pGroupKeys) return false;
1885
0
    pInfo->pSubplan = pSubplan;
1886
0
    return true;
1887
0
  }
1888
0
  return false;
1889
0
}
1890
1891
0
static int32_t unionDistinctSplit(SSplitContext* pCxt, SLogicSubplan* pSubplan) {
1892
0
  SUnionDistinctSplitInfo info = {0};
1893
0
  if (!splMatch(pCxt, pSubplan, 0, (FSplFindSplitNode)unDistSplFindSplitNode, &info)) {
1894
0
    return TSDB_CODE_SUCCESS;
1895
0
  }
1896
1897
0
  int32_t startGroupId = pCxt->groupId;
1898
0
  int32_t code = unionSplitSubplan(pCxt, info.pSubplan, (SLogicNode*)info.pAgg);
1899
0
  if (TSDB_CODE_SUCCESS == code) {
1900
0
    code = unDistSplCreateExchangeNode(pCxt, startGroupId, info.pSubplan, info.pAgg);
1901
0
  }
1902
0
  pCxt->split = true;
1903
0
  return code;
1904
0
}
1905
1906
typedef struct SSmaIndexSplitInfo {
1907
  SMergeLogicNode* pMerge;
1908
  SLogicSubplan*   pSubplan;
1909
} SSmaIndexSplitInfo;
1910
1911
static bool smaIdxSplFindSplitNode(SSplitContext* pCxt, SLogicSubplan* pSubplan, SLogicNode* pNode,
1912
0
                                   SSmaIndexSplitInfo* pInfo) {
1913
0
  if (QUERY_NODE_LOGIC_PLAN_MERGE == nodeType(pNode) && LIST_LENGTH(pNode->pChildren) > 1) {
1914
0
    if (((SMergeLogicNode*)pNode)->node.dynamicOp) {
1915
0
      return false;
1916
0
    }
1917
0
    int32_t nodeType = nodeType(nodesListGetNode(pNode->pChildren, 0));
1918
0
    if (nodeType == QUERY_NODE_LOGIC_PLAN_EXCHANGE || nodeType == QUERY_NODE_LOGIC_PLAN_MERGE) {
1919
0
      pInfo->pMerge = (SMergeLogicNode*)pNode;
1920
0
      pInfo->pSubplan = pSubplan;
1921
0
      return true;
1922
0
    }
1923
0
  }
1924
0
  return false;
1925
0
}
1926
1927
0
static int32_t smaIndexSplit(SSplitContext* pCxt, SLogicSubplan* pSubplan) {
1928
0
  SSmaIndexSplitInfo info = {0};
1929
0
  if (!splMatch(pCxt, pSubplan, 0, (FSplFindSplitNode)smaIdxSplFindSplitNode, &info)) {
1930
0
    return TSDB_CODE_SUCCESS;
1931
0
  }
1932
1933
0
  int32_t code = unionSplitSubplan(pCxt, info.pSubplan, (SLogicNode*)info.pMerge);
1934
0
  if (TSDB_CODE_SUCCESS == code) {
1935
0
    info.pMerge->srcGroupId = pCxt->groupId;
1936
0
  }
1937
0
  ++(pCxt->groupId);
1938
0
  pCxt->split = true;
1939
0
  return code;
1940
0
}
1941
1942
typedef struct SInsertSelectSplitInfo {
1943
  SLogicNode*    pQueryRoot;
1944
  SLogicSubplan* pSubplan;
1945
} SInsertSelectSplitInfo;
1946
1947
static bool insSelSplFindSplitNode(SSplitContext* pCxt, SLogicSubplan* pSubplan, SLogicNode* pNode,
1948
0
                                   SInsertSelectSplitInfo* pInfo) {
1949
0
  if (QUERY_NODE_LOGIC_PLAN_VNODE_MODIFY == nodeType(pNode) && 1 == LIST_LENGTH(pNode->pChildren) &&
1950
0
      MODIFY_TABLE_TYPE_INSERT == ((SVnodeModifyLogicNode*)pNode)->modifyType) {
1951
0
    pInfo->pQueryRoot = (SLogicNode*)nodesListGetNode(pNode->pChildren, 0);
1952
0
    pInfo->pSubplan = pSubplan;
1953
0
    return true;
1954
0
  }
1955
0
  return false;
1956
0
}
1957
1958
0
static int32_t insertSelectSplit(SSplitContext* pCxt, SLogicSubplan* pSubplan) {
1959
0
  SInsertSelectSplitInfo info = {0};
1960
0
  if (!splMatch(pCxt, pSubplan, SPLIT_FLAG_INSERT_SPLIT, (FSplFindSplitNode)insSelSplFindSplitNode, &info)) {
1961
0
    return TSDB_CODE_SUCCESS;
1962
0
  }
1963
1964
0
  SLogicSubplan* pNewSubplan = NULL;
1965
0
  SNodeList*     pSubplanChildren = info.pSubplan->pChildren;
1966
0
  int32_t        code = splCreateExchangeNodeForSubplan(pCxt, info.pSubplan, info.pQueryRoot, SUBPLAN_TYPE_MODIFY, false);
1967
0
  if (TSDB_CODE_SUCCESS == code) {
1968
0
    code = splCreateSubplan(pCxt, info.pQueryRoot, &pNewSubplan);
1969
0
  }
1970
0
  if (TSDB_CODE_SUCCESS == code) {
1971
0
    code = nodesListMakeStrictAppend(&info.pSubplan->pChildren, (SNode*)pNewSubplan);
1972
0
  }
1973
0
  if (TSDB_CODE_SUCCESS == code) {
1974
0
    code = splMountSubplan(pNewSubplan, pSubplanChildren);
1975
0
  }
1976
1977
0
  SPLIT_FLAG_SET_MASK(info.pSubplan->splitFlag, SPLIT_FLAG_INSERT_SPLIT);
1978
0
  ++(pCxt->groupId);
1979
0
  pCxt->split = true;
1980
0
  return code;
1981
0
}
1982
1983
typedef struct SVirtualTableSplitInfo {
1984
  SVirtualScanLogicNode *pVirtual;
1985
  SLogicSubplan          *pSubplan;
1986
} SVirtualTableSplitInfo;
1987
1988
static bool virtualTableFindSplitNode(SSplitContext* pCxt, SLogicSubplan* pSubplan, SLogicNode* pNode,
1989
0
                                      SVirtualTableSplitInfo* pInfo) {
1990
0
  if (QUERY_NODE_LOGIC_PLAN_VIRTUAL_TABLE_SCAN == nodeType(pNode) && 0 != LIST_LENGTH(pNode->pChildren) &&
1991
0
      QUERY_NODE_LOGIC_PLAN_EXCHANGE != nodeType(nodesListGetNode(pNode->pChildren, 0))) {
1992
0
    pInfo->pVirtual = (SVirtualScanLogicNode*)pNode;
1993
0
    pInfo->pSubplan = pSubplan;
1994
0
    return true;
1995
0
  }
1996
0
  return false;
1997
0
}
1998
1999
0
static bool needProcessOneBlockEachTime(SVirtualScanLogicNode* pVirtual) {
2000
0
  if (pVirtual->node.pParent && QUERY_NODE_LOGIC_PLAN_DYN_QUERY_CTRL == nodeType(pVirtual->node.pParent)) {
2001
0
    return true;
2002
0
  }
2003
0
  return false;
2004
0
}
2005
2006
0
static int32_t virtualTableSplit(SSplitContext* pCxt, SLogicSubplan* pSubplan) {
2007
0
  int32_t                code = TSDB_CODE_SUCCESS;
2008
0
  SVirtualTableSplitInfo info = {0};
2009
0
  if (!splMatch(pCxt, pSubplan, 0, (FSplFindSplitNode)virtualTableFindSplitNode, &info)) {
2010
0
    return TSDB_CODE_SUCCESS;
2011
0
  }
2012
0
  SNode*  pChild = NULL;
2013
0
  FOREACH(pChild, info.pVirtual->node.pChildren) {
2014
0
    SExchangeLogicNode* pExchange = NULL;
2015
0
    PLAN_ERR_JRET(splCreateExchangeNode(pCxt, (SLogicNode*)pChild, &pExchange));
2016
2017
0
    pExchange->dynTbname = nodeType((SLogicNode*)pChild) == QUERY_NODE_LOGIC_PLAN_SCAN ? ((SScanLogicNode*)pChild)->phTbnameScan : false;
2018
0
    pExchange->seqRecvData = (info.pVirtual->tableType == TSDB_SUPER_TABLE);
2019
2020
0
    pExchange->node.stmtRoot = ((SLogicNode*)pChild)->stmtRoot;
2021
0
    REPLACE_NODE(pExchange);
2022
0
    pExchange->node.pParent = ((SLogicNode*)pChild)->pParent;
2023
2024
0
    SLogicSubplan *sub = splCreateScanSubplan(pCxt, (SLogicNode*)pChild, 0);
2025
0
    sub->processOneBlock = needProcessOneBlockEachTime(info.pVirtual);
2026
0
    PLAN_ERR_JRET(nodesListMakeStrictAppend(&info.pSubplan->pChildren, (SNode*)sub));
2027
0
    ++(pCxt->groupId);
2028
0
  }
2029
0
  info.pSubplan->subplanType = SUBPLAN_TYPE_MERGE;
2030
0
_return:
2031
0
  pCxt->split = true;
2032
0
  return code;
2033
0
}
2034
2035
typedef struct SMergeAggColsSplitInfo {
2036
  SAggLogicNode   *pAgg;
2037
  SLogicNode      *pSplitNode;
2038
  SLogicSubplan   *pSubplan;
2039
} SMergeAggColsSplitInfo;
2040
2041
typedef struct SMergeTableScanSplitInfo {
2042
  SLogicNode    *pMerge;    // Dynamic merge node selected for split.
2043
  SLogicSubplan *pSubplan;  // Subplan that owns pMerge.
2044
} SMergeTableScanSplitInfo;
2045
2046
/*
2047
 * Find dynamic merge node that contains table-merge scan children.
2048
 *
2049
 * @param pCxt Split context.
2050
 * @param pSubplan Subplan currently visited.
2051
 * @param pNode Candidate logic node.
2052
 * @param pInfo Output split-node info.
2053
 *
2054
 * @return true when a split candidate is found, otherwise false.
2055
 */
2056
static bool mergeTableScanFindSplitNode(SSplitContext* pCxt, SLogicSubplan* pSubplan, SLogicNode* pNode,
2057
0
                                        SMergeTableScanSplitInfo* pInfo) {
2058
0
  if (QUERY_NODE_LOGIC_PLAN_MERGE != nodeType(pNode)) {
2059
0
    return false;
2060
0
  }
2061
0
  if (!pNode->dynamicOp) {
2062
0
    return false;
2063
0
  }
2064
2065
0
  SNode* pChild = NULL;
2066
0
  FOREACH(pChild, pNode->pChildren) {
2067
0
    if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pChild) &&
2068
0
        ((SScanLogicNode*)pChild)->scanType == SCAN_TYPE_TABLE_MERGE &&
2069
0
        ((SLogicNode*)pChild)->dynamicOp) {
2070
0
      pInfo->pSubplan = pSubplan;
2071
0
      pInfo->pMerge = pNode;
2072
0
      return true;
2073
0
    }
2074
0
  }
2075
0
  return false;
2076
0
}
2077
2078
/*
2079
 * Split dynamic table-merge scan children into independent scan subplans.
2080
 *
2081
 * @param pCxt Split context.
2082
 * @param pSubplan Subplan to split.
2083
 *
2084
 * @return TSDB_CODE_SUCCESS when completed or no split needed, otherwise error code.
2085
 */
2086
0
static int32_t mergeTableScanSplit(SSplitContext* pCxt, SLogicSubplan* pSubplan) {
2087
0
  int32_t                   code = TSDB_CODE_SUCCESS;
2088
0
  SMergeTableScanSplitInfo  info = {0};
2089
0
  if (!splMatch(pCxt, pSubplan, 0, (FSplFindSplitNode)mergeTableScanFindSplitNode, &info)) {
2090
0
    return TSDB_CODE_SUCCESS;
2091
0
  }
2092
0
  SMergeLogicNode* pMerge = (SMergeLogicNode*)info.pMerge;
2093
  // set group id range for merge node
2094
0
  pMerge->srcGroupId = pCxt->groupId;
2095
2096
0
  SNode*  pChild = NULL;
2097
0
  FOREACH(pChild, info.pMerge->pChildren) {
2098
0
    if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pChild) &&
2099
0
        ((SScanLogicNode*)pChild)->scanType == SCAN_TYPE_TABLE_MERGE &&
2100
0
        ((SLogicNode*)pChild)->dynamicOp) {
2101
0
      PLAN_ERR_RET(splCreateExchangeNodeForSubplan(pCxt, info.pSubplan, (SLogicNode*)pChild, SUBPLAN_TYPE_SCAN, false));
2102
0
      PLAN_ERR_RET(nodesListMakeStrictAppend(&info.pSubplan->pChildren, (SNode*)splCreateScanSubplan(pCxt, (SLogicNode*)pChild, 0)));
2103
0
      ++(pCxt->groupId);
2104
0
    }
2105
0
  }
2106
2107
0
  pMerge->srcEndGroupId = pCxt->groupId - 1;
2108
2109
0
  pCxt->split = true;
2110
0
  return code;
2111
0
}
2112
2113
0
static bool mergeAggColsNeedSplit(SLogicNode* pNode) {
2114
0
  if (QUERY_NODE_LOGIC_PLAN_AGG == nodeType(pNode) && 1 == LIST_LENGTH(pNode->pChildren) &&
2115
0
      NULL != pNode->pParent &&
2116
0
      QUERY_NODE_LOGIC_PLAN_MERGE == nodeType(pNode->pParent) &&
2117
0
      ((SMergeLogicNode *)pNode->pParent)->colsMerge &&
2118
0
      QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(nodesListGetNode(pNode->pChildren, 0))) {
2119
0
    return true;
2120
0
  }
2121
0
  return false;
2122
0
}
2123
2124
static bool mergeAggColsFindSplitNode(SSplitContext* pCxt, SLogicSubplan* pSubplan, SLogicNode* pNode,
2125
0
                                      SMergeAggColsSplitInfo* pInfo) {
2126
0
  if (mergeAggColsNeedSplit(pNode)) {
2127
0
    pInfo->pAgg = (SAggLogicNode *)pNode;
2128
0
    pInfo->pSplitNode = (SLogicNode*)nodesListGetNode(pNode->pChildren, 0);
2129
0
    pInfo->pSubplan = pSubplan;
2130
0
    return true;
2131
0
  }
2132
0
  return false;
2133
0
}
2134
2135
0
static int32_t mergeAggColsSplit(SSplitContext* pCxt, SLogicSubplan* pSubplan) {
2136
0
  int32_t                code = TSDB_CODE_SUCCESS;
2137
0
  SMergeAggColsSplitInfo info = {0};
2138
0
  if (!splMatch(pCxt, pSubplan, 0, (FSplFindSplitNode)mergeAggColsFindSplitNode, &info)) {
2139
0
    return TSDB_CODE_SUCCESS;
2140
0
  }
2141
2142
0
  PLAN_ERR_RET(splCreateExchangeNodeForSubplan(pCxt, info.pSubplan, info.pSplitNode, SUBPLAN_TYPE_MERGE, false));
2143
0
  PLAN_ERR_RET(nodesListMakeStrictAppend(&info.pSubplan->pChildren, (SNode*)splCreateScanSubplan(pCxt, info.pSplitNode, 0)));
2144
2145
0
  ++(pCxt->groupId);
2146
0
  pCxt->split = true;
2147
0
  return code;
2148
0
}
2149
2150
typedef struct SMergeExtWinSplitInfo {
2151
  SLogicNode      *pSplitNode;
2152
  SLogicSubplan   *pSubplan;
2153
} SMergeExtWinSplitInfo;
2154
2155
0
static bool mergeExtWinNeedSplit(SLogicNode* pNode) {
2156
0
  if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pNode) &&
2157
0
      pNode->pParent &&
2158
0
      pNode->pParent->pParent &&
2159
0
      QUERY_NODE_LOGIC_PLAN_WINDOW == nodeType(pNode->pParent)) {
2160
    // right part, which calculate the final result depends on the time range from left part
2161
    // virtual normal/child table
2162
0
    if (((SWindowLogicNode*)(pNode->pParent))->winType == WINDOW_TYPE_EXTERNAL &&
2163
0
        QUERY_NODE_LOGIC_PLAN_MERGE == nodeType(pNode->pParent->pParent)) {
2164
0
      return true;
2165
0
    }
2166
    // virtual super table
2167
0
    if (((SWindowLogicNode*)(pNode->pParent))->winType == WINDOW_TYPE_EXTERNAL &&
2168
0
        QUERY_NODE_LOGIC_PLAN_DYN_QUERY_CTRL == nodeType(pNode->pParent->pParent) &&
2169
0
        ((SDynQueryCtrlLogicNode*)pNode->pParent->pParent)->qType == DYN_QTYPE_VTB_WINDOW) {
2170
0
      return true;
2171
0
    }
2172
    // left part, which calculate the window range
2173
0
    if (((SWindowLogicNode*)(pNode->pParent))->winType != WINDOW_TYPE_EXTERNAL &&
2174
0
        QUERY_NODE_LOGIC_PLAN_DYN_QUERY_CTRL == nodeType(pNode->pParent->pParent)) {
2175
0
      return true;
2176
0
    }
2177
0
    return false;
2178
0
  }
2179
0
  return false;
2180
0
}
2181
2182
static bool mergeExtWinFindSplitNode(SSplitContext* pCxt, SLogicSubplan* pSubplan, SLogicNode* pNode,
2183
0
                                     SMergeExtWinSplitInfo* pInfo) {
2184
0
  if (mergeExtWinNeedSplit(pNode)) {
2185
0
    pInfo->pSplitNode = pNode;
2186
0
    pInfo->pSubplan = pSubplan;
2187
0
    return true;
2188
0
  }
2189
0
  return false;
2190
0
}
2191
2192
0
static int32_t mergeExtWinSplit(SSplitContext* pCxt, SLogicSubplan* pSubplan) {
2193
0
  int32_t                code = TSDB_CODE_SUCCESS;
2194
0
  SMergeExtWinSplitInfo  info = {0};
2195
0
  if (!splMatch(pCxt, pSubplan, 0, (FSplFindSplitNode)mergeExtWinFindSplitNode, &info)) {
2196
0
    return TSDB_CODE_SUCCESS;
2197
0
  }
2198
2199
0
  PLAN_ERR_RET(splCreateExchangeNodeForSubplan(pCxt, info.pSubplan, info.pSplitNode, info.pSubplan->subplanType, false));
2200
0
  PLAN_ERR_RET(nodesListMakeStrictAppend(&info.pSubplan->pChildren, (SNode*)splCreateScanSubplan(pCxt, info.pSplitNode, 0)));
2201
2202
0
  ++(pCxt->groupId);
2203
0
  pCxt->split = true;
2204
0
  return code;
2205
0
}
2206
2207
typedef struct SQnodeSplitInfo {
2208
  SLogicNode*    pSplitNode;
2209
  SLogicSubplan* pSubplan;
2210
} SQnodeSplitInfo;
2211
2212
static bool qndSplFindSplitNode(SSplitContext* pCxt, SLogicSubplan* pSubplan, SLogicNode* pNode,
2213
0
                                SQnodeSplitInfo* pInfo) {
2214
0
  if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pNode) && NULL != pNode->pParent &&
2215
0
      QUERY_NODE_LOGIC_PLAN_ANALYSIS_FUNC != nodeType(pNode->pParent) &&
2216
0
      QUERY_NODE_LOGIC_PLAN_FORECAST_FUNC != nodeType(pNode->pParent) && ((SScanLogicNode*)pNode)->scanSeq[0] <= 1 &&
2217
0
      ((SScanLogicNode*)pNode)->scanSeq[1] <= 1) {
2218
0
    pInfo->pSplitNode = pNode;
2219
0
    pInfo->pSubplan = pSubplan;
2220
0
    return true;
2221
0
  }
2222
0
  return false;
2223
0
}
2224
2225
0
static int32_t qnodeSplit(SSplitContext* pCxt, SLogicSubplan* pSubplan) {
2226
0
  if (QUERY_POLICY_QNODE != tsQueryPolicy) {
2227
0
    return TSDB_CODE_SUCCESS;
2228
0
  }
2229
2230
0
  SQnodeSplitInfo info = {0};
2231
0
  if (!splMatch(pCxt, pSubplan, 0, (FSplFindSplitNode)qndSplFindSplitNode, &info)) {
2232
0
    return TSDB_CODE_SUCCESS;
2233
0
  }
2234
0
  ((SScanLogicNode*)info.pSplitNode)->dataRequired = FUNC_DATA_REQUIRED_DATA_LOAD;
2235
0
  int32_t code = splCreateExchangeNodeForSubplan(pCxt, info.pSubplan, info.pSplitNode, info.pSubplan->subplanType, false);
2236
0
  if (TSDB_CODE_SUCCESS == code) {
2237
0
    SLogicSubplan* pScanSubplan = splCreateScanSubplan(pCxt, info.pSplitNode, 0);
2238
0
    if (NULL != pScanSubplan) {
2239
0
      if (NULL != info.pSubplan->pVgroupList) {
2240
0
        info.pSubplan->numOfComputeNodes = info.pSubplan->pVgroupList->numOfVgroups;
2241
0
        TSWAP(pScanSubplan->pVgroupList, info.pSubplan->pVgroupList);
2242
0
      } else {
2243
0
        info.pSubplan->numOfComputeNodes = 1;
2244
0
      }
2245
0
      code = nodesListMakeStrictAppend(&info.pSubplan->pChildren, (SNode*)pScanSubplan);
2246
0
    } else {
2247
0
      code = terrno;
2248
0
    }
2249
0
  }
2250
0
  info.pSubplan->subplanType = SUBPLAN_TYPE_COMPUTE;
2251
0
  ++(pCxt->groupId);
2252
0
  pCxt->split = true;
2253
0
  return code;
2254
0
}
2255
2256
typedef struct SDynVirtualScanSplitInfo {
2257
  SScanLogicNode         *pDyn;
2258
  SLogicSubplan          *pSubplan;
2259
} SDynVirtualScanSplitInfo;
2260
2261
static bool dynVirtualScanFindSplitNode(SSplitContext* pCxt, SLogicSubplan* pSubplan, SLogicNode* pNode,
2262
0
                                        SDynVirtualScanSplitInfo* pInfo) {
2263
0
  if (QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(pNode) || NULL == pNode->pParent) {
2264
0
    return false;
2265
0
  }
2266
2267
0
  SLogicNode*   pParent = pNode->pParent;
2268
0
  EScanType     scanType = ((SScanLogicNode*)pNode)->scanType;
2269
2270
  // 1. split for system table scan under dynamic query control node(virtual stable scan)
2271
0
  if (QUERY_NODE_LOGIC_PLAN_DYN_QUERY_CTRL == nodeType(pParent) &&
2272
0
      (((SDynQueryCtrlLogicNode*)(pParent))->qType == DYN_QTYPE_VTB_SCAN ||
2273
0
       ((SDynQueryCtrlLogicNode*)(pParent))->qType == DYN_QTYPE_VTB_WINDOW ||
2274
0
       ((SDynQueryCtrlLogicNode*)(pParent))->qType == DYN_QTYPE_VTB_TS_SCAN) &&
2275
0
      scanType == SCAN_TYPE_SYSTEM_TABLE) {
2276
0
    pInfo->pDyn = (SScanLogicNode*)pNode;
2277
0
    pInfo->pSubplan = pSubplan;
2278
0
    return true;
2279
0
  }
2280
2281
  // 2. split for system table scan under dynamic query control node(virtual stable agg)
2282
0
  if (QUERY_NODE_LOGIC_PLAN_DYN_QUERY_CTRL == nodeType(pParent) &&
2283
0
      (((SDynQueryCtrlLogicNode*)(pParent))->qType == DYN_QTYPE_VTB_AGG ||
2284
0
       ((SDynQueryCtrlLogicNode*)(pParent))->qType == DYN_QTYPE_VTB_INTERVAL) &&
2285
0
      scanType == SCAN_TYPE_SYSTEM_TABLE) {
2286
0
    pInfo->pDyn = (SScanLogicNode*)pNode;
2287
0
    pInfo->pSubplan = pSubplan;
2288
0
    return true;
2289
0
  }
2290
2291
  // 3. split for tag scan under partition node under dynamic query control node(virtual stable agg)
2292
0
  if (QUERY_NODE_LOGIC_PLAN_PARTITION == nodeType(pParent) && NULL != pParent->pParent &&
2293
0
      (((SDynQueryCtrlLogicNode*)(pParent->pParent))->qType == DYN_QTYPE_VTB_AGG ||
2294
0
       ((SDynQueryCtrlLogicNode*)(pParent->pParent))->qType == DYN_QTYPE_VTB_INTERVAL) &&
2295
0
      scanType == SCAN_TYPE_TAG) {
2296
0
    pInfo->pDyn = (SScanLogicNode*)pNode;
2297
0
    pInfo->pSubplan = pSubplan;
2298
0
    return true;
2299
0
  }
2300
2301
  // 4. split for tag scan under dynamic query control node(virtual stable agg)
2302
0
  if (QUERY_NODE_LOGIC_PLAN_DYN_QUERY_CTRL == nodeType(pParent) &&
2303
0
      (((SDynQueryCtrlLogicNode*)(pParent))->qType == DYN_QTYPE_VTB_AGG ||
2304
0
       ((SDynQueryCtrlLogicNode*)(pParent))->qType == DYN_QTYPE_VTB_INTERVAL) &&
2305
0
      scanType == SCAN_TYPE_TAG) {
2306
0
    pInfo->pDyn = (SScanLogicNode*)pNode;
2307
0
    pInfo->pSubplan = pSubplan;
2308
0
    return true;
2309
0
  }
2310
2311
0
  return false;
2312
0
}
2313
2314
0
static int32_t dynVirtualScanSplit(SSplitContext* pCxt, SLogicSubplan* pSubplan) {
2315
0
  int32_t                  code = TSDB_CODE_SUCCESS;
2316
0
  SDynVirtualScanSplitInfo info = {0};
2317
0
  if (!splMatch(pCxt, pSubplan, 0, (FSplFindSplitNode)dynVirtualScanFindSplitNode, &info)) {
2318
0
    return TSDB_CODE_SUCCESS;
2319
0
  }
2320
2321
0
  PLAN_ERR_RET(splCreateExchangeNodeForSubplan(pCxt, info.pSubplan, (SLogicNode*)info.pDyn, info.pSubplan->subplanType, false));
2322
0
  PLAN_ERR_RET(nodesListMakeStrictAppend(&info.pSubplan->pChildren, (SNode*)splCreateScanSubplan(pCxt, (SLogicNode*)info.pDyn, 0)));
2323
  
2324
0
  info.pSubplan->subplanType = SUBPLAN_TYPE_MERGE;
2325
0
  ++(pCxt->groupId);
2326
2327
0
  pCxt->split = true;
2328
0
  return code;
2329
0
}
2330
2331
typedef struct SVstbAggSplitInfo {
2332
  SLogicNode             *pAgg;
2333
  SLogicNode             *pDyn;
2334
  SLogicSubplan          *pSubplan;
2335
  bool                    needPartAgg;
2336
} SVstbAggSplitInfo;
2337
2338
static bool vstbAggFindSplitNode(SSplitContext* pCxt, SLogicSubplan* pSubplan, SLogicNode* pNode,
2339
0
                                 SVstbAggSplitInfo* pInfo) {
2340
0
  if (QUERY_NODE_LOGIC_PLAN_AGG == nodeType(pNode) && NULL != pNode->pParent && LIST_LENGTH(pNode->pChildren) == 1) {
2341
0
    if (QUERY_NODE_LOGIC_PLAN_DYN_QUERY_CTRL == nodeType(pNode->pParent) &&
2342
0
        (((SDynQueryCtrlLogicNode*)(pNode->pParent))->qType == DYN_QTYPE_VTB_AGG ||
2343
0
         ((SDynQueryCtrlLogicNode*)(pNode->pParent))->qType == DYN_QTYPE_VTB_INTERVAL) &&
2344
0
        QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(nodesListGetNode(pNode->pChildren, 0))) {
2345
0
      if (((SDynQueryCtrlLogicNode*)(pNode->pParent))->vtbScan.batchProcessChild) {
2346
0
        pInfo->pAgg = (SLogicNode *)pNode;
2347
0
        pInfo->pSubplan = pSubplan;
2348
0
        pInfo->needPartAgg = true;
2349
0
      } else {
2350
0
        pInfo->pAgg = (SLogicNode *)pNode;
2351
0
        pInfo->pDyn = pNode->pParent;
2352
0
        pInfo->pSubplan = pSubplan;
2353
0
        pInfo->needPartAgg = false;
2354
0
      }
2355
0
      return true;
2356
0
    }
2357
0
  }
2358
0
  return false;
2359
2360
0
}
2361
2362
0
static int32_t vstbAggSplit(SSplitContext* pCxt, SLogicSubplan* pSubplan) {
2363
0
  int32_t                  code = TSDB_CODE_SUCCESS;
2364
0
  int32_t                  lino = 0;
2365
0
  struct SVstbAggSplitInfo info = {0};
2366
0
  if (!splMatch(pCxt, pSubplan, 0, (FSplFindSplitNode)vstbAggFindSplitNode, &info)) {
2367
0
    return TSDB_CODE_SUCCESS;
2368
0
  }
2369
2370
0
  SLogicNode* pPartAgg = NULL;
2371
2372
0
  if (info.needPartAgg) {
2373
0
    PLAN_ERR_JRET(stbSplCreatePartAggNode((SAggLogicNode*)info.pAgg, &pPartAgg));
2374
0
    PLAN_ERR_JRET(stbSplCreateExchangeNode(pCxt, info.pAgg, pPartAgg));
2375
0
    PLAN_ERR_JRET(nodesListMakeStrictAppend(&info.pSubplan->pChildren, (SNode*)splCreateScanSubplan(pCxt, pPartAgg, 0)));
2376
0
  } else {
2377
0
    PLAN_ERR_JRET(splCreateExchangeNodeForSubplan(pCxt, info.pSubplan, (SLogicNode*)info.pAgg, info.pSubplan->subplanType, false));
2378
0
    PLAN_ERR_JRET(nodesListMakeStrictAppend(&info.pSubplan->pChildren, (SNode*)splCreateScanSubplan(pCxt, (SLogicNode*)info.pAgg, 0)));
2379
0
  }
2380
2381
2382
0
  info.pSubplan->subplanType = SUBPLAN_TYPE_MERGE;
2383
0
  ++(pCxt->groupId);
2384
2385
0
  pCxt->split = true;
2386
0
  return code;
2387
0
_return:
2388
0
  planError("%s failed, code: %d, line: %d", __func__, code, lino);
2389
0
  return code;
2390
0
}
2391
2392
typedef struct SVstbIntervalSplitInfo {
2393
  SLogicNode*    pWindow;   // Interval-window node selected for split.
2394
  SLogicSubplan* pSubplan;  // Subplan that owns pWindow.
2395
} SVstbIntervalSplitInfo;
2396
2397
/*
2398
 * Find virtual-stable interval window that can be split for batch processing.
2399
 *
2400
 * @param pCxt Split context.
2401
 * @param pSubplan Subplan currently visited.
2402
 * @param pNode Candidate logic node.
2403
 * @param pInfo Output split-node info.
2404
 *
2405
 * @return true when a split candidate is found, otherwise false.
2406
 */
2407
static bool vstbIntervalFindSplitNode(SSplitContext* pCxt, SLogicSubplan* pSubplan, SLogicNode* pNode,
2408
0
                                      SVstbIntervalSplitInfo* pInfo) {
2409
0
  (void)pCxt;
2410
0
  if (QUERY_NODE_LOGIC_PLAN_WINDOW != nodeType(pNode) || LIST_LENGTH(pNode->pChildren) != 1 ||
2411
0
      WINDOW_TYPE_INTERVAL != ((SWindowLogicNode*)pNode)->winType || NULL == pNode->pParent ||
2412
0
      QUERY_NODE_LOGIC_PLAN_DYN_QUERY_CTRL != nodeType(pNode->pParent) ||
2413
0
      DYN_QTYPE_VTB_INTERVAL != ((SDynQueryCtrlLogicNode*)pNode->pParent)->qType ||
2414
0
      !((SDynQueryCtrlLogicNode*)pNode->pParent)->vtbScan.batchProcessChild ||
2415
0
      QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(nodesListGetNode(pNode->pChildren, 0))) {
2416
0
    return false;
2417
0
  }
2418
2419
0
  pInfo->pWindow = pNode;
2420
0
  pInfo->pSubplan = pSubplan;
2421
0
  return true;
2422
0
}
2423
2424
/*
2425
 * Split a virtual-stable interval window subplan into per-group scan subplans.
2426
 *
2427
 * @param pCxt Split context.
2428
 * @param pSubplan Subplan to split.
2429
 *
2430
 * @return TSDB_CODE_SUCCESS on success, otherwise error code.
2431
 */
2432
0
static int32_t vstbIntervalSplit(SSplitContext* pCxt, SLogicSubplan* pSubplan) {
2433
0
  SVstbIntervalSplitInfo info = {0};
2434
0
  if (!splMatch(pCxt, pSubplan, 0, (FSplFindSplitNode)vstbIntervalFindSplitNode, &info)) {
2435
0
    return TSDB_CODE_SUCCESS;
2436
0
  }
2437
2438
0
  SStableSplitInfo splitInfo = {
2439
0
    .pSplitNode = info.pWindow,
2440
0
    .pSubplan = info.pSubplan,
2441
0
  };
2442
2443
0
  int32_t code = stbSplSplitIntervalForBatch(pCxt, &splitInfo);
2444
0
  if (TSDB_CODE_SUCCESS == code) {
2445
0
    info.pWindow->splitDone = true;
2446
0
    pCxt->split = true;
2447
0
  }
2448
0
  return code;
2449
0
}
2450
2451
typedef struct SStreamScanSplitInfo {
2452
  SLogicNode             *pSplitNode;
2453
  SLogicSubplan          *pSubplan;
2454
} SStreamScanSplitInfo;
2455
2456
static bool streamScanFindSplitNode(SSplitContext* pCxt, SLogicSubplan* pSubplan, SLogicNode* pNode,
2457
0
                                           SStreamScanSplitInfo* pInfo) {
2458
0
  if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pNode) && NULL != pNode->pParent) {
2459
0
    pInfo->pSplitNode = (SLogicNode *)pNode;
2460
0
    pInfo->pSubplan = pSubplan;
2461
0
    return true;
2462
0
  }
2463
0
  return false;
2464
0
}
2465
2466
0
static int32_t streamScanSplit(SSplitContext* pCxt, SLogicSubplan* pSubplan) {
2467
0
  int32_t                     code = TSDB_CODE_SUCCESS;
2468
0
  SStreamScanSplitInfo info = {0};
2469
0
  if (!inStreamCalcClause(pCxt->pPlanCxt) && !inStreamTriggerClause(pCxt->pPlanCxt)) {
2470
0
    return TSDB_CODE_SUCCESS;
2471
0
  }
2472
0
  while (splMatch(pCxt, pSubplan, 0, (FSplFindSplitNode)streamScanFindSplitNode, &info)) {
2473
0
    PLAN_ERR_RET(splCreateExchangeNodeForSubplan(pCxt, info.pSubplan, info.pSplitNode, info.pSubplan->subplanType, false));
2474
0
    SLogicSubplan* pScanSubplan = splCreateScanSubplan(pCxt, info.pSplitNode, 0);
2475
0
    if (NULL != pScanSubplan) {
2476
0
      if (NULL != info.pSubplan->pVgroupList) {
2477
0
        info.pSubplan->numOfComputeNodes = info.pSubplan->pVgroupList->numOfVgroups;
2478
0
      } else {
2479
0
        info.pSubplan->numOfComputeNodes = 1;
2480
0
      }
2481
0
      if (!pScanSubplan->pVgroupList) {
2482
0
        PLAN_ERR_RET(cloneVgroups(&pScanSubplan->pVgroupList, info.pSubplan->pVgroupList));
2483
0
      }
2484
0
      pScanSubplan->dynTbname = ((SScanLogicNode*)info.pSplitNode)->phTbnameScan;
2485
0
      PLAN_ERR_RET(nodesListMakeStrictAppend(&info.pSubplan->pChildren, (SNode*)pScanSubplan));
2486
0
    } else {
2487
0
      PLAN_ERR_RET(terrno);
2488
0
    }
2489
0
    info.pSubplan->subplanType = SUBPLAN_TYPE_COMPUTE;
2490
0
    ++(pCxt->groupId);
2491
0
    info.pSplitNode->splitDone = true;
2492
0
    pCxt->split = true;
2493
0
  }
2494
2495
0
  return code;
2496
0
}
2497
2498
// clang-format off
2499
static const SSplitRule splitRuleSet[] = {
2500
  {.pName = "SuperTableSplit",        .splitFunc = stableSplit},
2501
  {.pName = "SingleTableJoinSplit",   .splitFunc = singleTableJoinSplit},
2502
  {.pName = "UnionAllSplit",          .splitFunc = unionAllSplit},
2503
  {.pName = "UnionDistinctSplit",     .splitFunc = unionDistinctSplit},
2504
  {.pName = "SmaIndexSplit",          .splitFunc = smaIndexSplit}, // not used yet
2505
  {.pName = "InsertSelectSplit",      .splitFunc = insertSelectSplit},
2506
  {.pName = "VirtualtableSplit",      .splitFunc = virtualTableSplit},
2507
  {.pName = "MergeTableScanSplit",    .splitFunc = mergeTableScanSplit},
2508
  {.pName = "MergeAggColsSplit",      .splitFunc = mergeAggColsSplit},
2509
  {.pName = "DynVirtualScanSplit",    .splitFunc = dynVirtualScanSplit},
2510
  {.pName = "VStbIntervalSplit",      .splitFunc = vstbIntervalSplit},
2511
  {.pName = "MergeExtWinSplit",       .splitFunc = mergeExtWinSplit},
2512
  {.pName = "VStbAggSplit",           .splitFunc = vstbAggSplit},
2513
};
2514
// clang-format on
2515
2516
static const int32_t splitRuleNum = (sizeof(splitRuleSet) / sizeof(SSplitRule));
2517
2518
0
static int32_t dumpLogicSubplan(const char* pRuleName, SLogicSubplan* pSubplan) {
2519
0
  int32_t code = 0;
2520
0
  if (!tsQueryPlannerTrace) {
2521
0
    return code;
2522
0
  }
2523
0
  char* pStr = NULL;
2524
0
  code = nodesNodeToString((SNode*)pSubplan, false, &pStr, NULL);
2525
0
  if (TSDB_CODE_SUCCESS == code) {
2526
0
    if (NULL == pRuleName) {
2527
0
      qDebugL("before split, JsonPlan: %s", pStr);
2528
0
    } else {
2529
0
      qDebugL("apply split %s rule, JsonPlan: %s", pRuleName, pStr);
2530
0
    }
2531
0
    taosMemoryFree(pStr);
2532
0
  }
2533
0
  return code;
2534
0
}
2535
2536
0
static int32_t applySplitRule(SPlanContext* pCxt, SLogicSubplan* pSubplan) {
2537
0
  SSplitContext cxt = {
2538
0
      .pPlanCxt = pCxt, .queryId = pSubplan->id.queryId, .groupId = pCxt->groupId + 1, .split = false};
2539
0
  bool    split = false;
2540
0
  int32_t code =TSDB_CODE_SUCCESS;
2541
0
  PLAN_ERR_RET(dumpLogicSubplan(NULL, pSubplan));
2542
0
  do {
2543
0
    split = false;
2544
0
    for (int32_t i = 0; i < splitRuleNum; ++i) {
2545
0
      cxt.split = false;
2546
0
      PLAN_ERR_RET(splitRuleSet[i].splitFunc(&cxt, pSubplan));
2547
0
      if (cxt.split) {
2548
0
        split = true;
2549
0
        PLAN_ERR_RET(dumpLogicSubplan(splitRuleSet[i].pName, pSubplan));
2550
0
      }
2551
0
    }
2552
0
  } while (split);
2553
2554
0
  PLAN_ERR_RET(streamScanSplit(&cxt, pSubplan));
2555
0
  PLAN_ERR_RET(qnodeSplit(&cxt, pSubplan));
2556
2557
0
  pCxt->groupId = cxt.groupId + 1;
2558
  
2559
0
  PLAN_RET(code);
2560
0
}
2561
2562
0
static void setVgroupsInfo(SLogicNode* pNode, SLogicSubplan* pSubplan) {
2563
0
  if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pNode)) {
2564
0
    TSWAP(((SScanLogicNode*)pNode)->pVgroupList, pSubplan->pVgroupList);
2565
0
    return;
2566
0
  } else if (QUERY_NODE_LOGIC_PLAN_VIRTUAL_TABLE_SCAN == nodeType(pNode)) {
2567
    // do nothing, since virtual table scan node is SUBPLAN_TYPE_MERGE
2568
0
    return;
2569
0
  }
2570
2571
0
  SNode* pChild;
2572
0
  FOREACH(pChild, pNode->pChildren) { setVgroupsInfo((SLogicNode*)pChild, pSubplan); }
2573
0
}
2574
2575
0
static bool needSplitSubplan(SLogicSubplan* pLogicSubplan) {
2576
0
  if (QUERY_NODE_LOGIC_PLAN_VNODE_MODIFY != nodeType(pLogicSubplan->pNode)) {
2577
0
    return true;
2578
0
  }
2579
0
  SVnodeModifyLogicNode* pModify = (SVnodeModifyLogicNode*)pLogicSubplan->pNode;
2580
0
  return (MODIFY_TABLE_TYPE_INSERT == pModify->modifyType && NULL != pModify->node.pChildren);
2581
0
}
2582
2583
0
int32_t splitLogicPlan(SPlanContext* pCxt, SLogicSubplan* pLogicSubplan) {
2584
0
  if (!needSplitSubplan(pLogicSubplan)) {
2585
0
    setVgroupsInfo(pLogicSubplan->pNode, pLogicSubplan);
2586
0
    return TSDB_CODE_SUCCESS;
2587
0
  }
2588
0
  return applySplitRule(pCxt, pLogicSubplan);
2589
0
}