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

taosdata / TDengine / #3524

08 Nov 2024 04:27AM UTC coverage: 60.898% (+5.0%) from 55.861%
#3524

push

travis-ci

web-flow
Merge pull request #28647 from taosdata/fix/3.0/TD-32519_drop_ctb

fix TD-32519 drop child table with tsma caused crash

118687 of 248552 branches covered (47.75%)

Branch coverage included in aggregate %.

286 of 337 new or added lines in 18 files covered. (84.87%)

9647 existing lines in 190 files now uncovered.

199106 of 273291 relevant lines covered (72.85%)

15236719.35 hits per line

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

70.12
/source/libs/executor/src/streamtimewindowoperator.c
1
/*
2
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
3
 *
4
 * This program is free software: you can use, redistribute, and/or modify
5
 * it under the terms of the GNU Affero General Public License, version 3
6
 * or later ("AGPL"), as published by the Free Software Foundation.
7
 *
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 * FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * You should have received a copy of the GNU Affero General Public License
13
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14
 */
15
#include "executorInt.h"
16
#include "filter.h"
17
#include "function.h"
18
#include "functionMgt.h"
19
#include "operator.h"
20
#include "querytask.h"
21
#include "streamexecutorInt.h"
22
#include "tchecksum.h"
23
#include "tcommon.h"
24
#include "tcompare.h"
25
#include "tdatablock.h"
26
#include "tfill.h"
27
#include "tglobal.h"
28
#include "tlog.h"
29
#include "ttime.h"
30

31
#define IS_FINAL_INTERVAL_OP(op) ((op)->operatorType == QUERY_NODE_PHYSICAL_PLAN_STREAM_FINAL_INTERVAL)
32
#define IS_MID_INTERVAL_OP(op)   ((op)->operatorType == QUERY_NODE_PHYSICAL_PLAN_STREAM_MID_INTERVAL)
33

34
#define IS_FINAL_SESSION_OP(op) ((op)->operatorType == QUERY_NODE_PHYSICAL_PLAN_STREAM_FINAL_SESSION)
35
#define IS_NORMAL_SESSION_OP(op)                                    \
36
  ((op)->operatorType == QUERY_NODE_PHYSICAL_PLAN_STREAM_SESSION || \
37
   (op)->operatorType == QUERY_NODE_PHYSICAL_PLAN_STREAM_FINAL_SESSION)
38

39
#define IS_NORMAL_STATE_OP(op) ((op)->operatorType == QUERY_NODE_PHYSICAL_PLAN_STREAM_STATE)
40

41
#define DEAULT_DELETE_MARK                 INT64_MAX
42
#define STREAM_INTERVAL_OP_STATE_NAME      "StreamIntervalHistoryState"
43
#define STREAM_SESSION_OP_STATE_NAME       "StreamSessionHistoryState"
44
#define STREAM_STATE_OP_STATE_NAME         "StreamStateHistoryState"
45
#define STREAM_INTERVAL_OP_CHECKPOINT_NAME "StreamIntervalOperator_Checkpoint"
46
#define STREAM_SESSION_OP_CHECKPOINT_NAME  "StreamSessionOperator_Checkpoint"
47
#define STREAM_STATE_OP_CHECKPOINT_NAME    "StreamStateOperator_Checkpoint"
48

49
#define MAX_STREAM_HISTORY_RESULT 20000000
50

51
typedef struct SStateWindowInfo {
52
  SResultWindowInfo winInfo;
53
  SStateKeys*       pStateKey;
54
} SStateWindowInfo;
55

56
typedef struct SPullWindowInfo {
57
  STimeWindow window;
58
  uint64_t    groupId;
59
  STimeWindow calWin;
60
} SPullWindowInfo;
61

62
static int32_t doStreamMidIntervalAggNext(SOperatorInfo* pOperator, SSDataBlock** ppRes);
63

64
typedef int32_t (*__compare_fn_t)(void* pKey, void* data, int32_t index);
65

66
static int32_t binarySearchCom(void* keyList, int num, void* pKey, int order, __compare_fn_t comparefn) {
1,584✔
67
  int firstPos = 0, lastPos = num - 1, midPos = -1;
1,584✔
68
  int numOfRows = 0;
1,584✔
69

70
  if (num <= 0) return -1;
1,584✔
71
  if (order == TSDB_ORDER_DESC) {
1,375!
72
    // find the first position which is smaller or equal than the key
73
    while (1) {
74
      if (comparefn(pKey, keyList, lastPos) >= 0) return lastPos;
1,490✔
75
      if (comparefn(pKey, keyList, firstPos) == 0) return firstPos;
360✔
76
      if (comparefn(pKey, keyList, firstPos) < 0) return firstPos - 1;
234✔
77

78
      numOfRows = lastPos - firstPos + 1;
170✔
79
      midPos = (numOfRows >> 1) + firstPos;
170✔
80

81
      if (comparefn(pKey, keyList, midPos) < 0) {
170✔
82
        lastPos = midPos - 1;
79✔
83
      } else if (comparefn(pKey, keyList, midPos) > 0) {
91✔
84
        firstPos = midPos + 1;
36✔
85
      } else {
86
        break;
55✔
87
      }
88
    }
89

90
  } else {
91
    // find the first position which is bigger or equal than the key
92
    while (1) {
UNCOV
93
      if (comparefn(pKey, keyList, firstPos) <= 0) return firstPos;
×
UNCOV
94
      if (comparefn(pKey, keyList, lastPos) == 0) return lastPos;
×
95

96
      if (comparefn(pKey, keyList, lastPos) > 0) {
×
97
        lastPos = lastPos + 1;
×
UNCOV
98
        if (lastPos >= num)
×
99
          return -1;
×
100
        else
101
          return lastPos;
×
102
      }
103

104
      numOfRows = lastPos - firstPos + 1;
×
UNCOV
105
      midPos = (numOfRows >> 1) + firstPos;
×
106

107
      if (comparefn(pKey, keyList, midPos) < 0) {
×
108
        lastPos = midPos - 1;
×
UNCOV
109
      } else if (comparefn(pKey, keyList, midPos) > 0) {
×
110
        firstPos = midPos + 1;
×
111
      } else {
112
        break;
×
113
      }
114
    }
115
  }
116

117
  return midPos;
55✔
118
}
119

120
static int32_t comparePullWinKey(void* pKey, void* data, int32_t index) {
220✔
121
  SArray*          res = (SArray*)data;
220✔
122
  SPullWindowInfo* pos = taosArrayGet(res, index);
220✔
123
  SPullWindowInfo* pData = (SPullWindowInfo*)pKey;
220✔
124
  if (pData->groupId > pos->groupId) {
220✔
125
    return 1;
108✔
126
  } else if (pData->groupId < pos->groupId) {
112✔
127
    return -1;
67✔
128
  }
129

130
  if (pData->window.skey > pos->window.ekey) {
45✔
131
    return 1;
36✔
132
  } else if (pData->window.ekey < pos->window.skey) {
9✔
133
    return -1;
3✔
134
  }
135
  return 0;
6✔
136
}
137

138
static int32_t savePullWindow(SPullWindowInfo* pPullInfo, SArray* pPullWins) {
226✔
139
  int32_t size = taosArrayGetSize(pPullWins);
226✔
140
  int32_t index = binarySearchCom(pPullWins, size, pPullInfo, TSDB_ORDER_DESC, comparePullWinKey);
226✔
141
  if (index == -1) {
226✔
142
    index = 0;
172✔
143
  } else {
144
    int32_t code = comparePullWinKey(pPullInfo, pPullWins, index);
54✔
145
    if (code == 0) {
54✔
146
      SPullWindowInfo* pos = taosArrayGet(pPullWins, index);
3✔
147
      pos->window.skey = TMIN(pos->window.skey, pPullInfo->window.skey);
3✔
148
      pos->window.ekey = TMAX(pos->window.ekey, pPullInfo->window.ekey);
3✔
149
      pos->calWin.skey = TMIN(pos->calWin.skey, pPullInfo->calWin.skey);
3✔
150
      pos->calWin.ekey = TMAX(pos->calWin.ekey, pPullInfo->calWin.ekey);
3✔
151
      return TSDB_CODE_SUCCESS;
3✔
152
    } else if (code > 0) {
51!
153
      index++;
51✔
154
    }
155
  }
156
  if (taosArrayInsert(pPullWins, index, pPullInfo) == NULL) {
223!
UNCOV
157
    return terrno;
×
158
  }
159
  return TSDB_CODE_SUCCESS;
223✔
160
}
161

162
int32_t saveResult(SResultWindowInfo winInfo, SSHashObj* pStUpdated) {
10,119✔
163
  if (tSimpleHashGetSize(pStUpdated) > MAX_STREAM_HISTORY_RESULT) {
10,119!
UNCOV
164
    qError("%s failed at line %d since too many history result. ", __func__, __LINE__);
×
UNCOV
165
    return TSDB_CODE_STREAM_INTERNAL_ERROR;
×
166
  }
167
  winInfo.sessionWin.win.ekey = winInfo.sessionWin.win.skey;
10,120✔
168
  return tSimpleHashPut(pStUpdated, &winInfo.sessionWin, sizeof(SSessionKey), &winInfo, sizeof(SResultWindowInfo));
10,120✔
169
}
170

171
int32_t saveWinResult(SWinKey* pKey, SRowBuffPos* pPos, SSHashObj* pUpdatedMap) {
12,742,786✔
172
  if (tSimpleHashGetSize(pUpdatedMap) > MAX_STREAM_HISTORY_RESULT) {
12,742,786!
UNCOV
173
    qError("%s failed at line %d since too many history result. ", __func__, __LINE__);
×
UNCOV
174
    return TSDB_CODE_STREAM_INTERNAL_ERROR;
×
175
  }
176
  return tSimpleHashPut(pUpdatedMap, pKey, sizeof(SWinKey), &pPos, POINTER_BYTES);
12,740,937✔
177
}
178

179
static int32_t saveWinResultInfo(TSKEY ts, uint64_t groupId, SRowBuffPos* pPos, SSHashObj* pUpdatedMap) {
311✔
180
  SWinKey key = {.ts = ts, .groupId = groupId};
311✔
181
  return saveWinResult(&key, pPos, pUpdatedMap);
311✔
182
}
183

184
static void removeResults(SArray* pWins, SSHashObj* pUpdatedMap) {
207✔
185
  int32_t size = taosArrayGetSize(pWins);
207✔
186
  for (int32_t i = 0; i < size; i++) {
456✔
187
    SWinKey* pW = taosArrayGet(pWins, i);
249✔
188
    void*    tmp = tSimpleHashGet(pUpdatedMap, pW, sizeof(SWinKey));
249✔
189
    if (tmp) {
249!
UNCOV
190
      void* value = *(void**)tmp;
×
UNCOV
191
      taosMemoryFree(value);
×
UNCOV
192
      int32_t tmpRes = tSimpleHashRemove(pUpdatedMap, pW, sizeof(SWinKey));
×
193
      qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
×
194
    }
195
  }
196
}
207✔
197

198
static int32_t compareWinKey(void* pKey, void* data, int32_t index) {
3,442✔
199
  void* pDataPos = taosArrayGet((SArray*)data, index);
3,442✔
200
  return winKeyCmprImpl(pKey, pDataPos);
3,441✔
201
}
202

203
void removeDeleteResults(SSHashObj* pUpdatedMap, SArray* pDelWins) {
33,502✔
204
  taosArraySort(pDelWins, winKeyCmprImpl);
33,502✔
205
  taosArrayRemoveDuplicate(pDelWins, winKeyCmprImpl, NULL);
33,501✔
206
  int32_t delSize = taosArrayGetSize(pDelWins);
33,500✔
207
  if (tSimpleHashGetSize(pUpdatedMap) == 0 || delSize == 0) {
33,500✔
208
    return;
32,838✔
209
  }
210
  void*   pIte = NULL;
663✔
211
  int32_t iter = 0;
663✔
212
  while ((pIte = tSimpleHashIterate(pUpdatedMap, pIte, &iter)) != NULL) {
1,800✔
213
    SWinKey* pResKey = tSimpleHashGetKey(pIte, NULL);
1,137✔
214
    int32_t  index = binarySearchCom(pDelWins, delSize, pResKey, TSDB_ORDER_DESC, compareWinKey);
1,137✔
215
    if (index >= 0 && 0 == compareWinKey(pResKey, pDelWins, index)) {
1,137✔
216
      taosArrayRemove(pDelWins, index);
951✔
217
      delSize = taosArrayGetSize(pDelWins);
951✔
218
    }
219
  }
220
}
221

222
bool isOverdue(TSKEY ekey, STimeWindowAggSupp* pTwSup) {
99,234,760✔
223
  return pTwSup->maxTs != INT64_MIN && ekey < pTwSup->maxTs - pTwSup->waterMark;
99,234,760✔
224
}
225

226
bool isCloseWindow(STimeWindow* pWin, STimeWindowAggSupp* pTwSup) { return isOverdue(pWin->ekey, pTwSup); }
45,467,317✔
227

228
static void doDeleteWindow(SOperatorInfo* pOperator, TSKEY ts, uint64_t groupId) {
3,585✔
229
  SStorageAPI* pAPI = &pOperator->pTaskInfo->storageAPI;
3,585✔
230

231
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
3,585✔
232
  SWinKey                      key = {.ts = ts, .groupId = groupId};
3,585✔
233
  int32_t                      tmpRes = tSimpleHashRemove(pInfo->aggSup.pResultRowHashTable, &key, sizeof(SWinKey));
3,585✔
234
  qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
3,586✔
235
  pAPI->stateStore.streamStateDel(pInfo->pState, &key);
3,586✔
236
}
3,583✔
237

238
static int32_t getChildIndex(SSDataBlock* pBlock) { return pBlock->info.childId; }
1,512✔
239

240
static int32_t doDeleteWindows(SOperatorInfo* pOperator, SInterval* pInterval, SSDataBlock* pBlock, SArray* pUpWins,
2,436✔
241
                               SSHashObj* pUpdatedMap, SHashObj* pInvalidWins) {
242
  int32_t                      code = TSDB_CODE_SUCCESS;
2,436✔
243
  int32_t                      lino = 0;
2,436✔
244
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
2,436✔
245
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
2,436✔
246
  SColumnInfoData*             pStartTsCol = taosArrayGet(pBlock->pDataBlock, START_TS_COLUMN_INDEX);
2,436✔
247
  TSKEY*                       startTsCols = (TSKEY*)pStartTsCol->pData;
2,436✔
248
  SColumnInfoData*             pEndTsCol = taosArrayGet(pBlock->pDataBlock, END_TS_COLUMN_INDEX);
2,436✔
249
  TSKEY*                       endTsCols = (TSKEY*)pEndTsCol->pData;
2,438✔
250
  SColumnInfoData*             pCalStTsCol = taosArrayGet(pBlock->pDataBlock, CALCULATE_START_TS_COLUMN_INDEX);
2,438✔
251
  TSKEY*                       calStTsCols = (TSKEY*)pCalStTsCol->pData;
2,438✔
252
  SColumnInfoData*             pCalEnTsCol = taosArrayGet(pBlock->pDataBlock, CALCULATE_END_TS_COLUMN_INDEX);
2,438✔
253
  TSKEY*                       calEnTsCols = (TSKEY*)pCalEnTsCol->pData;
2,439✔
254
  SColumnInfoData*             pGpCol = taosArrayGet(pBlock->pDataBlock, GROUPID_COLUMN_INDEX);
2,439✔
255
  uint64_t*                    pGpDatas = (uint64_t*)pGpCol->pData;
2,437✔
256
  for (int32_t i = 0; i < pBlock->info.rows; i++) {
5,172✔
257
    SResultRowInfo dumyInfo = {0};
2,733✔
258
    dumyInfo.cur.pageId = -1;
2,733✔
259

260
    STimeWindow win = {0};
2,733✔
261
    if (IS_FINAL_INTERVAL_OP(pOperator) || IS_MID_INTERVAL_OP(pOperator)) {
2,733✔
262
      win.skey = startTsCols[i];
261✔
263
      win.ekey = endTsCols[i];
261✔
264
    } else {
265
      win = getActiveTimeWindow(NULL, &dumyInfo, startTsCols[i], pInterval, TSDB_ORDER_ASC);
2,472✔
266
    }
267

268
    do {
269
      if (!inCalSlidingWindow(pInterval, &win, calStTsCols[i], calEnTsCols[i], pBlock->info.type)) {
3,638✔
270
        getNextTimeWindow(pInterval, &win, TSDB_ORDER_ASC);
26✔
271
        continue;
81✔
272
      }
273
      uint64_t winGpId = pGpDatas[i];
3,611✔
274
      SWinKey  winRes = {.ts = win.skey, .groupId = winGpId};
3,611✔
275
      void*    chIds = taosHashGet(pInfo->pPullDataMap, &winRes, sizeof(SWinKey));
3,611✔
276
      if (chIds) {
3,612✔
277
        int32_t childId = getChildIndex(pBlock);
56✔
278
        if (pInvalidWins) {
56✔
279
          qDebug("===stream===save invalid delete window:%" PRId64 ",groupId:%" PRId64 ",chId:%d", winRes.ts,
50!
280
                 winRes.groupId, childId);
281
          code = taosHashPut(pInvalidWins, &winRes, sizeof(SWinKey), NULL, 0);
50✔
282
          QUERY_CHECK_CODE(code, lino, _end);
50!
283
        }
284

285
        SArray* chArray = *(void**)chIds;
56✔
286
        int32_t index = taosArraySearchIdx(chArray, &childId, compareInt32Val, TD_EQ);
56✔
287
        if (index != -1) {
56✔
288
          qDebug("===stream===try push delete window:%" PRId64 ",groupId:%" PRId64 ",chId:%d ,continue", win.skey,
55!
289
                 winGpId, childId);
290
          getNextTimeWindow(pInterval, &win, TSDB_ORDER_ASC);
55✔
291
          continue;
55✔
292
        }
293
      }
294
      doDeleteWindow(pOperator, win.skey, winGpId);
3,557✔
295
      if (pUpWins) {
3,553✔
296
        void* tmp = taosArrayPush(pUpWins, &winRes);
2,778✔
297
        if (!tmp) {
2,778!
UNCOV
298
          code = terrno;
×
UNCOV
299
          QUERY_CHECK_CODE(code, lino, _end);
×
300
        }
301
      }
302
      if (pUpdatedMap) {
3,553!
303
        int32_t tmpRes = tSimpleHashRemove(pUpdatedMap, &winRes, sizeof(SWinKey));
3,554✔
304
        qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
3,556✔
305
      }
306
      getNextTimeWindow(pInterval, &win, TSDB_ORDER_ASC);
3,555✔
307
    } while (win.ekey <= endTsCols[i]);
3,637✔
308
  }
309
_end:
2,439✔
310
  if (code != TSDB_CODE_SUCCESS) {
2,439!
UNCOV
311
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
312
  }
313
  return code;
2,439✔
314
}
315

316
static int32_t getAllIntervalWindow(SSHashObj* pHashMap, SSHashObj* resWins) {
1,080✔
317
  void*   pIte = NULL;
1,080✔
318
  int32_t iter = 0;
1,080✔
319
  while ((pIte = tSimpleHashIterate(pHashMap, pIte, &iter)) != NULL) {
1,435✔
320
    SWinKey*     pKey = tSimpleHashGetKey(pIte, NULL);
355✔
321
    uint64_t     groupId = pKey->groupId;
355✔
322
    TSKEY        ts = pKey->ts;
355✔
323
    SRowBuffPos* pPos = *(SRowBuffPos**)pIte;
355✔
324
    if (!pPos->beUpdated) {
355✔
325
      continue;
44✔
326
    }
327
    pPos->beUpdated = false;
311✔
328
    int32_t code = saveWinResultInfo(ts, groupId, pPos, resWins);
311✔
329
    if (code != TSDB_CODE_SUCCESS) {
311!
UNCOV
330
      return code;
×
331
    }
332
  }
333
  return TSDB_CODE_SUCCESS;
1,081✔
334
}
335

336
static int32_t closeStreamIntervalWindow(SSHashObj* pHashMap, STimeWindowAggSupp* pTwSup, SInterval* pInterval,
32,911✔
337
                                         SHashObj* pPullDataMap, SSHashObj* closeWins, SArray* pDelWins,
338
                                         SOperatorInfo* pOperator) {
339
  qDebug("===stream===close interval window");
32,911✔
340
  int32_t                      code = TSDB_CODE_SUCCESS;
32,911✔
341
  int32_t                      lino = 0;
32,911✔
342
  void*                        pIte = NULL;
32,911✔
343
  int32_t                      iter = 0;
32,911✔
344
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
32,911✔
345
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
32,911✔
346
  int32_t                      delSize = taosArrayGetSize(pDelWins);
32,911✔
347
  while ((pIte = tSimpleHashIterate(pHashMap, pIte, &iter)) != NULL) {
42,167✔
348
    void*    key = tSimpleHashGetKey(pIte, NULL);
9,255!
349
    SWinKey* pWinKey = (SWinKey*)key;
9,255✔
350
    if (delSize > 0) {
9,255✔
351
      int32_t index = binarySearchCom(pDelWins, delSize, pWinKey, TSDB_ORDER_DESC, compareWinKey);
221✔
352
      if (index >= 0 && 0 == compareWinKey(pWinKey, pDelWins, index)) {
221✔
353
        taosArrayRemove(pDelWins, index);
130✔
354
        delSize = taosArrayGetSize(pDelWins);
130✔
355
      }
356
    }
357

358
    void*       chIds = taosHashGet(pPullDataMap, pWinKey, sizeof(SWinKey));
9,255✔
359
    STimeWindow win = {
18,509✔
360
        .skey = pWinKey->ts,
9,254✔
361
        .ekey = taosTimeAdd(win.skey, pInterval->interval, pInterval->intervalUnit, pInterval->precision) - 1,
9,254✔
362
    };
363
    if (isCloseWindow(&win, pTwSup)) {
9,255✔
364
      if (chIds && pPullDataMap) {
3,163!
UNCOV
365
        SArray* chAy = *(SArray**)chIds;
×
UNCOV
366
        int32_t size = taosArrayGetSize(chAy);
×
UNCOV
367
        qDebug("===stream===window %" PRId64 " wait child size:%d", pWinKey->ts, size);
×
368
        for (int32_t i = 0; i < size; i++) {
×
369
          qDebug("===stream===window %" PRId64 " wait child id:%d", pWinKey->ts, *(int32_t*)taosArrayGet(chAy, i));
×
370
        }
371
        continue;
×
372
      } else if (pPullDataMap) {
3,163✔
373
        qDebug("===stream===close window %" PRId64, pWinKey->ts);
1,570✔
374
      }
375

376
      if (pTwSup->calTrigger == STREAM_TRIGGER_WINDOW_CLOSE) {
3,163!
377
        code = saveWinResult(pWinKey, *(SRowBuffPos**)pIte, closeWins);
3,163✔
378
        QUERY_CHECK_CODE(code, lino, _end);
3,163!
379
      }
380
      int32_t tmpRes = tSimpleHashIterateRemove(pHashMap, pWinKey, sizeof(SWinKey), &pIte, &iter);
3,163✔
381
      qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
3,163✔
382
    }
383
  }
384

385
_end:
32,908✔
386
  if (code != TSDB_CODE_SUCCESS) {
32,908!
UNCOV
387
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
388
  }
389
  return code;
32,911✔
390
}
391

392
STimeWindow getFinalTimeWindow(int64_t ts, SInterval* pInterval) {
319,057✔
393
  STimeWindow w = {.skey = ts, .ekey = INT64_MAX};
319,057✔
394
  w.ekey = taosTimeAdd(w.skey, pInterval->interval, pInterval->intervalUnit, pInterval->precision) - 1;
319,057✔
395
  return w;
319,057✔
396
}
397

398
static void doBuildDeleteResult(SStreamIntervalOperatorInfo* pInfo, SArray* pWins, int32_t* index,
179,426✔
399
                                SSDataBlock* pBlock) {
400
  doBuildDeleteResultImpl(&pInfo->stateStore, pInfo->pState, pWins, index, pBlock);
179,426✔
401
}
179,428✔
402

403
void doBuildDeleteResultImpl(SStateStore* pAPI, SStreamState* pState, SArray* pWins, int32_t* index,
180,026✔
404
                             SSDataBlock* pBlock) {
405
  int32_t code = TSDB_CODE_SUCCESS;
180,026✔
406
  int32_t lino = 0;
180,026✔
407
  blockDataCleanup(pBlock);
180,026✔
408
  int32_t size = taosArrayGetSize(pWins);
180,029✔
409
  if (*index == size) {
180,029✔
410
    *index = 0;
179,286✔
411
    taosArrayClear(pWins);
179,286✔
412
    goto _end;
179,286✔
413
  }
414
  code = blockDataEnsureCapacity(pBlock, size - *index);
743✔
415
  QUERY_CHECK_CODE(code, lino, _end);
743!
416

417
  uint64_t uid = 0;
743✔
418
  for (int32_t i = *index; i < size; i++) {
2,336✔
419
    SWinKey* pWin = taosArrayGet(pWins, i);
1,593✔
420
    void*    tbname = NULL;
1,593✔
421
    int32_t  winCode = TSDB_CODE_SUCCESS;
1,593✔
422
    code = pAPI->streamStateGetParName(pState, pWin->groupId, &tbname, false, &winCode);
1,593✔
423
    QUERY_CHECK_CODE(code, lino, _end);
1,593!
424

425
    if (winCode != TSDB_CODE_SUCCESS) {
1,593✔
426
      code = appendDataToSpecialBlock(pBlock, &pWin->ts, &pWin->ts, &uid, &pWin->groupId, NULL);
1,079✔
427
      QUERY_CHECK_CODE(code, lino, _end);
1,079!
428
    } else {
429
      QUERY_CHECK_CONDITION((tbname), code, lino, _end, TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR);
514!
430
      char parTbName[VARSTR_HEADER_SIZE + TSDB_TABLE_NAME_LEN];
431
      STR_WITH_MAXSIZE_TO_VARSTR(parTbName, tbname, sizeof(parTbName));
514✔
432
      code = appendDataToSpecialBlock(pBlock, &pWin->ts, &pWin->ts, &uid, &pWin->groupId, parTbName);
514✔
433
      QUERY_CHECK_CODE(code, lino, _end);
514!
434
    }
435
    pAPI->streamStateFreeVal(tbname);
1,593✔
436
    (*index)++;
1,593✔
437
  }
438

439
_end:
743✔
440
  if (code != TSDB_CODE_SUCCESS) {
180,029!
UNCOV
441
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
442
  }
443
}
180,029✔
444

445
void destroyFlusedPos(void* pRes) {
790,658✔
446
  SRowBuffPos* pPos = (SRowBuffPos*)pRes;
790,658✔
447
  if (!pPos->needFree && !pPos->pRowBuff) {
790,658!
UNCOV
448
    taosMemoryFreeClear(pPos->pKey);
×
449
    taosMemoryFree(pPos);
×
450
  }
451
}
790,658✔
452

453
void destroyFlusedppPos(void* ppRes) {
×
454
  void* pRes = *(void**)ppRes;
×
UNCOV
455
  destroyFlusedPos(pRes);
×
UNCOV
456
}
×
457

458
void clearGroupResInfo(SGroupResInfo* pGroupResInfo) {
6,105✔
459
  if (pGroupResInfo->freeItem) {
6,105✔
460
    int32_t size = taosArrayGetSize(pGroupResInfo->pRows);
3,581✔
461
    for (int32_t i = pGroupResInfo->index; i < size; i++) {
794,239✔
462
      void* pPos = taosArrayGetP(pGroupResInfo->pRows, i);
790,658✔
463
      destroyFlusedPos(pPos);
790,658✔
464
    }
465
    pGroupResInfo->freeItem = false;
3,581✔
466
  }
467
  taosArrayDestroy(pGroupResInfo->pRows);
6,105✔
468
  pGroupResInfo->pRows = NULL;
6,105✔
469
  pGroupResInfo->index = 0;
6,105✔
470
}
6,105✔
471

472
void destroyStreamFinalIntervalOperatorInfo(void* param) {
3,967✔
473
  if (param == NULL) {
3,967!
UNCOV
474
    return;
×
475
  }
476
  SStreamIntervalOperatorInfo* pInfo = (SStreamIntervalOperatorInfo*)param;
3,967✔
477
  cleanupBasicInfo(&pInfo->binfo);
3,967✔
478
  if (pInfo->pOperator) {
3,967!
479
    cleanupResultInfo(pInfo->pOperator->pTaskInfo, &pInfo->pOperator->exprSupp, &pInfo->groupResInfo, &pInfo->aggSup,
3,967✔
480
                      false);
481
    pInfo->pOperator = NULL;
3,968✔
482
  }
483
  cleanupAggSup(&pInfo->aggSup);
3,968✔
484
  clearGroupResInfo(&pInfo->groupResInfo);
3,968✔
485
  taosArrayDestroyP(pInfo->pUpdated, destroyFlusedPos);
3,968✔
486
  pInfo->pUpdated = NULL;
3,968✔
487

488
  // it should be empty.
489
  void* pIte = NULL;
3,968✔
490
  while ((pIte = taosHashIterate(pInfo->pPullDataMap, pIte)) != NULL) {
3,969✔
491
    taosArrayDestroy(*(void**)pIte);
1✔
492
  }
493
  taosHashCleanup(pInfo->pPullDataMap);
3,968✔
494
  taosHashCleanup(pInfo->pFinalPullDataMap);
3,968✔
495
  taosArrayDestroy(pInfo->pPullWins);
3,968✔
496
  blockDataDestroy(pInfo->pPullDataRes);
3,968✔
497
  taosArrayDestroy(pInfo->pDelWins);
3,968✔
498
  blockDataDestroy(pInfo->pDelRes);
3,968✔
499
  blockDataDestroy(pInfo->pMidRetriveRes);
3,968✔
500
  blockDataDestroy(pInfo->pMidPulloverRes);
3,968✔
501
  if (pInfo->pUpdatedMap != NULL) {
3,968!
502
    // free flushed pos
503
    tSimpleHashSetFreeFp(pInfo->pUpdatedMap, destroyFlusedppPos);
×
UNCOV
504
    tSimpleHashCleanup(pInfo->pUpdatedMap);
×
UNCOV
505
    pInfo->pUpdatedMap = NULL;
×
506
  }
507

508
  if (pInfo->stateStore.streamFileStateDestroy != NULL) {
3,968!
509
    pInfo->stateStore.streamFileStateDestroy(pInfo->pState->pFileState);
3,968✔
510
  }
511
  taosArrayDestroy(pInfo->pMidPullDatas);
3,968✔
512

513
  if (pInfo->pState != NULL && pInfo->pState->dump == 1) {
3,968!
514
    taosMemoryFreeClear(pInfo->pState->pTdbState->pOwner);
934!
515
    taosMemoryFreeClear(pInfo->pState->pTdbState);
934!
516
  }
517
  taosMemoryFreeClear(pInfo->pState);
3,968!
518

519
  nodesDestroyNode((SNode*)pInfo->pPhyNode);
3,968✔
520
  colDataDestroy(&pInfo->twAggSup.timeWindowData);
3,968✔
521
  cleanupExprSupp(&pInfo->scalarSupp);
3,968✔
522
  tSimpleHashCleanup(pInfo->pDeletedMap);
3,968✔
523

524
  blockDataDestroy(pInfo->pCheckpointRes);
3,968✔
525

526
  taosMemoryFreeClear(param);
3,968!
527
}
528

529
#ifdef BUILD_NO_CALL
530
static bool allInvertible(SqlFunctionCtx* pFCtx, int32_t numOfCols) {
531
  for (int32_t i = 0; i < numOfCols; i++) {
532
    if (fmIsUserDefinedFunc(pFCtx[i].functionId) || !fmIsInvertible(pFCtx[i].functionId)) {
533
      return false;
534
    }
535
  }
536
  return true;
537
}
538
#endif
539

540
void reloadFromDownStream(SOperatorInfo* downstream, SStreamIntervalOperatorInfo* pInfo) {
1,358✔
541
  SStateStore* pAPI = &downstream->pTaskInfo->storageAPI.stateStore;
1,358✔
542

543
  if (downstream->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_SCAN) {
1,358✔
544
    reloadFromDownStream(downstream->pDownstream[0], pInfo);
64✔
545
    return;
64✔
546
  }
547

548
  SStreamScanInfo* pScanInfo = downstream->info;
1,294✔
549
  pInfo->pUpdateInfo = pScanInfo->pUpdateInfo;
1,294✔
550
}
551

552
bool hasSrcPrimaryKeyCol(SSteamOpBasicInfo* pInfo) { return pInfo->primaryPkIndex != -1; }
13,274,673✔
553

554
int32_t initIntervalDownStream(SOperatorInfo* downstream, uint16_t type, SStreamIntervalOperatorInfo* pInfo,
4,073✔
555
                               struct SSteamOpBasicInfo* pBasic) {
556
  int32_t        code = TSDB_CODE_SUCCESS;
4,073✔
557
  int32_t        lino = 0;
4,073✔
558
  SStateStore*   pAPI = &downstream->pTaskInfo->storageAPI.stateStore;
4,073✔
559
  SExecTaskInfo* pTaskInfo = downstream->pTaskInfo;
4,073✔
560

561
  if (downstream->operatorType == QUERY_NODE_PHYSICAL_PLAN_STREAM_PARTITION) {
4,073✔
562
    SStreamPartitionOperatorInfo* pScanInfo = downstream->info;
252✔
563
    pBasic->primaryPkIndex = pScanInfo->basic.primaryPkIndex;
252✔
564
  }
565

566
  if (downstream->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_SCAN) {
4,073✔
567
    return initIntervalDownStream(downstream->pDownstream[0], type, pInfo, pBasic);
252✔
568
  }
569

570
  SStreamScanInfo* pScanInfo = downstream->info;
3,821✔
571
  pScanInfo->windowSup.parentType = type;
3,821✔
572
  pScanInfo->windowSup.pIntervalAggSup = &pInfo->aggSup;
3,821✔
573
  if (!pScanInfo->pUpdateInfo) {
3,821✔
574
    code = pAPI->updateInfoInitP(&pInfo->interval, pInfo->twAggSup.waterMark, pScanInfo->igCheckUpdate,
3,558✔
575
                                 pScanInfo->pkColType, pScanInfo->pkColLen, &pScanInfo->pUpdateInfo);
3,558✔
576
    QUERY_CHECK_CODE(code, lino, _end);
3,558!
577
  }
578

579
  pScanInfo->interval = pInfo->interval;
3,821✔
580
  pScanInfo->twAggSup = pInfo->twAggSup;
3,821✔
581
  pScanInfo->pState = pInfo->pState;
3,821✔
582
  pInfo->pUpdateInfo = pScanInfo->pUpdateInfo;
3,821✔
583
  if (!hasSrcPrimaryKeyCol(pBasic)) {
3,821!
584
    pBasic->primaryPkIndex = pScanInfo->basic.primaryPkIndex;
3,822✔
585
  }
586

587
_end:
×
588
  if (code != TSDB_CODE_SUCCESS) {
3,822!
UNCOV
589
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
590
  }
591
  return code;
3,822✔
592
}
593

594
int32_t compactFunctions(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx, int32_t numOfOutput,
46✔
595
                         SExecTaskInfo* pTaskInfo, SColumnInfoData* pTimeWindowData) {
596
  int32_t code = TSDB_CODE_SUCCESS;
46✔
597
  int32_t lino = 0;
46✔
598
  for (int32_t k = 0; k < numOfOutput; ++k) {
231✔
599
    if (fmIsWindowPseudoColumnFunc(pDestCtx[k].functionId)) {
187✔
600
      if (!pTimeWindowData) {
50!
UNCOV
601
        continue;
×
602
      }
603

604
      SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(&pDestCtx[k]);
50✔
605
      char*                p = GET_ROWCELL_INTERBUF(pEntryInfo);
50✔
606
      SColumnInfoData      idata = {0};
50✔
607
      idata.info.type = TSDB_DATA_TYPE_BIGINT;
50✔
608
      idata.info.bytes = tDataTypes[TSDB_DATA_TYPE_BIGINT].bytes;
50✔
609
      idata.pData = p;
50✔
610

611
      SScalarParam out = {.columnData = &idata};
50✔
612
      SScalarParam tw = {.numOfRows = 5, .columnData = pTimeWindowData};
50✔
613
      code = pDestCtx[k].sfp.process(&tw, 1, &out);
50✔
614
      QUERY_CHECK_CODE(code, lino, _end);
50!
615

616
      pEntryInfo->numOfRes = 1;
50✔
617
    } else if (functionNeedToExecute(&pDestCtx[k]) && pDestCtx[k].fpSet.combine != NULL) {
137!
618
      code = pDestCtx[k].fpSet.combine(&pDestCtx[k], &pSourceCtx[k]);
135✔
619
      QUERY_CHECK_CODE(code, lino, _end);
135!
620
    } else if (pDestCtx[k].fpSet.combine == NULL) {
2!
621
      char* funName = fmGetFuncName(pDestCtx[k].functionId);
2✔
622
      qError("%s error, combine funcion for %s is not implemented", GET_TASKID(pTaskInfo), funName);
2!
623
      taosMemoryFreeClear(funName);
2!
624
      code = TSDB_CODE_FAILED;
2✔
625
      QUERY_CHECK_CODE(code, lino, _end);
2!
626
    }
627
  }
628

629
_end:
44✔
630
  if (code != TSDB_CODE_SUCCESS) {
46✔
631
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
2!
632
  }
633
  return code;
46✔
634
}
635

636
bool hasIntervalWindow(void* pState, SWinKey* pKey, SStateStore* pStore) {
26✔
637
  return pStore->streamStateCheck(pState, pKey);
26✔
638
}
639

640
int32_t setIntervalOutputBuf(void* pState, STimeWindow* win, SRowBuffPos** pResult, int64_t groupId,
12,714,373✔
641
                             SqlFunctionCtx* pCtx, int32_t numOfOutput, int32_t* rowEntryInfoOffset,
642
                             SAggSupporter* pAggSup, SStateStore* pStore, int32_t* pWinCode) {
643
  int32_t code = TSDB_CODE_SUCCESS;
12,714,373✔
644
  int32_t lino = 0;
12,714,373✔
645
  SWinKey key = {.ts = win->skey, .groupId = groupId};
12,714,373✔
646
  char*   value = NULL;
12,714,373✔
647
  int32_t size = pAggSup->resultRowSize;
12,714,373✔
648

649
  code = pStore->streamStateAddIfNotExist(pState, &key, (void**)&value, &size, pWinCode);
12,714,373✔
650
  QUERY_CHECK_CODE(code, lino, _end);
12,739,585!
651

652
  *pResult = (SRowBuffPos*)value;
12,739,585✔
653
  SResultRow* res = (SResultRow*)((*pResult)->pRowBuff);
12,739,585✔
654

655
  // set time window for current result
656
  res->win = (*win);
12,739,585✔
657
  code = setResultRowInitCtx(res, pCtx, numOfOutput, rowEntryInfoOffset);
12,739,585✔
658
  QUERY_CHECK_CODE(code, lino, _end);
12,690,507!
659

660
_end:
12,690,507✔
661
  if (code != TSDB_CODE_SUCCESS) {
12,690,507!
UNCOV
662
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
663
  }
664
  return code;
12,690,525✔
665
}
666

667
bool isDeletedStreamWindow(STimeWindow* pWin, uint64_t groupId, void* pState, STimeWindowAggSupp* pTwSup,
32,200,834✔
668
                           SStateStore* pStore) {
669
  if (pTwSup->maxTs != INT64_MIN && pWin->ekey < pTwSup->maxTs - pTwSup->deleteMark) {
32,200,834✔
670
    SWinKey key = {.ts = pWin->skey, .groupId = groupId};
26✔
671
    if (!hasIntervalWindow(pState, &key, pStore)) {
26✔
672
      return true;
15✔
673
    }
674
    return false;
11✔
675
  }
676
  return false;
32,200,808✔
677
}
678

679
int32_t getNexWindowPos(SInterval* pInterval, SDataBlockInfo* pBlockInfo, TSKEY* tsCols, int32_t startPos, TSKEY eKey,
45✔
680
                        STimeWindow* pNextWin) {
681
  int32_t forwardRows =
682
      getNumOfRowsInTimeWindow(pBlockInfo, tsCols, startPos, eKey, binarySearchForKey, NULL, TSDB_ORDER_ASC);
45✔
683
  int32_t prevEndPos = forwardRows - 1 + startPos;
45✔
684
  return getNextQualifiedWindow(pInterval, pNextWin, pBlockInfo, tsCols, prevEndPos, TSDB_ORDER_ASC);
45✔
685
}
686

687
int32_t addPullWindow(SHashObj* pMap, SWinKey* pWinRes, int32_t size) {
232✔
688
  int32_t code = TSDB_CODE_SUCCESS;
232✔
689
  int32_t lino = 0;
232✔
690
  SArray* childIds = taosArrayInit(8, sizeof(int32_t));
232✔
691
  QUERY_CHECK_NULL(childIds, code, lino, _end, terrno);
232!
692
  for (int32_t i = 0; i < size; i++) {
998✔
693
    void* tmp = taosArrayPush(childIds, &i);
766✔
694
    if (!tmp) {
766!
UNCOV
695
      code = terrno;
×
UNCOV
696
      QUERY_CHECK_CODE(code, lino, _end);
×
697
    }
698
  }
699
  code = taosHashPut(pMap, pWinRes, sizeof(SWinKey), &childIds, sizeof(void*));
232✔
700
  QUERY_CHECK_CODE(code, lino, _end);
232!
701
_end:
232✔
702
  if (code != TSDB_CODE_SUCCESS) {
232!
UNCOV
703
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
704
  }
705
  return code;
232✔
706
}
707

708
static void clearStreamIntervalOperator(SStreamIntervalOperatorInfo* pInfo) {
3,267✔
709
  tSimpleHashClear(pInfo->aggSup.pResultRowHashTable);
3,267✔
710
  clearDiskbasedBuf(pInfo->aggSup.pResultBuf);
3,267✔
711
  initResultRowInfo(&pInfo->binfo.resultRowInfo);
3,267✔
712
  pInfo->aggSup.currentPageId = -1;
3,267✔
713
  pInfo->stateStore.streamStateClear(pInfo->pState);
3,267✔
714
}
3,267✔
715

716
static void clearSpecialDataBlock(SSDataBlock* pBlock) {
6,213✔
717
  if (pBlock->info.rows <= 0) {
6,213✔
718
    return;
6,049✔
719
  }
720
  blockDataCleanup(pBlock);
164✔
721
}
722

723
static void doBuildPullDataBlock(SArray* array, int32_t* pIndex, SSDataBlock* pBlock) {
6,213✔
724
  int32_t code = TSDB_CODE_SUCCESS;
6,213✔
725
  int32_t lino = 0;
6,213✔
726
  clearSpecialDataBlock(pBlock);
6,213✔
727
  int32_t size = taosArrayGetSize(array);
6,213✔
728
  if (size - (*pIndex) == 0) {
6,213✔
729
    goto _end;
6,049✔
730
  }
731
  code = blockDataEnsureCapacity(pBlock, size - (*pIndex));
164✔
732
  QUERY_CHECK_CODE(code, lino, _end);
164!
733

734
  SColumnInfoData* pStartTs = (SColumnInfoData*)taosArrayGet(pBlock->pDataBlock, START_TS_COLUMN_INDEX);
164✔
735
  SColumnInfoData* pEndTs = (SColumnInfoData*)taosArrayGet(pBlock->pDataBlock, END_TS_COLUMN_INDEX);
164✔
736
  SColumnInfoData* pGroupId = (SColumnInfoData*)taosArrayGet(pBlock->pDataBlock, GROUPID_COLUMN_INDEX);
164✔
737
  SColumnInfoData* pCalStartTs = (SColumnInfoData*)taosArrayGet(pBlock->pDataBlock, CALCULATE_START_TS_COLUMN_INDEX);
164✔
738
  SColumnInfoData* pCalEndTs = (SColumnInfoData*)taosArrayGet(pBlock->pDataBlock, CALCULATE_END_TS_COLUMN_INDEX);
164✔
739
  SColumnInfoData* pTbName = (SColumnInfoData*)taosArrayGet(pBlock->pDataBlock, TABLE_NAME_COLUMN_INDEX);
164✔
740
  SColumnInfoData* pPrimaryKey = NULL;
164✔
741
  if (taosArrayGetSize(pBlock->pDataBlock) > PRIMARY_KEY_COLUMN_INDEX) {
164!
UNCOV
742
    pPrimaryKey = (SColumnInfoData*)taosArrayGet(pBlock->pDataBlock, PRIMARY_KEY_COLUMN_INDEX);
×
743
  }
744
  for (; (*pIndex) < size; (*pIndex)++) {
387✔
745
    SPullWindowInfo* pWin = taosArrayGet(array, (*pIndex));
223✔
746
    code = colDataSetVal(pStartTs, pBlock->info.rows, (const char*)&pWin->window.skey, false);
223✔
747
    QUERY_CHECK_CODE(code, lino, _end);
223!
748

749
    code = colDataSetVal(pEndTs, pBlock->info.rows, (const char*)&pWin->window.ekey, false);
223✔
750
    QUERY_CHECK_CODE(code, lino, _end);
223!
751

752
    code = colDataSetVal(pGroupId, pBlock->info.rows, (const char*)&pWin->groupId, false);
223✔
753
    QUERY_CHECK_CODE(code, lino, _end);
223!
754

755
    code = colDataSetVal(pCalStartTs, pBlock->info.rows, (const char*)&pWin->calWin.skey, false);
223✔
756
    QUERY_CHECK_CODE(code, lino, _end);
223!
757

758
    code = colDataSetVal(pCalEndTs, pBlock->info.rows, (const char*)&pWin->calWin.ekey, false);
223✔
759
    QUERY_CHECK_CODE(code, lino, _end);
223!
760

761
    colDataSetNULL(pTbName, pBlock->info.rows);
223!
762
    if (pPrimaryKey != NULL) {
223!
UNCOV
763
      colDataSetNULL(pPrimaryKey, pBlock->info.rows);
×
764
    }
765

766
    pBlock->info.rows++;
223✔
767
  }
768
  if ((*pIndex) == size) {
164!
769
    *pIndex = 0;
164✔
770
    taosArrayClear(array);
164✔
771
  }
772
  code = blockDataUpdateTsWindow(pBlock, 0);
164✔
773
  QUERY_CHECK_CODE(code, lino, _end);
164!
774

775
_end:
164✔
776
  if (code != TSDB_CODE_SUCCESS) {
6,213!
UNCOV
777
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
778
  }
779
}
6,213✔
780

781
static int32_t processPullOver(SSDataBlock* pBlock, SHashObj* pMap, SHashObj* pFinalMap, SInterval* pInterval,
543✔
782
                               SArray* pPullWins, int32_t numOfCh, SOperatorInfo* pOperator, bool* pBeOver) {
783
  int32_t                      code = TSDB_CODE_SUCCESS;
543✔
784
  int32_t                      lino = 0;
543✔
785
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
543✔
786
  SColumnInfoData*             pStartCol = taosArrayGet(pBlock->pDataBlock, CALCULATE_START_TS_COLUMN_INDEX);
543✔
787
  TSKEY*                       tsData = (TSKEY*)pStartCol->pData;
543✔
788
  SColumnInfoData*             pEndCol = taosArrayGet(pBlock->pDataBlock, CALCULATE_END_TS_COLUMN_INDEX);
543✔
789
  TSKEY*                       tsEndData = (TSKEY*)pEndCol->pData;
543✔
790
  SColumnInfoData*             pGroupCol = taosArrayGet(pBlock->pDataBlock, GROUPID_COLUMN_INDEX);
543✔
791
  uint64_t*                    groupIdData = (uint64_t*)pGroupCol->pData;
543✔
792
  int32_t                      chId = getChildIndex(pBlock);
543✔
793
  bool                         res = false;
543✔
794
  for (int32_t i = 0; i < pBlock->info.rows; i++) {
1,288✔
795
    TSKEY winTs = tsData[i];
745✔
796
    while (winTs <= tsEndData[i]) {
1,508✔
797
      SWinKey winRes = {.ts = winTs, .groupId = groupIdData[i]};
763✔
798
      void*   chIds = taosHashGet(pMap, &winRes, sizeof(SWinKey));
763✔
799
      if (chIds) {
763!
800
        SArray* chArray = *(SArray**)chIds;
763✔
801
        int32_t index = taosArraySearchIdx(chArray, &chId, compareInt32Val, TD_EQ);
763✔
802
        if (index != -1) {
763!
803
          qDebug("===stream===retrive window %" PRId64 " delete child id %d", winRes.ts, chId);
763✔
804
          taosArrayRemove(chArray, index);
763✔
805
          if (taosArrayGetSize(chArray) == 0) {
763✔
806
            // pull data is over
807
            taosArrayDestroy(chArray);
231✔
808
            int32_t tmpRes = taosHashRemove(pMap, &winRes, sizeof(SWinKey));
231✔
809
            qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
231!
810
            res = true;
231✔
811
            qDebug("===stream===retrive pull data over.window %" PRId64, winRes.ts);
231✔
812

813
            void* pFinalCh = taosHashGet(pFinalMap, &winRes, sizeof(SWinKey));
231✔
814
            if (pFinalCh) {
231✔
815
              int32_t tmpRes = taosHashRemove(pFinalMap, &winRes, sizeof(SWinKey));
30✔
816
              qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
30!
817
              doDeleteWindow(pOperator, winRes.ts, winRes.groupId);
30✔
818
              STimeWindow     nextWin = getFinalTimeWindow(winRes.ts, pInterval);
30✔
819
              SPullWindowInfo pull = {.window = nextWin,
30✔
820
                                      .groupId = winRes.groupId,
30✔
821
                                      .calWin.skey = nextWin.skey,
30✔
822
                                      .calWin.ekey = nextWin.skey};
30✔
823
              // add pull data request
824
              qDebug("===stream===prepare final retrive for delete window:%" PRId64 ",groupId:%" PRId64 ", size:%d",
30!
825
                     winRes.ts, winRes.groupId, numOfCh);
826
              if (IS_MID_INTERVAL_OP(pOperator)) {
30!
827
                SStreamIntervalOperatorInfo* pInfo = (SStreamIntervalOperatorInfo*)pOperator->info;
×
828

829
                void* tmp = taosArrayPush(pInfo->pMidPullDatas, &winRes);
×
830
                if (!tmp) {
×
UNCOV
831
                  code = terrno;
×
UNCOV
832
                  QUERY_CHECK_CODE(code, lino, _end);
×
833
                }
834
              } else if (savePullWindow(&pull, pPullWins) == TSDB_CODE_SUCCESS) {
30!
835
                void* tmp = taosArrayPush(pInfo->pDelWins, &winRes);
30✔
836
                if (!tmp) {
30!
UNCOV
837
                  code = terrno;
×
UNCOV
838
                  QUERY_CHECK_CODE(code, lino, _end);
×
839
                }
840

841
                code = addPullWindow(pMap, &winRes, numOfCh);
30✔
842
                QUERY_CHECK_CODE(code, lino, _end);
30!
843

844
                if (pInfo->destHasPrimaryKey) {
30!
UNCOV
845
                  code = tSimpleHashPut(pInfo->pDeletedMap, &winRes, sizeof(SWinKey), NULL, 0);
×
UNCOV
846
                  QUERY_CHECK_CODE(code, lino, _end);
×
847
                }
848
                qDebug("===stream===prepare final retrive for delete %" PRId64 ", size:%d", winRes.ts, numOfCh);
30!
849
              }
850
            }
851
          }
852
        }
853
      }
854
      winTs = taosTimeAdd(winTs, pInterval->sliding, pInterval->slidingUnit, pInterval->precision);
763✔
855
    }
856
  }
857
  if (pBeOver) {
543✔
858
    *pBeOver = res;
12✔
859
  }
860

861
_end:
531✔
862
  if (code != TSDB_CODE_SUCCESS) {
543!
UNCOV
863
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
864
  }
865
  return code;
543✔
866
}
867

868
static int32_t addRetriveWindow(SArray* wins, SStreamIntervalOperatorInfo* pInfo, int32_t childId) {
204✔
869
  int32_t code = TSDB_CODE_SUCCESS;
204✔
870
  int32_t lino = 0;
204✔
871
  int32_t size = taosArrayGetSize(wins);
204✔
872
  for (int32_t i = 0; i < size; i++) {
401✔
873
    SWinKey*    winKey = taosArrayGet(wins, i);
197✔
874
    STimeWindow nextWin = getFinalTimeWindow(winKey->ts, &pInfo->interval);
197✔
875
    void*       chIds = taosHashGet(pInfo->pPullDataMap, winKey, sizeof(SWinKey));
197✔
876
    if (!chIds) {
197✔
877
      SPullWindowInfo pull = {
196✔
878
          .window = nextWin, .groupId = winKey->groupId, .calWin.skey = nextWin.skey, .calWin.ekey = nextWin.skey};
196✔
879
      // add pull data request
880
      if (savePullWindow(&pull, pInfo->pPullWins) == TSDB_CODE_SUCCESS) {
196!
881
        code = addPullWindow(pInfo->pPullDataMap, winKey, pInfo->numOfChild);
196✔
882
        QUERY_CHECK_CODE(code, lino, _end);
196!
883

884
        if (pInfo->destHasPrimaryKey) {
196!
UNCOV
885
          code = tSimpleHashPut(pInfo->pDeletedMap, winKey, sizeof(SWinKey), NULL, 0);
×
UNCOV
886
          QUERY_CHECK_CODE(code, lino, _end);
×
887
        }
888
        qDebug("===stream===prepare retrive for delete %" PRId64 ", size:%d", winKey->ts, pInfo->numOfChild);
196✔
889
      }
890
    } else {
891
      SArray* chArray = *(void**)chIds;
1✔
892
      int32_t index = taosArraySearchIdx(chArray, &childId, compareInt32Val, TD_EQ);
1✔
893
      qDebug("===stream===check final retrive %" PRId64 ",chid:%d", winKey->ts, index);
1!
894
      if (index == -1) {
1!
895
        qDebug("===stream===add final retrive %" PRId64, winKey->ts);
1!
896
        code = taosHashPut(pInfo->pFinalPullDataMap, winKey, sizeof(SWinKey), NULL, 0);
1✔
897
        QUERY_CHECK_CODE(code, lino, _end);
1!
898
      }
899
    }
900
  }
901

902
_end:
204✔
903
  if (code != TSDB_CODE_SUCCESS) {
204!
UNCOV
904
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
905
  }
906
  return code;
204✔
907
}
908

909
static void clearFunctionContext(SExprSupp* pSup) {
4,074✔
910
  for (int32_t i = 0; i < pSup->numOfExprs; i++) {
40,590✔
911
    pSup->pCtx[i].saveHandle.currentPage = -1;
36,516✔
912
  }
913
}
4,074✔
914

915
int32_t getOutputBuf(void* pState, SRowBuffPos* pPos, SResultRow** pResult, SStateStore* pStore) {
11,557,864✔
916
  return pStore->streamStateGetByPos(pState, pPos, (void**)pResult);
11,557,864✔
917
}
918

919
void buildDataBlockFromGroupRes(SOperatorInfo* pOperator, void* pState, SSDataBlock* pBlock, SExprSupp* pSup,
130,343✔
920
                                SGroupResInfo* pGroupResInfo) {
921
  int32_t         code = TSDB_CODE_SUCCESS;
130,343✔
922
  int32_t         lino = 0;
130,343✔
923
  SExecTaskInfo*  pTaskInfo = pOperator->pTaskInfo;
130,343✔
924
  SStorageAPI*    pAPI = &pOperator->pTaskInfo->storageAPI;
130,343✔
925
  SExprInfo*      pExprInfo = pSup->pExprInfo;
130,343✔
926
  int32_t         numOfExprs = pSup->numOfExprs;
130,343✔
927
  int32_t*        rowEntryOffset = pSup->rowEntryInfoOffset;
130,343✔
928
  SqlFunctionCtx* pCtx = pSup->pCtx;
130,343✔
929

930
  int32_t numOfRows = getNumOfTotalRes(pGroupResInfo);
130,343✔
931

932
  for (int32_t i = pGroupResInfo->index; i < numOfRows; i += 1) {
11,578,826✔
933
    SRowBuffPos* pPos = *(SRowBuffPos**)taosArrayGet(pGroupResInfo->pRows, i);
11,558,097✔
934
    SResultRow*  pRow = NULL;
11,558,118✔
935
    code = getOutputBuf(pState, pPos, &pRow, &pAPI->stateStore);
11,558,118✔
936
    QUERY_CHECK_CODE(code, lino, _end);
11,557,233!
937
    uint64_t groupId = ((SWinKey*)pPos->pKey)->groupId;
11,557,233✔
938
    doUpdateNumOfRows(pCtx, pRow, numOfExprs, rowEntryOffset);
11,557,233✔
939
    // no results, continue to check the next one
940
    if (pRow->numOfRows == 0) {
11,555,164!
UNCOV
941
      pGroupResInfo->index += 1;
×
UNCOV
942
      continue;
×
943
    }
944
    if (pBlock->info.id.groupId == 0) {
11,555,164✔
945
      pBlock->info.id.groupId = groupId;
707,738✔
946
      void*   tbname = NULL;
707,738✔
947
      int32_t winCode = TSDB_CODE_SUCCESS;
707,738✔
948
      code = pAPI->stateStore.streamStateGetParName(pTaskInfo->streamInfo.pState, pBlock->info.id.groupId, &tbname,
707,738✔
949
                                                    false, &winCode);
950
      QUERY_CHECK_CODE(code, lino, _end);
708,333!
951
      if (winCode != TSDB_CODE_SUCCESS) {
708,333✔
952
        pBlock->info.parTbName[0] = 0;
701,794✔
953
      } else {
954
        memcpy(pBlock->info.parTbName, tbname, TSDB_TABLE_NAME_LEN);
6,539✔
955
      }
956
      pAPI->stateStore.streamStateFreeVal(tbname);
708,333✔
957
    } else {
958
      // current value belongs to different group, it can't be packed into one datablock
959
      if (pBlock->info.id.groupId != groupId) {
10,847,426✔
960
        break;
108,161✔
961
      }
962
    }
963

964
    if (pBlock->info.rows + pRow->numOfRows > pBlock->info.capacity) {
11,448,727✔
965
      break;
1,186✔
966
    }
967
    pGroupResInfo->index += 1;
11,447,541✔
968

969
    for (int32_t j = 0; j < numOfExprs; ++j) {
80,198,363✔
970
      int32_t slotId = pExprInfo[j].base.resSchema.slotId;
68,749,880✔
971

972
      pCtx[j].resultInfo = getResultEntryInfo(pRow, j, rowEntryOffset);
68,749,880✔
973

974
      if (pCtx[j].fpSet.finalize) {
68,745,274✔
975
        int32_t tmpRes = pCtx[j].fpSet.finalize(&pCtx[j], pBlock);
45,531,925✔
976
        if (TAOS_FAILED(tmpRes)) {
45,548,565!
UNCOV
977
          qError("%s build result data block error, code %s", GET_TASKID(pTaskInfo), tstrerror(tmpRes));
×
UNCOV
978
          QUERY_CHECK_CODE(code, lino, _end);
×
979
        }
980
      } else if (strcmp(pCtx[j].pExpr->pExpr->_function.functionName, "_select_value") == 0) {
23,213,349✔
981
        // do nothing, todo refactor
982
      } else {
983
        // expand the result into multiple rows. E.g., _wstart, top(k, 20)
984
        // the _wstart needs to copy to 20 following rows, since the results of top-k expands to 20 different rows.
985
        SColumnInfoData* pColInfoData = taosArrayGet(pBlock->pDataBlock, slotId);
23,028,921✔
986
        char*            in = GET_ROWCELL_INTERBUF(pCtx[j].resultInfo);
23,022,841✔
987
        for (int32_t k = 0; k < pRow->numOfRows; ++k) {
46,043,464✔
988
          code = colDataSetVal(pColInfoData, pBlock->info.rows + k, in, pCtx[j].resultInfo->isNullRes);
23,023,120✔
989
          QUERY_CHECK_CODE(code, lino, _end);
23,020,623!
990
        }
991
      }
992
    }
993

994
    pBlock->info.rows += pRow->numOfRows;
11,448,483✔
995
  }
996

997
  pBlock->info.dataLoad = 1;
128,890✔
998
  code = blockDataUpdateTsWindow(pBlock, 0);
128,890✔
999
  QUERY_CHECK_CODE(code, lino, _end);
130,343!
1000

1001
_end:
130,343✔
1002
  if (code != TSDB_CODE_SUCCESS) {
130,343!
UNCOV
1003
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
1004
  }
1005
}
130,343✔
1006

1007
void doBuildStreamIntervalResult(SOperatorInfo* pOperator, void* pState, SSDataBlock* pBlock,
179,191✔
1008
                                 SGroupResInfo* pGroupResInfo) {
1009
  SExecTaskInfo* pTaskInfo = pOperator->pTaskInfo;
179,191✔
1010
  // set output datablock version
1011
  pBlock->info.version = pTaskInfo->version;
179,191✔
1012

1013
  blockDataCleanup(pBlock);
179,191✔
1014
  if (!hasRemainResults(pGroupResInfo)) {
179,186✔
1015
    return;
48,844✔
1016
  }
1017

1018
  // clear the existed group id
1019
  pBlock->info.id.groupId = 0;
130,343✔
1020
  buildDataBlockFromGroupRes(pOperator, pState, pBlock, &pOperator->exprSupp, pGroupResInfo);
130,343✔
1021
}
1022

1023
static int32_t getNextQualifiedFinalWindow(SInterval* pInterval, STimeWindow* pNext, SDataBlockInfo* pDataBlockInfo,
318,830✔
1024
                                           TSKEY* primaryKeys, int32_t prevPosition) {
1025
  int32_t startPos = prevPosition + 1;
318,830✔
1026
  if (startPos == pDataBlockInfo->rows) {
318,830✔
1027
    startPos = -1;
4,023✔
1028
  } else {
1029
    *pNext = getFinalTimeWindow(primaryKeys[startPos], pInterval);
314,807✔
1030
  }
1031
  return startPos;
318,830✔
1032
}
1033

1034
static int32_t doStreamIntervalAggImpl(SOperatorInfo* pOperator, SSDataBlock* pSDataBlock, uint64_t groupId,
542,729✔
1035
                                       SSHashObj* pUpdatedMap, SSHashObj* pDeletedMap) {
1036
  int32_t                      code = TSDB_CODE_SUCCESS;
542,729✔
1037
  int32_t                      lino = 0;
542,729✔
1038
  SStreamIntervalOperatorInfo* pInfo = (SStreamIntervalOperatorInfo*)pOperator->info;
542,729✔
1039
  pInfo->dataVersion = TMAX(pInfo->dataVersion, pSDataBlock->info.version);
542,729✔
1040

1041
  SResultRowInfo* pResultRowInfo = &(pInfo->binfo.resultRowInfo);
542,729✔
1042
  SExecTaskInfo*  pTaskInfo = pOperator->pTaskInfo;
542,729✔
1043
  SExprSupp*      pSup = &pOperator->exprSupp;
542,729✔
1044
  int32_t         numOfOutput = pSup->numOfExprs;
542,729✔
1045
  int32_t         step = 1;
542,729✔
1046
  TSKEY*          tsCols = NULL;
542,729✔
1047
  SRowBuffPos*    pResPos = NULL;
542,729✔
1048
  SResultRow*     pResult = NULL;
542,729✔
1049
  int32_t         forwardRows = 0;
542,729✔
1050
  int32_t         endRowId = pSDataBlock->info.rows - 1;
542,729✔
1051

1052
  SColumnInfoData* pColDataInfo = taosArrayGet(pSDataBlock->pDataBlock, pInfo->primaryTsIndex);
542,729✔
1053
  tsCols = (int64_t*)pColDataInfo->pData;
542,729✔
1054

1055
  void*            pPkVal = NULL;
542,729✔
1056
  int32_t          pkLen = 0;
542,729✔
1057
  SColumnInfoData* pPkColDataInfo = NULL;
542,729✔
1058
  if (hasSrcPrimaryKeyCol(&pInfo->basic)) {
542,729✔
1059
    pPkColDataInfo = taosArrayGet(pSDataBlock->pDataBlock, pInfo->basic.primaryPkIndex);
505,211✔
1060
  }
1061

1062
  if (pSDataBlock->info.window.skey != tsCols[0] || pSDataBlock->info.window.ekey != tsCols[endRowId]) {
542,729!
1063
    qError("table uid %" PRIu64 " data block timestamp range may not be calculated! minKey %" PRId64 ",maxKey %" PRId64,
×
1064
           pSDataBlock->info.id.uid, pSDataBlock->info.window.skey, pSDataBlock->info.window.ekey);
UNCOV
1065
    code = blockDataUpdateTsWindow(pSDataBlock, pInfo->primaryTsIndex);
×
UNCOV
1066
    QUERY_CHECK_CODE(code, lino, _end);
×
1067

1068
    // timestamp of the data is incorrect
UNCOV
1069
    if (pSDataBlock->info.window.skey <= 0 || pSDataBlock->info.window.ekey <= 0) {
×
UNCOV
1070
      qError("table uid %" PRIu64 " data block timestamp is out of range! minKey %" PRId64 ",maxKey %" PRId64,
×
1071
             pSDataBlock->info.id.uid, pSDataBlock->info.window.skey, pSDataBlock->info.window.ekey);
1072
    }
1073
  }
1074

1075
  int32_t     startPos = 0;
542,731✔
1076
  TSKEY       ts = getStartTsKey(&pSDataBlock->info.window, tsCols);
542,731✔
1077
  STimeWindow nextWin = {0};
542,731✔
1078
  if (IS_FINAL_INTERVAL_OP(pOperator)) {
542,731✔
1079
    nextWin = getFinalTimeWindow(ts, &pInfo->interval);
3,985✔
1080
  } else {
1081
    nextWin = getActiveTimeWindow(pInfo->aggSup.pResultBuf, pResultRowInfo, ts, &pInfo->interval, TSDB_ORDER_ASC);
538,746✔
1082
  }
1083
  while (1) {
12,180,283✔
1084
    bool isClosed = isCloseWindow(&nextWin, &pInfo->twAggSup);
12,723,006✔
1085
    if (hasSrcPrimaryKeyCol(&pInfo->basic) && !IS_FINAL_INTERVAL_OP(pOperator) && pInfo->ignoreExpiredData &&
12,719,896!
1086
        pSDataBlock->info.type != STREAM_PULL_DATA) {
×
UNCOV
1087
      pPkVal = colDataGetData(pPkColDataInfo, startPos);
×
UNCOV
1088
      pkLen = colDataGetRowLength(pPkColDataInfo, startPos);
×
1089
    }
1090

1091
    if ((!IS_FINAL_INTERVAL_OP(pOperator) && pInfo->ignoreExpiredData && pSDataBlock->info.type != STREAM_PULL_DATA &&
12,721,022!
1092
         checkExpiredData(&pInfo->stateStore, pInfo->pUpdateInfo, &pInfo->twAggSup, pSDataBlock->info.id.uid,
2,293✔
1093
                          nextWin.ekey, pPkVal, pkLen)) ||
12,711,219✔
1094
        !inSlidingWindow(&pInfo->interval, &nextWin, &pSDataBlock->info)) {
12,718,703!
UNCOV
1095
      startPos = getNexWindowPos(&pInfo->interval, &pSDataBlock->info, tsCols, startPos, nextWin.ekey, &nextWin);
×
1096
      if (startPos < 0) {
45✔
1097
        break;
542,732✔
1098
      }
1099
      qDebug("===stream===ignore expired data, window end ts:%" PRId64 ", maxts - wartermak:%" PRId64, nextWin.ekey,
19!
1100
             pInfo->twAggSup.maxTs - pInfo->twAggSup.waterMark);
1101
      continue;
51✔
1102
    }
1103

1104
    if (IS_FINAL_INTERVAL_OP(pOperator) && pInfo->numOfChild > 0) {
12,711,469!
1105
      bool    ignore = true;
317,536✔
1106
      SWinKey winRes = {
317,536✔
1107
          .ts = nextWin.skey,
317,536✔
1108
          .groupId = groupId,
1109
      };
1110
      void* chIds = taosHashGet(pInfo->pPullDataMap, &winRes, sizeof(SWinKey));
317,536✔
1111
      if (isDeletedStreamWindow(&nextWin, groupId, pInfo->pState, &pInfo->twAggSup, &pInfo->stateStore) && isClosed &&
317,536!
1112
          !chIds) {
×
UNCOV
1113
        SPullWindowInfo pull = {
×
1114
            .window = nextWin, .groupId = groupId, .calWin.skey = nextWin.skey, .calWin.ekey = nextWin.skey};
×
1115
        // add pull data request
1116
        if (savePullWindow(&pull, pInfo->pPullWins) == TSDB_CODE_SUCCESS) {
×
UNCOV
1117
          code = addPullWindow(pInfo->pPullDataMap, &winRes, pInfo->numOfChild);
×
1118
          QUERY_CHECK_CODE(code, lino, _end);
×
1119

1120
          if (pInfo->destHasPrimaryKey) {
×
UNCOV
1121
            code = tSimpleHashPut(pInfo->pDeletedMap, &winRes, sizeof(SWinKey), NULL, 0);
×
UNCOV
1122
            QUERY_CHECK_CODE(code, lino, _end);
×
1123
          }
1124
        }
1125
      } else {
1126
        int32_t index = -1;
317,536✔
1127
        SArray* chArray = NULL;
317,536✔
1128
        int32_t chId = 0;
317,536✔
1129
        if (chIds) {
317,536✔
1130
          chArray = *(void**)chIds;
361✔
1131
          chId = getChildIndex(pSDataBlock);
361✔
1132
          index = taosArraySearchIdx(chArray, &chId, compareInt32Val, TD_EQ);
361✔
1133
        }
1134
        if (index == -1 || pSDataBlock->info.type == STREAM_PULL_DATA) {
317,536✔
1135
          ignore = false;
317,391✔
1136
        }
1137
      }
1138

1139
      if (ignore) {
317,536✔
1140
        startPos = getNextQualifiedFinalWindow(&pInfo->interval, &nextWin, &pSDataBlock->info, tsCols, startPos);
145✔
1141
        if (startPos < 0) {
145✔
1142
          break;
113✔
1143
        }
1144
        continue;
32✔
1145
      }
1146
    }
1147

1148
    int32_t winCode = TSDB_CODE_SUCCESS;
12,711,324✔
1149
    code = setIntervalOutputBuf(pInfo->pState, &nextWin, &pResPos, groupId, pSup->pCtx, numOfOutput,
12,711,324✔
1150
                                pSup->rowEntryInfoOffset, &pInfo->aggSup, &pInfo->stateStore, &winCode);
1151
    QUERY_CHECK_CODE(code, lino, _end);
12,688,689!
1152

1153
    pResult = (SResultRow*)pResPos->pRowBuff;
12,688,689✔
1154

1155
    if (IS_FINAL_INTERVAL_OP(pOperator)) {
12,688,689✔
1156
      forwardRows = 1;
317,391✔
1157
    } else {
1158
      forwardRows = getNumOfRowsInTimeWindow(&pSDataBlock->info, tsCols, startPos, nextWin.ekey, binarySearchForKey,
12,371,298✔
1159
                                             NULL, TSDB_ORDER_ASC);
1160
    }
1161

1162
    SWinKey key = {
12,752,033✔
1163
        .ts = pResult->win.skey,
12,752,033✔
1164
        .groupId = groupId,
1165
    };
1166

1167
    if (pInfo->destHasPrimaryKey && winCode == TSDB_CODE_SUCCESS && IS_NORMAL_INTERVAL_OP(pOperator)) {
12,752,033!
UNCOV
1168
      code = tSimpleHashPut(pDeletedMap, &key, sizeof(SWinKey), NULL, 0);
×
UNCOV
1169
      QUERY_CHECK_CODE(code, lino, _end);
×
1170
    }
1171

1172
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_AT_ONCE && pUpdatedMap) {
12,752,033!
1173
      code = saveWinResult(&key, pResPos, pUpdatedMap);
12,741,006✔
1174
      QUERY_CHECK_CODE(code, lino, _end);
12,749,036!
1175
    }
1176

1177
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_WINDOW_CLOSE) {
12,760,063✔
1178
      pResPos->beUpdated = true;
9,940✔
1179
      code = tSimpleHashPut(pInfo->aggSup.pResultRowHashTable, &key, sizeof(SWinKey), &pResPos, POINTER_BYTES);
9,940✔
1180
      QUERY_CHECK_CODE(code, lino, _end);
9,941!
1181
    }
1182

1183
    updateTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &nextWin, 1);
12,760,064✔
1184
    code = applyAggFunctionOnPartialTuples(pTaskInfo, pSup->pCtx, &pInfo->twAggSup.timeWindowData, startPos,
12,754,872✔
1185
                                           forwardRows, pSDataBlock->info.rows, numOfOutput);
12,754,872✔
1186
    QUERY_CHECK_CODE(code, lino, _end);
12,743,084!
1187
    key.ts = nextWin.skey;
12,743,084✔
1188

1189
    if (pInfo->delKey.ts > key.ts) {
12,743,084✔
1190
      pInfo->delKey = key;
2,044✔
1191
    }
1192
    int32_t prevEndPos = (forwardRows - 1) * step + startPos;
12,743,084✔
1193
    if (IS_FINAL_INTERVAL_OP(pOperator)) {
12,743,084✔
1194
      startPos = getNextQualifiedFinalWindow(&pInfo->interval, &nextWin, &pSDataBlock->info, tsCols, prevEndPos);
317,391✔
1195
    } else {
1196
      startPos =
1197
          getNextQualifiedWindow(&pInfo->interval, &nextWin, &pSDataBlock->info, tsCols, prevEndPos, TSDB_ORDER_ASC);
12,425,693✔
1198
    }
1199
    if (startPos < 0) {
12,722,825✔
1200
      break;
542,593✔
1201
    }
1202
  }
1203
_end:
542,732✔
1204
  if (code != TSDB_CODE_SUCCESS) {
542,732!
UNCOV
1205
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
1206
  }
1207
  return code;
542,731✔
1208
}
1209

1210
int winPosCmprImpl(const void* pKey1, const void* pKey2) {
177,211,417✔
1211
  SRowBuffPos* pos1 = *(SRowBuffPos**)pKey1;
177,211,417✔
1212
  SRowBuffPos* pos2 = *(SRowBuffPos**)pKey2;
177,211,417✔
1213
  SWinKey*     pWin1 = (SWinKey*)pos1->pKey;
177,211,417✔
1214
  SWinKey*     pWin2 = (SWinKey*)pos2->pKey;
177,211,417✔
1215

1216
  if (pWin1->groupId > pWin2->groupId) {
177,211,417✔
1217
    return 1;
36,541,044✔
1218
  } else if (pWin1->groupId < pWin2->groupId) {
140,670,373✔
1219
    return -1;
34,624,241✔
1220
  }
1221

1222
  if (pWin1->ts > pWin2->ts) {
106,046,132✔
1223
    return 1;
53,497,379✔
1224
  } else if (pWin1->ts < pWin2->ts) {
52,548,753!
1225
    return -1;
52,865,796✔
1226
  }
1227

UNCOV
1228
  return 0;
×
1229
}
1230

1231
static void resetUnCloseWinInfo(SSHashObj* winMap) {
266✔
1232
  void*   pIte = NULL;
266✔
1233
  int32_t iter = 0;
266✔
1234
  while ((pIte = tSimpleHashIterate(winMap, pIte, &iter)) != NULL) {
624✔
1235
    SRowBuffPos* pPos = *(SRowBuffPos**)pIte;
358✔
1236
    pPos->beUsed = true;
358✔
1237
  }
1238
}
266✔
1239

1240
int32_t encodeSWinKey(void** buf, SWinKey* key) {
52✔
1241
  int32_t tlen = 0;
52✔
1242
  tlen += taosEncodeFixedI64(buf, key->ts);
52✔
1243
  tlen += taosEncodeFixedU64(buf, key->groupId);
52✔
1244
  return tlen;
52✔
1245
}
1246

1247
void* decodeSWinKey(void* buf, SWinKey* key) {
6✔
1248
  buf = taosDecodeFixedI64(buf, &key->ts);
6!
1249
  buf = taosDecodeFixedU64(buf, &key->groupId);
6!
1250
  return buf;
6✔
1251
}
1252

1253
int32_t encodeSTimeWindowAggSupp(void** buf, STimeWindowAggSupp* pTwAggSup) {
218✔
1254
  int32_t tlen = 0;
218✔
1255
  tlen += taosEncodeFixedI64(buf, pTwAggSup->minTs);
218✔
1256
  tlen += taosEncodeFixedI64(buf, pTwAggSup->maxTs);
218✔
1257
  return tlen;
218✔
1258
}
1259

1260
void* decodeSTimeWindowAggSupp(void* buf, STimeWindowAggSupp* pTwAggSup) {
28✔
1261
  buf = taosDecodeFixedI64(buf, &pTwAggSup->minTs);
28!
1262
  buf = taosDecodeFixedI64(buf, &pTwAggSup->maxTs);
28!
1263
  return buf;
28✔
1264
}
1265

1266
int32_t encodeSTimeWindow(void** buf, STimeWindow* pWin) {
4✔
1267
  int32_t tlen = 0;
4✔
1268
  tlen += taosEncodeFixedI64(buf, pWin->skey);
4✔
1269
  tlen += taosEncodeFixedI64(buf, pWin->ekey);
4✔
1270
  return tlen;
4✔
1271
}
1272

1273
void* decodeSTimeWindow(void* buf, STimeWindow* pWin) {
×
1274
  buf = taosDecodeFixedI64(buf, &pWin->skey);
×
UNCOV
1275
  buf = taosDecodeFixedI64(buf, &pWin->ekey);
×
UNCOV
1276
  return buf;
×
1277
}
1278

1279
int32_t encodeSPullWindowInfo(void** buf, SPullWindowInfo* pPullInfo) {
×
1280
  int32_t tlen = 0;
×
1281
  tlen += encodeSTimeWindow(buf, &pPullInfo->calWin);
×
1282
  tlen += taosEncodeFixedU64(buf, pPullInfo->groupId);
×
UNCOV
1283
  tlen += encodeSTimeWindow(buf, &pPullInfo->window);
×
UNCOV
1284
  return tlen;
×
1285
}
1286

1287
void* decodeSPullWindowInfo(void* buf, SPullWindowInfo* pPullInfo) {
×
1288
  buf = decodeSTimeWindow(buf, &pPullInfo->calWin);
×
1289
  buf = taosDecodeFixedU64(buf, &pPullInfo->groupId);
×
UNCOV
1290
  buf = decodeSTimeWindow(buf, &pPullInfo->window);
×
UNCOV
1291
  return buf;
×
1292
}
1293

1294
int32_t encodeSPullWindowInfoArray(void** buf, SArray* pPullInfos) {
78✔
1295
  int32_t tlen = 0;
78✔
1296
  int32_t size = taosArrayGetSize(pPullInfos);
78✔
1297
  tlen += taosEncodeFixedI32(buf, size);
78✔
1298
  for (int32_t i = 0; i < size; i++) {
78!
UNCOV
1299
    void* pItem = taosArrayGet(pPullInfos, i);
×
UNCOV
1300
    tlen += encodeSPullWindowInfo(buf, pItem);
×
1301
  }
1302
  return tlen;
78✔
1303
}
1304

1305
int32_t decodeSPullWindowInfoArray(void* buf, SArray* pPullInfos, void** ppBuf) {
14✔
1306
  int32_t code = TSDB_CODE_SUCCESS;
14✔
1307
  int32_t lino = 0;
14✔
1308
  int32_t size = 0;
14!
1309
  buf = taosDecodeFixedI32(buf, &size);
14✔
1310
  for (int32_t i = 0; i < size; i++) {
14!
1311
    SPullWindowInfo item = {0};
×
1312
    buf = decodeSPullWindowInfo(buf, &item);
×
1313
    void* tmp = taosArrayPush(pPullInfos, &item);
×
1314
    if (!tmp) {
×
UNCOV
1315
      code = terrno;
×
UNCOV
1316
      QUERY_CHECK_CODE(code, lino, _end);
×
1317
    }
1318
  }
1319
  (*ppBuf) = buf;
14✔
1320

1321
_end:
14✔
1322
  if (code != TSDB_CODE_SUCCESS) {
14!
UNCOV
1323
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
1324
  }
1325
  return code;
14✔
1326
}
1327

1328
int32_t doStreamIntervalEncodeOpState(void** buf, int32_t len, SOperatorInfo* pOperator) {
78✔
1329
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
78✔
1330
  if (!pInfo) {
78!
UNCOV
1331
    return 0;
×
1332
  }
1333

1334
  void* pData = (buf == NULL) ? NULL : *buf;
78✔
1335

1336
  // 1.pResultRowHashTable
1337
  int32_t tlen = 0;
78✔
1338
  int32_t mapSize = tSimpleHashGetSize(pInfo->aggSup.pResultRowHashTable);
78✔
1339
  tlen += taosEncodeFixedI32(buf, mapSize);
78✔
1340
  void*   pIte = NULL;
78✔
1341
  size_t  keyLen = 0;
78✔
1342
  int32_t iter = 0;
78✔
1343
  while ((pIte = tSimpleHashIterate(pInfo->aggSup.pResultRowHashTable, pIte, &iter)) != NULL) {
130✔
1344
    void* key = tSimpleHashGetKey(pIte, &keyLen);
52✔
1345
    tlen += encodeSWinKey(buf, key);
52✔
1346
  }
1347

1348
  // 2.twAggSup
1349
  tlen += encodeSTimeWindowAggSupp(buf, &pInfo->twAggSup);
78✔
1350

1351
  // 3.pPullDataMap
1352
  int32_t size = taosHashGetSize(pInfo->pPullDataMap);
78✔
1353
  tlen += taosEncodeFixedI32(buf, size);
78✔
1354
  pIte = NULL;
78✔
1355
  keyLen = 0;
78✔
1356
  while ((pIte = taosHashIterate(pInfo->pPullDataMap, pIte)) != NULL) {
78!
1357
    void* key = taosHashGetKey(pIte, &keyLen);
×
1358
    tlen += encodeSWinKey(buf, key);
×
1359
    SArray* pArray = *(SArray**)pIte;
×
1360
    int32_t chSize = taosArrayGetSize(pArray);
×
1361
    tlen += taosEncodeFixedI32(buf, chSize);
×
1362
    for (int32_t i = 0; i < chSize; i++) {
×
UNCOV
1363
      void* pChItem = taosArrayGet(pArray, i);
×
UNCOV
1364
      tlen += taosEncodeFixedI32(buf, *(int32_t*)pChItem);
×
1365
    }
1366
  }
1367

1368
  // 4.pPullWins
1369
  tlen += encodeSPullWindowInfoArray(buf, pInfo->pPullWins);
78✔
1370

1371
  // 5.dataVersion
1372
  tlen += taosEncodeFixedI64(buf, pInfo->dataVersion);
78✔
1373

1374
  // 6.checksum
1375
  if (buf) {
78✔
1376
    uint32_t cksum = taosCalcChecksum(0, pData, len - sizeof(uint32_t));
78!
1377
    tlen += taosEncodeFixedU32(buf, cksum);
39✔
1378
  } else {
1379
    tlen += sizeof(uint32_t);
39✔
1380
  }
1381

1382
  return tlen;
78✔
1383
}
1384

1385
void doStreamIntervalDecodeOpState(void* buf, int32_t len, SOperatorInfo* pOperator) {
14✔
1386
  int32_t                      code = TSDB_CODE_SUCCESS;
14✔
1387
  int32_t                      lino = 0;
14✔
1388
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
14✔
1389
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
14✔
1390
  if (!pInfo) {
14!
UNCOV
1391
    code = TSDB_CODE_FAILED;
×
UNCOV
1392
    QUERY_CHECK_CODE(code, lino, _end);
×
1393
  }
1394

1395
  // 6.checksum
1396
  int32_t dataLen = len - sizeof(uint32_t);
14✔
1397
  void*   pCksum = POINTER_SHIFT(buf, dataLen);
14✔
1398
  if (taosCheckChecksum(buf, dataLen, *(uint32_t*)pCksum) != TSDB_CODE_SUCCESS) {
28!
UNCOV
1399
    code = TSDB_CODE_FAILED;
×
UNCOV
1400
    QUERY_CHECK_CODE(code, lino, _end);
×
1401
  }
1402

1403
  // 1.pResultRowHashTable
1404
  int32_t mapSize = 0;
14✔
1405
  buf = taosDecodeFixedI32(buf, &mapSize);
14!
1406
  for (int32_t i = 0; i < mapSize; i++) {
20✔
1407
    SWinKey key = {0};
6✔
1408
    buf = decodeSWinKey(buf, &key);
6✔
1409
    SRowBuffPos* pPos = NULL;
6✔
1410
    int32_t      resSize = pInfo->aggSup.resultRowSize;
6✔
1411
    int32_t      winCode = TSDB_CODE_SUCCESS;
6✔
1412
    code = pInfo->stateStore.streamStateAddIfNotExist(pInfo->pState, &key, (void**)&pPos, &resSize, &winCode);
6✔
1413
    QUERY_CHECK_CODE(code, lino, _end);
6!
1414
    QUERY_CHECK_CONDITION((winCode == TSDB_CODE_SUCCESS), code, lino, _end, TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR);
6!
1415

1416
    code = tSimpleHashPut(pInfo->aggSup.pResultRowHashTable, &key, sizeof(SWinKey), &pPos, POINTER_BYTES);
6✔
1417
    QUERY_CHECK_CODE(code, lino, _end);
6!
1418
  }
1419

1420
  // 2.twAggSup
1421
  buf = decodeSTimeWindowAggSupp(buf, &pInfo->twAggSup);
14✔
1422

1423
  // 3.pPullDataMap
1424
  int32_t size = 0;
14✔
1425
  buf = taosDecodeFixedI32(buf, &size);
14!
1426
  for (int32_t i = 0; i < size; i++) {
14!
1427
    SWinKey key = {0};
×
1428
    SArray* pArray = taosArrayInit(0, sizeof(int32_t));
×
1429
    if (!pArray) {
×
UNCOV
1430
      code = terrno;
×
UNCOV
1431
      QUERY_CHECK_CODE(code, lino, _end);
×
1432
    }
1433

1434
    buf = decodeSWinKey(buf, &key);
×
1435
    int32_t chSize = 0;
×
1436
    buf = taosDecodeFixedI32(buf, &chSize);
×
1437
    for (int32_t i = 0; i < chSize; i++) {
×
1438
      int32_t chId = 0;
×
1439
      buf = taosDecodeFixedI32(buf, &chId);
×
1440
      void* tmp = taosArrayPush(pArray, &chId);
×
1441
      if (!tmp) {
×
UNCOV
1442
        code = terrno;
×
UNCOV
1443
        QUERY_CHECK_CODE(code, lino, _end);
×
1444
      }
1445
    }
UNCOV
1446
    code = taosHashPut(pInfo->pPullDataMap, &key, sizeof(SWinKey), &pArray, POINTER_BYTES);
×
UNCOV
1447
    QUERY_CHECK_CODE(code, lino, _end);
×
1448
  }
1449

1450
  // 4.pPullWins
1451
  code = decodeSPullWindowInfoArray(buf, pInfo->pPullWins, &buf);
14✔
1452
  QUERY_CHECK_CODE(code, lino, _end);
14!
1453

1454
  // 5.dataVersion
1455
  buf = taosDecodeFixedI64(buf, &pInfo->dataVersion);
28!
1456

1457
_end:
14✔
1458
  if (code != TSDB_CODE_SUCCESS) {
14!
UNCOV
1459
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
1460
  }
1461
}
14✔
1462

1463
void doStreamIntervalSaveCheckpoint(SOperatorInfo* pOperator) {
2,114✔
1464
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
2,114✔
1465
  if (needSaveStreamOperatorInfo(&pInfo->basic)) {
2,114✔
1466
    int32_t len = doStreamIntervalEncodeOpState(NULL, 0, pOperator);
39✔
1467
    void*   buf = taosMemoryCalloc(1, len);
39✔
1468
    if (!buf) {
39!
UNCOV
1469
      qError("%s failed at line %d since %s", __func__, __LINE__, tstrerror(TSDB_CODE_OUT_OF_MEMORY));
×
UNCOV
1470
      return;
×
1471
    }
1472
    void* pBuf = buf;
39✔
1473
    len = doStreamIntervalEncodeOpState(&pBuf, len, pOperator);
39✔
1474
    pInfo->stateStore.streamStateSaveInfo(pInfo->pState, STREAM_INTERVAL_OP_CHECKPOINT_NAME,
39✔
1475
                                          strlen(STREAM_INTERVAL_OP_CHECKPOINT_NAME), buf, len);
1476
    taosMemoryFree(buf);
39✔
1477
    saveStreamOperatorStateComplete(&pInfo->basic);
39✔
1478
  }
1479
}
1480

UNCOV
1481
int32_t copyIntervalDeleteKey(SSHashObj* pMap, SArray* pWins) {
×
UNCOV
1482
  int32_t code = TSDB_CODE_SUCCESS;
×
UNCOV
1483
  int32_t lino = 0;
×
UNCOV
1484
  void*   pIte = NULL;
×
UNCOV
1485
  int32_t iter = 0;
×
UNCOV
1486
  while ((pIte = tSimpleHashIterate(pMap, pIte, &iter)) != NULL) {
×
UNCOV
1487
    void* pKey = tSimpleHashGetKey(pIte, NULL);
×
1488
    void* tmp = taosArrayPush(pWins, pKey);
×
1489
    if (!tmp) {
×
UNCOV
1490
      code = terrno;
×
UNCOV
1491
      QUERY_CHECK_CODE(code, lino, _end);
×
1492
    }
1493
  }
UNCOV
1494
  tSimpleHashClear(pMap);
×
1495

1496
_end:
×
UNCOV
1497
  if (code != TSDB_CODE_SUCCESS) {
×
UNCOV
1498
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
1499
  }
UNCOV
1500
  return code;
×
1501
}
1502

1503
static int32_t buildIntervalResult(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
179,296✔
1504
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
179,296✔
1505
  int32_t                      code = TSDB_CODE_SUCCESS;
179,296✔
1506
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
179,296✔
1507
  uint16_t                     opType = pOperator->operatorType;
179,296✔
1508

1509
  // check if query task is closed or not
1510
  if (isTaskKilled(pTaskInfo)) {
179,296✔
1511
    (*ppRes) = NULL;
7✔
1512
    return code;
7✔
1513
  }
1514

1515
  if (IS_FINAL_INTERVAL_OP(pOperator)) {
179,291✔
1516
    doBuildPullDataBlock(pInfo->pPullWins, &pInfo->pullIndex, pInfo->pPullDataRes);
6,213✔
1517
    if (pInfo->pPullDataRes->info.rows != 0) {
6,213✔
1518
      // process the rest of the data
1519
      printDataBlock(pInfo->pPullDataRes, getStreamOpName(opType), GET_TASKID(pTaskInfo));
164✔
1520
      (*ppRes) = pInfo->pPullDataRes;
164✔
1521
      return code;
164✔
1522
    }
1523
  }
1524

1525
  doBuildDeleteResult(pInfo, pInfo->pDelWins, &pInfo->delIndex, pInfo->pDelRes);
179,127✔
1526
  if (pInfo->pDelRes->info.rows != 0) {
179,126✔
1527
    // process the rest of the data
1528
    printDataBlock(pInfo->pDelRes, getStreamOpName(opType), GET_TASKID(pTaskInfo));
536✔
1529
    (*ppRes) = pInfo->pDelRes;
536✔
1530
    return code;
536✔
1531
  }
1532

1533
  doBuildStreamIntervalResult(pOperator, pInfo->pState, pInfo->binfo.pRes, &pInfo->groupResInfo);
178,590✔
1534
  if (pInfo->binfo.pRes->info.rows != 0) {
178,587✔
1535
    printDataBlock(pInfo->binfo.pRes, getStreamOpName(opType), GET_TASKID(pTaskInfo));
130,269✔
1536
    (*ppRes) = pInfo->binfo.pRes;
130,269✔
1537
    return code;
130,269✔
1538
  }
1539

1540
  (*ppRes) = NULL;
48,318✔
1541
  return code;
48,318✔
1542
}
1543

1544
int32_t copyUpdateResult(SSHashObj** ppWinUpdated, SArray* pUpdated, __compar_fn_t compar) {
25,440✔
1545
  int32_t code = TSDB_CODE_SUCCESS;
25,440✔
1546
  int32_t lino = 0;
25,440✔
1547
  void*   pIte = NULL;
25,440✔
1548
  int32_t iter = 0;
25,440✔
1549
  while ((pIte = tSimpleHashIterate(*ppWinUpdated, pIte, &iter)) != NULL) {
616,621✔
1550
    void* tmp = taosArrayPush(pUpdated, pIte);
591,181✔
1551
    if (!tmp) {
591,181!
UNCOV
1552
      code = terrno;
×
UNCOV
1553
      QUERY_CHECK_CODE(code, lino, _end);
×
1554
    }
1555
  }
1556
  taosArraySort(pUpdated, compar);
25,445✔
1557
  tSimpleHashCleanup(*ppWinUpdated);
25,449✔
1558
  *ppWinUpdated = NULL;
25,450✔
1559

1560
_end:
25,450✔
1561
  if (code != TSDB_CODE_SUCCESS) {
25,450!
UNCOV
1562
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
1563
  }
1564
  return code;
25,443✔
1565
}
1566

1567
static int32_t doStreamFinalIntervalAggNext(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
20,004✔
1568
  int32_t                      code = TSDB_CODE_SUCCESS;
20,004✔
1569
  int32_t                      lino = 0;
20,004✔
1570
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
20,004✔
1571
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
20,004✔
1572
  SStorageAPI*                 pAPI = &pOperator->pTaskInfo->storageAPI;
20,004✔
1573

1574
  SOperatorInfo* downstream = pOperator->pDownstream[0];
20,004✔
1575
  SExprSupp*     pSup = &pOperator->exprSupp;
20,004✔
1576

1577
  qDebug("stask:%s  %s status: %d", GET_TASKID(pTaskInfo), getStreamOpName(pOperator->operatorType), pOperator->status);
20,004✔
1578

1579
  if (pOperator->status == OP_EXEC_DONE) {
20,005!
UNCOV
1580
    (*ppRes) = NULL;
×
UNCOV
1581
    return code;
×
1582
  } else if (pOperator->status == OP_RES_TO_RETURN) {
20,005✔
1583
    SSDataBlock* resBlock = NULL;
7,340✔
1584
    code = buildIntervalResult(pOperator, &resBlock);
7,340✔
1585
    QUERY_CHECK_CODE(code, lino, _end);
7,340!
1586
    if (resBlock != NULL) {
7,340✔
1587
      (*ppRes) = resBlock;
1,729✔
1588
      return code;
7,340✔
1589
    }
1590

1591
    if (pInfo->recvGetAll) {
5,611✔
1592
      pInfo->recvGetAll = false;
83✔
1593
      resetUnCloseWinInfo(pInfo->aggSup.pResultRowHashTable);
83✔
1594
    }
1595

1596
    if (pInfo->reCkBlock) {
5,611!
1597
      pInfo->reCkBlock = false;
×
1598
      printDataBlock(pInfo->pCheckpointRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
UNCOV
1599
      (*ppRes) = pInfo->pCheckpointRes;
×
UNCOV
1600
      return code;
×
1601
    }
1602

1603
    setStreamOperatorCompleted(pOperator);
5,611✔
1604
    if (!IS_FINAL_INTERVAL_OP(pOperator)) {
5,611✔
1605
      clearFunctionContext(&pOperator->exprSupp);
3,225✔
1606
      // semi interval operator clear disk buffer
1607
      clearStreamIntervalOperator(pInfo);
3,225✔
1608
      qDebug("===stream===clear semi operator");
3,225✔
1609
    }
1610
    (*ppRes) = NULL;
5,611✔
1611
    return code;
5,611✔
1612
  } else {
1613
    if (!IS_FINAL_INTERVAL_OP(pOperator)) {
12,665✔
1614
      SSDataBlock* resBlock = NULL;
8,368✔
1615
      code = buildIntervalResult(pOperator, &resBlock);
8,368✔
1616
      QUERY_CHECK_CODE(code, lino, _end);
8,368!
1617
      if (resBlock != NULL) {
8,368!
UNCOV
1618
        (*ppRes) = resBlock;
×
UNCOV
1619
        return code;
×
1620
      }
1621

1622
      if (pInfo->recvRetrive) {
8,368!
1623
        pInfo->recvRetrive = false;
×
1624
        printDataBlock(pInfo->pMidRetriveRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
UNCOV
1625
        (*ppRes) = pInfo->pMidRetriveRes;
×
UNCOV
1626
        return code;
×
1627
      }
1628
    }
1629
  }
1630

1631
  if (!pInfo->pUpdated) {
12,665✔
1632
    pInfo->pUpdated = taosArrayInit(4096, POINTER_BYTES);
9,691✔
1633
    QUERY_CHECK_NULL(pInfo->pUpdated, code, lino, _end, terrno);
9,691!
1634
  }
1635
  if (!pInfo->pUpdatedMap) {
12,665✔
1636
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
9,692✔
1637
    pInfo->pUpdatedMap = tSimpleHashInit(4096, hashFn);
9,692✔
1638
    QUERY_CHECK_NULL(pInfo->pUpdatedMap, code, lino, _end, terrno);
9,690!
1639
  }
1640

1641
  while (1) {
24,290✔
1642
    if (isTaskKilled(pTaskInfo)) {
36,953!
UNCOV
1643
      qInfo("===stream=== %s task is killed, code %s", GET_TASKID(pTaskInfo), tstrerror(pTaskInfo->code));
×
UNCOV
1644
      (*ppRes) = NULL;
×
1645
      return code;
2,974✔
1646
    }
1647

1648
    SSDataBlock* pBlock = NULL;
36,956✔
1649
    code = downstream->fpSet.getNextFn(downstream, &pBlock);
36,956✔
1650
    QUERY_CHECK_CODE(code, lino, _end);
36,958!
1651

1652
    if (pBlock == NULL) {
36,958✔
1653
      pOperator->status = OP_RES_TO_RETURN;
9,152✔
1654
      qDebug("===stream===return data:%s. recv datablock num:%" PRIu64, getStreamOpName(pOperator->operatorType),
9,152✔
1655
             pInfo->numOfDatapack);
1656
      pInfo->numOfDatapack = 0;
9,152✔
1657
      break;
9,152✔
1658
    }
1659

1660
    pInfo->numOfDatapack++;
27,806✔
1661
    printSpecDataBlock(pBlock, getStreamOpName(pOperator->operatorType), "recv", GET_TASKID(pTaskInfo));
27,806✔
1662
    setStreamOperatorState(&pInfo->basic, pBlock->info.type);
27,806✔
1663

1664
    if (pBlock->info.type == STREAM_NORMAL || pBlock->info.type == STREAM_PULL_DATA) {
27,806✔
1665
      pInfo->binfo.pRes->info.type = pBlock->info.type;
21,487✔
1666
    } else if (pBlock->info.type == STREAM_DELETE_DATA || pBlock->info.type == STREAM_DELETE_RESULT ||
6,319✔
1667
               pBlock->info.type == STREAM_CLEAR) {
6,087✔
1668
      SArray* delWins = taosArrayInit(8, sizeof(SWinKey));
408✔
1669
      QUERY_CHECK_NULL(delWins, code, lino, _end, terrno);
408!
1670
      SHashObj* finalMap = IS_FINAL_INTERVAL_OP(pOperator) ? pInfo->pFinalPullDataMap : NULL;
408✔
1671
      code = doDeleteWindows(pOperator, &pInfo->interval, pBlock, delWins, pInfo->pUpdatedMap, finalMap);
408✔
1672
      QUERY_CHECK_CODE(code, lino, _end);
408!
1673

1674
      if (IS_FINAL_INTERVAL_OP(pOperator)) {
408✔
1675
        int32_t chId = getChildIndex(pBlock);
204✔
1676
        code = addRetriveWindow(delWins, pInfo, chId);
204✔
1677
        QUERY_CHECK_CODE(code, lino, _end);
204!
1678

1679
        if (pBlock->info.type != STREAM_CLEAR) {
204✔
1680
          void* tmp = taosArrayAddAll(pInfo->pDelWins, delWins);
116✔
1681
          if (!tmp && taosArrayGetSize(delWins) > 0) {
116!
UNCOV
1682
            code = TSDB_CODE_OUT_OF_MEMORY;
×
UNCOV
1683
            QUERY_CHECK_CODE(code, lino, _end);
×
1684
          }
1685
        }
1686
        taosArrayDestroy(delWins);
204✔
1687
        continue;
2,117✔
1688
      }
1689
      removeResults(delWins, pInfo->pUpdatedMap);
204✔
1690
      void* tmp = taosArrayAddAll(pInfo->pDelWins, delWins);
204✔
1691
      if (!tmp && taosArrayGetSize(delWins) > 0) {
204!
UNCOV
1692
        code = TSDB_CODE_OUT_OF_MEMORY;
×
UNCOV
1693
        QUERY_CHECK_CODE(code, lino, _end);
×
1694
      }
1695
      taosArrayDestroy(delWins);
204✔
1696

1697
      doBuildDeleteResult(pInfo, pInfo->pDelWins, &pInfo->delIndex, pInfo->pDelRes);
204✔
1698
      if (pInfo->pDelRes->info.rows != 0) {
204!
1699
        // process the rest of the data
1700
        printDataBlock(pInfo->pDelRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
204✔
1701
        if (pBlock->info.type == STREAM_CLEAR) {
204✔
1702
          pInfo->pDelRes->info.type = STREAM_CLEAR;
88✔
1703
        } else {
1704
          pInfo->pDelRes->info.type = STREAM_DELETE_RESULT;
116✔
1705
        }
1706
        (*ppRes) = pInfo->pDelRes;
204✔
1707
        return code;
204✔
1708
      }
1709

UNCOV
1710
      break;
×
1711
    } else if (pBlock->info.type == STREAM_GET_ALL && IS_FINAL_INTERVAL_OP(pOperator)) {
5,911!
1712
      pInfo->recvGetAll = true;
83✔
1713
      code = getAllIntervalWindow(pInfo->aggSup.pResultRowHashTable, pInfo->pUpdatedMap);
83✔
1714
      QUERY_CHECK_CODE(code, lino, _end);
83!
1715
      continue;
83✔
1716
    } else if (pBlock->info.type == STREAM_RETRIEVE) {
5,828✔
1717
      if (!IS_FINAL_INTERVAL_OP(pOperator)) {
539!
1718
        pInfo->recvRetrive = true;
539✔
1719
        code = copyDataBlock(pInfo->pMidRetriveRes, pBlock);
539✔
1720
        QUERY_CHECK_CODE(code, lino, _end);
539!
1721

1722
        pInfo->pMidRetriveRes->info.type = STREAM_MID_RETRIEVE;
539✔
1723
        code = doDeleteWindows(pOperator, &pInfo->interval, pBlock, NULL, pInfo->pUpdatedMap, NULL);
539✔
1724
        QUERY_CHECK_CODE(code, lino, _end);
539!
1725
        break;
539✔
1726
      }
UNCOV
1727
      continue;
×
1728
    } else if (pBlock->info.type == STREAM_PULL_OVER && IS_FINAL_INTERVAL_OP(pOperator)) {
5,289!
1729
      code = processPullOver(pBlock, pInfo->pPullDataMap, pInfo->pFinalPullDataMap, &pInfo->interval, pInfo->pPullWins,
531✔
1730
                             pInfo->numOfChild, pOperator, NULL);
1731
      QUERY_CHECK_CODE(code, lino, _end);
531!
1732
      continue;
531✔
1733
    } else if (pBlock->info.type == STREAM_CREATE_CHILD_TABLE) {
4,758✔
1734
      (*ppRes) = pBlock;
2,770✔
1735
      return code;
2,770✔
1736
    } else if (pBlock->info.type == STREAM_CHECKPOINT) {
1,988✔
1737
      pAPI->stateStore.streamStateCommit(pInfo->pState);
764✔
1738
      doStreamIntervalSaveCheckpoint(pOperator);
763✔
1739
      code = copyDataBlock(pInfo->pCheckpointRes, pBlock);
754✔
1740
      QUERY_CHECK_CODE(code, lino, _end);
762!
1741

1742
      continue;
762✔
1743
    } else if (IS_FINAL_INTERVAL_OP(pOperator) && pBlock->info.type == STREAM_MID_RETRIEVE) {
1,224✔
1744
      continue;
537✔
1745
    } else {
1746
      if (pBlock->info.type != STREAM_INVALID) {
687!
UNCOV
1747
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
UNCOV
1748
        QUERY_CHECK_CODE(code, lino, _end);
×
1749
      }
1750
    }
1751

1752
    if (pInfo->scalarSupp.pExprInfo != NULL) {
22,174!
1753
      SExprSupp* pExprSup = &pInfo->scalarSupp;
×
UNCOV
1754
      code = projectApplyFunctions(pExprSup->pExprInfo, pBlock, pBlock, pExprSup->pCtx, pExprSup->numOfExprs, NULL);
×
UNCOV
1755
      QUERY_CHECK_CODE(code, lino, _end);
×
1756
    }
1757
    code = setInputDataBlock(pSup, pBlock, TSDB_ORDER_ASC, MAIN_SCAN, true);
22,174✔
1758
    QUERY_CHECK_CODE(code, lino, _end);
22,174!
1759

1760
    code = doStreamIntervalAggImpl(pOperator, pBlock, pBlock->info.id.groupId, pInfo->pUpdatedMap, pInfo->pDeletedMap);
22,174✔
1761
    if (code == TSDB_CODE_STREAM_INTERNAL_ERROR) {
22,173!
1762
      code = TSDB_CODE_SUCCESS;
×
UNCOV
1763
      pOperator->status = OP_RES_TO_RETURN;
×
UNCOV
1764
      break;
×
1765
    }
1766
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.window.ekey);
22,173✔
1767
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.watermark);
22,173✔
1768
    pInfo->twAggSup.minTs = TMIN(pInfo->twAggSup.minTs, pBlock->info.window.skey);
22,173✔
1769
  }
1770

1771
  if (IS_FINAL_INTERVAL_OP(pOperator) && !pInfo->destHasPrimaryKey) {
9,691!
1772
    removeDeleteResults(pInfo->pUpdatedMap, pInfo->pDelWins);
2,913✔
1773
  }
1774
  if (IS_FINAL_INTERVAL_OP(pOperator)) {
9,691✔
1775
    code = closeStreamIntervalWindow(pInfo->aggSup.pResultRowHashTable, &pInfo->twAggSup, &pInfo->interval,
2,913✔
1776
                                     pInfo->pPullDataMap, pInfo->pUpdatedMap, pInfo->pDelWins, pOperator);
1777
    QUERY_CHECK_CODE(code, lino, _end);
2,913!
1778

1779
    if (pInfo->destHasPrimaryKey) {
2,913!
UNCOV
1780
      code = copyIntervalDeleteKey(pInfo->pDeletedMap, pInfo->pDelWins);
×
UNCOV
1781
      QUERY_CHECK_CODE(code, lino, _end);
×
1782
    }
1783
  }
1784
  pInfo->binfo.pRes->info.watermark = pInfo->twAggSup.maxTs;
9,691✔
1785

1786
  code = copyUpdateResult(&pInfo->pUpdatedMap, pInfo->pUpdated, winPosCmprImpl);
9,691✔
1787
  QUERY_CHECK_CODE(code, lino, _end);
9,689!
1788

1789
  initMultiResInfoFromArrayList(&pInfo->groupResInfo, pInfo->pUpdated);
9,689✔
1790
  pInfo->pUpdated = NULL;
9,691✔
1791
  code = blockDataEnsureCapacity(pInfo->binfo.pRes, pOperator->resultInfo.capacity);
9,691✔
1792
  QUERY_CHECK_CODE(code, lino, _end);
9,691!
1793

1794
  SSDataBlock* resBlock = NULL;
9,691✔
1795
  code = buildIntervalResult(pOperator, &resBlock);
9,691✔
1796
  QUERY_CHECK_CODE(code, lino, _end);
9,691!
1797
  if (resBlock != NULL) {
9,691✔
1798
    (*ppRes) = resBlock;
5,611✔
1799
    return code;
5,611✔
1800
  }
1801

1802
  if (pInfo->recvRetrive) {
4,080✔
1803
    pInfo->recvRetrive = false;
538✔
1804
    printDataBlock(pInfo->pMidRetriveRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
538✔
1805
    (*ppRes) = pInfo->pMidRetriveRes;
539✔
1806
    return code;
539✔
1807
  }
1808

1809
_end:
3,542✔
1810
  if (code != TSDB_CODE_SUCCESS) {
3,542!
1811
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
UNCOV
1812
    pTaskInfo->code = code;
×
UNCOV
1813
    T_LONG_JMP(pTaskInfo->env, code);
×
1814
  }
1815
  setStreamOperatorCompleted(pOperator);
3,542✔
1816
  (*ppRes) = NULL;
3,542✔
1817
  return code;
3,542✔
1818
}
1819

1820
int64_t getDeleteMark(SWindowPhysiNode* pWinPhyNode, int64_t interval) {
5,782✔
1821
  if (pWinPhyNode->deleteMark <= 0) {
5,782✔
1822
    return DEAULT_DELETE_MARK;
3,708✔
1823
  }
1824
  int64_t deleteMark = TMAX(pWinPhyNode->deleteMark, pWinPhyNode->watermark);
2,074✔
1825
  deleteMark = TMAX(deleteMark, interval);
2,074✔
1826
  return deleteMark;
2,074✔
1827
}
1828

1829
int64_t getDeleteMarkFromOption(SStreamNodeOption* pOption) {
11✔
1830
  if (pOption->deleteMark <= 0) {
11!
1831
    return DEAULT_DELETE_MARK;
11✔
1832
  }
UNCOV
1833
  int64_t deleteMark = TMAX(pOption->deleteMark, pOption->watermark);
×
UNCOV
1834
  return deleteMark;
×
1835
}
1836

1837
static TSKEY compareTs(void* pKey) {
33,985,067✔
1838
  SWinKey* pWinKey = (SWinKey*)pKey;
33,985,067✔
1839
  return pWinKey->ts;
33,985,067✔
1840
}
1841

1842
static int32_t getSelectivityBufSize(SqlFunctionCtx* pCtx) {
225,995✔
1843
  if (pCtx->subsidiaries.rowLen == 0) {
225,995!
1844
    int32_t rowLen = 0;
225,995✔
1845
    for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
226,127✔
1846
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
132✔
1847
      rowLen += pc->pExpr->base.resSchema.bytes;
132✔
1848
    }
1849

1850
    return rowLen + pCtx->subsidiaries.num * sizeof(bool);
225,995✔
1851
  } else {
UNCOV
1852
    return pCtx->subsidiaries.rowLen;
×
1853
  }
1854
}
1855

1856
static int32_t getMaxFunResSize(SExprSupp* pSup, int32_t numOfCols) {
5,798✔
1857
  int32_t size = 0;
5,798✔
1858
  for (int32_t i = 0; i < numOfCols; ++i) {
231,792✔
1859
    int32_t resSize = getSelectivityBufSize(pSup->pCtx + i);
225,995✔
1860
    size = TMAX(size, resSize);
225,994✔
1861
  }
1862
  return size;
5,797✔
1863
}
1864

1865
static void streamIntervalReleaseState(SOperatorInfo* pOperator) {
1,292✔
1866
  if (pOperator->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_SEMI_INTERVAL &&
1,292✔
1867
      pOperator->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_MID_INTERVAL) {
1,153✔
1868
    SStreamIntervalOperatorInfo* pInfo = pOperator->info;
1,144✔
1869
    int32_t                      resSize = sizeof(TSKEY);
1,144✔
1870
    pInfo->stateStore.streamStateSaveInfo(pInfo->pState, STREAM_INTERVAL_OP_STATE_NAME,
1,144✔
1871
                                          strlen(STREAM_INTERVAL_OP_STATE_NAME), &pInfo->twAggSup.maxTs, resSize);
1,144✔
1872
  }
1873
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
1,291✔
1874
  SStorageAPI*                 pAPI = &pOperator->pTaskInfo->storageAPI;
1,291✔
1875
  pAPI->stateStore.streamStateCommit(pInfo->pState);
1,291✔
1876
  SOperatorInfo* downstream = pOperator->pDownstream[0];
1,293✔
1877
  if (downstream->fpSet.releaseStreamStateFn) {
1,293!
1878
    downstream->fpSet.releaseStreamStateFn(downstream);
1,293✔
1879
  }
1880
}
1,294✔
1881

1882
void streamIntervalReloadState(SOperatorInfo* pOperator) {
1,294✔
1883
  int32_t                      code = TSDB_CODE_SUCCESS;
1,294✔
1884
  int32_t                      lino = 0;
1,294✔
1885
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
1,294✔
1886
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
1,294✔
1887
  if (pOperator->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_SEMI_INTERVAL &&
1,294✔
1888
      pOperator->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_MID_INTERVAL) {
1,154✔
1889
    int32_t size = 0;
1,144✔
1890
    void*   pBuf = NULL;
1,144✔
1891
    code = pInfo->stateStore.streamStateGetInfo(pInfo->pState, STREAM_INTERVAL_OP_STATE_NAME,
1,144✔
1892
                                                strlen(STREAM_INTERVAL_OP_STATE_NAME), &pBuf, &size);
1893
    QUERY_CHECK_CODE(code, lino, _end);
1,144!
1894

1895
    TSKEY ts = *(TSKEY*)pBuf;
1,144✔
1896
    taosMemoryFree(pBuf);
1,144✔
1897
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, ts);
1,144✔
1898
    pInfo->stateStore.streamStateReloadInfo(pInfo->pState, ts);
1,144✔
1899
  }
1900
  SOperatorInfo* downstream = pOperator->pDownstream[0];
1,294✔
1901
  if (downstream->fpSet.reloadStreamStateFn) {
1,294!
1902
    downstream->fpSet.reloadStreamStateFn(downstream);
1,294✔
1903
  }
1904
  reloadFromDownStream(downstream, pInfo);
1,294✔
1905

1906
_end:
1,294✔
1907
  if (code != TSDB_CODE_SUCCESS) {
1,294!
UNCOV
1908
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
1909
  }
1910
}
1,294✔
1911

1912
int32_t createStreamFinalIntervalOperatorInfo(SOperatorInfo* downstream, SPhysiNode* pPhyNode, SExecTaskInfo* pTaskInfo,
948✔
1913
                                              int32_t numOfChild, SReadHandle* pHandle, SOperatorInfo** pOptrInfo) {
1914
  QRY_PARAM_CHECK(pOptrInfo);
948!
1915

1916
  int32_t                      code = TSDB_CODE_SUCCESS;
948✔
1917
  int32_t                      lino = 0;
948✔
1918
  SIntervalPhysiNode*          pIntervalPhyNode = (SIntervalPhysiNode*)pPhyNode;
948✔
1919
  SStreamIntervalOperatorInfo* pInfo = taosMemoryCalloc(1, sizeof(SStreamIntervalOperatorInfo));
948✔
1920
  SOperatorInfo*               pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo));
949✔
1921
  if (pInfo == NULL || pOperator == NULL) {
949!
UNCOV
1922
    code = terrno;
×
UNCOV
1923
    QUERY_CHECK_CODE(code, lino, _error);
×
1924
  }
1925

1926
  pOperator->exprSupp.hasWindowOrGroup = true;
949✔
1927
  pOperator->pTaskInfo = pTaskInfo;
949✔
1928
  SStorageAPI* pAPI = &pTaskInfo->storageAPI;
949✔
1929

1930
  pInfo->interval = (SInterval){.interval = pIntervalPhyNode->interval,
949✔
1931
                                .sliding = pIntervalPhyNode->sliding,
949✔
1932
                                .intervalUnit = pIntervalPhyNode->intervalUnit,
949✔
1933
                                .slidingUnit = pIntervalPhyNode->slidingUnit,
949✔
1934
                                .offset = pIntervalPhyNode->offset,
949✔
1935
                                .precision = ((SColumnNode*)pIntervalPhyNode->window.pTspk)->node.resType.precision};
949✔
1936
  pInfo->twAggSup = (STimeWindowAggSupp){
949✔
1937
      .waterMark = pIntervalPhyNode->window.watermark,
949✔
1938
      .calTrigger = pIntervalPhyNode->window.triggerType,
949✔
1939
      .maxTs = INT64_MIN,
1940
      .minTs = INT64_MAX,
1941
      .deleteMark = getDeleteMark(&pIntervalPhyNode->window, pIntervalPhyNode->interval),
949✔
1942
      .deleteMarkSaved = 0,
1943
      .calTriggerSaved = 0,
1944
  };
1945
  pInfo->primaryTsIndex = ((SColumnNode*)pIntervalPhyNode->window.pTspk)->slotId;
949✔
1946
  size_t keyBufSize = sizeof(int64_t) + sizeof(int64_t) + POINTER_BYTES;
949✔
1947
  initResultSizeInfo(&pOperator->resultInfo, 4096);
949✔
1948
  if (pIntervalPhyNode->window.pExprs != NULL) {
949!
UNCOV
1949
    int32_t    numOfScalar = 0;
×
UNCOV
1950
    SExprInfo* pScalarExprInfo = NULL;
×
1951

UNCOV
1952
    code = createExprInfo(pIntervalPhyNode->window.pExprs, NULL, &pScalarExprInfo, &numOfScalar);
×
UNCOV
1953
    QUERY_CHECK_CODE(code, lino, _error);
×
1954

UNCOV
1955
    code = initExprSupp(&pInfo->scalarSupp, pScalarExprInfo, numOfScalar, &pTaskInfo->storageAPI.functionStore);
×
UNCOV
1956
    QUERY_CHECK_CODE(code, lino, _error);
×
1957
  }
1958

1959
  SSDataBlock* pResBlock = createDataBlockFromDescNode(pPhyNode->pOutputDataBlockDesc);
949✔
1960
  QUERY_CHECK_NULL(pResBlock, code, lino, _error, terrno);
949!
1961
  initBasicInfo(&pInfo->binfo, pResBlock);
949✔
1962

1963
  pInfo->pState = taosMemoryCalloc(1, sizeof(SStreamState));
949✔
1964
  QUERY_CHECK_NULL(pInfo->pState, code, lino, _error, terrno);
949!
1965
  qInfo("open state %p", pInfo->pState);
949!
1966
  pAPI->stateStore.streamStateCopyBackend(pTaskInfo->streamInfo.pState, pInfo->pState);
949✔
1967
  //*(pInfo->pState) = *(pTaskInfo->streamInfo.pState);
1968

1969
  qInfo("copy state %p to %p", pTaskInfo->streamInfo.pState, pInfo->pState);
949!
1970

1971
  pAPI->stateStore.streamStateSetNumber(pInfo->pState, -1, pInfo->primaryTsIndex);
949✔
1972

1973
  int32_t    numOfCols = 0;
949✔
1974
  SExprInfo* pExprInfo = NULL;
949✔
1975
  code = createExprInfo(pIntervalPhyNode->window.pFuncs, NULL, &pExprInfo, &numOfCols);
949✔
1976
  QUERY_CHECK_CODE(code, lino, _error);
949!
1977

1978
  code = initAggSup(&pOperator->exprSupp, &pInfo->aggSup, pExprInfo, numOfCols, keyBufSize, pTaskInfo->id.str,
949✔
1979
                    pInfo->pState, &pTaskInfo->storageAPI.functionStore);
949✔
1980
  QUERY_CHECK_CODE(code, lino, _error);
948!
1981

1982
  code = initExecTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &pTaskInfo->window);
948✔
1983
  QUERY_CHECK_CODE(code, lino, _error);
948!
1984
  initResultRowInfo(&pInfo->binfo.resultRowInfo);
948✔
1985

1986
  pInfo->numOfChild = numOfChild;
948✔
1987
  pInfo->pPhyNode = NULL;
948✔
1988
  code = nodesCloneNode((SNode*)pPhyNode, (SNode**)&pInfo->pPhyNode);
948✔
1989
  if (TSDB_CODE_SUCCESS != code) {
949!
UNCOV
1990
    goto _error;
×
1991
  }
1992

1993
  pInfo->pPullWins = taosArrayInit(8, sizeof(SPullWindowInfo));
949✔
1994
  QUERY_CHECK_NULL(pInfo->pPullWins, code, lino, _error, terrno);
949!
1995
  pInfo->pullIndex = 0;
949✔
1996
  _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
949✔
1997
  pInfo->pPullDataMap = taosHashInit(64, hashFn, true, HASH_NO_LOCK);
949✔
1998
  pInfo->pFinalPullDataMap = taosHashInit(64, hashFn, true, HASH_NO_LOCK);
949✔
1999

2000
  code = createSpecialDataBlock(STREAM_RETRIEVE, &pInfo->pPullDataRes);
949✔
2001
  QUERY_CHECK_CODE(code, lino, _error);
949!
2002

2003
  pInfo->ignoreExpiredData = pIntervalPhyNode->window.igExpired;
949✔
2004
  pInfo->ignoreExpiredDataSaved = false;
949✔
2005
  code = createSpecialDataBlock(STREAM_DELETE_RESULT, &pInfo->pDelRes);
949✔
2006
  QUERY_CHECK_CODE(code, lino, _error);
949!
2007

2008
  pInfo->delIndex = 0;
949✔
2009
  pInfo->pDelWins = taosArrayInit(4, sizeof(SWinKey));
949✔
2010
  QUERY_CHECK_NULL(pInfo->pDelWins, code, lino, _error, terrno);
949!
2011
  pInfo->delKey.ts = INT64_MAX;
949✔
2012
  pInfo->delKey.groupId = 0;
949✔
2013
  pInfo->numOfDatapack = 0;
949✔
2014
  pInfo->pUpdated = NULL;
949✔
2015
  pInfo->pUpdatedMap = NULL;
949✔
2016
  pInfo->stateStore = pTaskInfo->storageAPI.stateStore;
949✔
2017
  int32_t funResSize = getMaxFunResSize(&pOperator->exprSupp, numOfCols);
949✔
2018
  pInfo->pState->pFileState = NULL;
949✔
2019

2020
  // used for backward compatibility of function's result info
2021
  pInfo->pState->pResultRowStore.resultRowGet = getResultRowFromBuf;
949✔
2022
  pInfo->pState->pResultRowStore.resultRowPut = putResultRowToBuf;
949✔
2023
  pInfo->pState->pExprSupp = &pOperator->exprSupp;
949✔
2024
  
2025
  code =
2026
      pAPI->stateStore.streamFileStateInit(tsStreamBufferSize, sizeof(SWinKey), pInfo->aggSup.resultRowSize, funResSize,
949✔
2027
                                           compareTs, pInfo->pState, pInfo->twAggSup.deleteMark, GET_TASKID(pTaskInfo),
949✔
2028
                                           pHandle->checkpointId, STREAM_STATE_BUFF_HASH, &pInfo->pState->pFileState);
949✔
2029
  QUERY_CHECK_CODE(code, lino, _error);
948!
2030

2031
  pInfo->dataVersion = 0;
948✔
2032
  pInfo->recvGetAll = false;
948✔
2033
  pInfo->recvPullover = false;
948✔
2034
  pInfo->recvRetrive = false;
948✔
2035

2036
  code = createSpecialDataBlock(STREAM_CHECKPOINT, &pInfo->pCheckpointRes);
948✔
2037
  QUERY_CHECK_CODE(code, lino, _error);
949!
2038
  code = createSpecialDataBlock(STREAM_MID_RETRIEVE, &pInfo->pMidRetriveRes);
949✔
2039
  QUERY_CHECK_CODE(code, lino, _error);
949!
2040
  code = createSpecialDataBlock(STREAM_MID_RETRIEVE, &pInfo->pMidPulloverRes);
949✔
2041
  QUERY_CHECK_CODE(code, lino, _error);
949!
2042

2043
  pInfo->clearState = false;
949✔
2044
  pInfo->pMidPullDatas = taosArrayInit(4, sizeof(SWinKey));
949✔
2045
  QUERY_CHECK_NULL(pInfo->pMidPullDatas, code, lino, _error, terrno);
949!
2046
  pInfo->pDeletedMap = tSimpleHashInit(4096, hashFn);
949✔
2047
  QUERY_CHECK_NULL(pInfo->pDeletedMap, code, lino, _error, terrno);
949!
2048
  pInfo->destHasPrimaryKey = pIntervalPhyNode->window.destHasPrimaryKey;
949✔
2049
  pInfo->pOperator = pOperator;
949✔
2050

2051
  pOperator->operatorType = pPhyNode->type;
949✔
2052
  if (!IS_FINAL_INTERVAL_OP(pOperator) || numOfChild == 0) {
949!
2053
    pInfo->twAggSup.calTrigger = STREAM_TRIGGER_AT_ONCE;
703✔
2054
  }
2055
  pOperator->name = getStreamOpName(pOperator->operatorType);
949✔
2056
  pOperator->blocking = true;
949✔
2057
  pOperator->status = OP_NOT_OPENED;
949✔
2058
  pOperator->info = pInfo;
949✔
2059

2060
  if (pPhyNode->type == QUERY_NODE_PHYSICAL_PLAN_STREAM_MID_INTERVAL) {
949✔
2061
    pOperator->fpSet =
2062
        createOperatorFpSet(NULL, doStreamMidIntervalAggNext, NULL, destroyStreamFinalIntervalOperatorInfo,
22✔
2063
                            optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
2064
  } else {
2065
    pOperator->fpSet =
2066
        createOperatorFpSet(NULL, doStreamFinalIntervalAggNext, NULL, destroyStreamFinalIntervalOperatorInfo,
927✔
2067
                            optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
2068
  }
2069
  setOperatorStreamStateFn(pOperator, streamIntervalReleaseState, streamIntervalReloadState);
949✔
2070
  if (pPhyNode->type == QUERY_NODE_PHYSICAL_PLAN_STREAM_SEMI_INTERVAL ||
949✔
2071
      pPhyNode->type == QUERY_NODE_PHYSICAL_PLAN_STREAM_MID_INTERVAL) {
268✔
2072
    pInfo->basic.primaryPkIndex = -1;
703✔
2073
    code = initIntervalDownStream(downstream, pPhyNode->type, pInfo, &pInfo->basic);
703✔
2074
    QUERY_CHECK_CODE(code, lino, _error);
703!
2075
  }
2076
  code = appendDownstream(pOperator, &downstream, 1);
949✔
2077
  QUERY_CHECK_CODE(code, lino, _error);
949!
2078

2079
  // for stream
2080
  void*   buff = NULL;
949✔
2081
  int32_t len = 0;
949✔
2082
  int32_t res = pAPI->stateStore.streamStateGetInfo(pInfo->pState, STREAM_INTERVAL_OP_CHECKPOINT_NAME,
949✔
2083
                                                    strlen(STREAM_INTERVAL_OP_CHECKPOINT_NAME), &buff, &len);
2084
  if (res == TSDB_CODE_SUCCESS) {
949✔
2085
    doStreamIntervalDecodeOpState(buff, len, pOperator);
6✔
2086
    taosMemoryFree(buff);
6✔
2087
  }
2088

2089
  *pOptrInfo = pOperator;
949✔
2090
  return TSDB_CODE_SUCCESS;
949✔
2091

UNCOV
2092
_error:
×
UNCOV
2093
  if (pInfo != NULL) destroyStreamFinalIntervalOperatorInfo(pInfo);
×
UNCOV
2094
  destroyOperatorAndDownstreams(pOperator, &downstream, 1);
×
UNCOV
2095
  pTaskInfo->code = code;
×
UNCOV
2096
  return code;
×
2097
}
2098

2099
void destroyStreamAggSupporter(SStreamAggSupporter* pSup) {
1,712✔
2100
  tSimpleHashCleanup(pSup->pResultRows);
1,712✔
2101
  destroyDiskbasedBuf(pSup->pResultBuf);
1,712✔
2102
  blockDataDestroy(pSup->pScanBlock);
1,712✔
2103
  if (pSup->stateStore.streamFileStateDestroy != NULL) {
1,712!
2104
    pSup->stateStore.streamFileStateDestroy(pSup->pState->pFileState);
1,712✔
2105
  }
2106
  taosMemoryFreeClear(pSup->pState);
1,712!
2107
  taosMemoryFreeClear(pSup->pDummyCtx);
1,712!
2108
}
1,712✔
2109

2110
void destroyStreamSessionAggOperatorInfo(void* param) {
848✔
2111
  if (param == NULL) {
848!
UNCOV
2112
    return;
×
2113
  }
2114
  SStreamSessionAggOperatorInfo* pInfo = (SStreamSessionAggOperatorInfo*)param;
848✔
2115
  cleanupBasicInfo(&pInfo->binfo);
848✔
2116
  if (pInfo->pOperator) {
848!
2117
    cleanupResultInfoInStream(pInfo->pOperator->pTaskInfo, pInfo->streamAggSup.pState, &pInfo->pOperator->exprSupp,
848✔
2118
                              &pInfo->groupResInfo);
2119
    pInfo->pOperator = NULL;
848✔
2120
  }
2121
  destroyStreamAggSupporter(&pInfo->streamAggSup);
848✔
2122
  cleanupExprSupp(&pInfo->scalarSupp);
848✔
2123
  clearGroupResInfo(&pInfo->groupResInfo);
848✔
2124
  taosArrayDestroyP(pInfo->pUpdated, destroyFlusedPos);
848✔
2125
  pInfo->pUpdated = NULL;
848✔
2126

2127
  if (pInfo->pChildren != NULL) {
848✔
2128
    int32_t size = taosArrayGetSize(pInfo->pChildren);
34✔
2129
    for (int32_t i = 0; i < size; i++) {
143✔
2130
      SOperatorInfo* pChild = taosArrayGetP(pInfo->pChildren, i);
109✔
2131
      destroyOperator(pChild);
109✔
2132
    }
2133
    taosArrayDestroy(pInfo->pChildren);
34✔
2134
  }
2135

2136
  colDataDestroy(&pInfo->twAggSup.timeWindowData);
848✔
2137
  blockDataDestroy(pInfo->pDelRes);
848✔
2138
  blockDataDestroy(pInfo->pWinBlock);
848✔
2139
  tSimpleHashCleanup(pInfo->pStUpdated);
848✔
2140
  tSimpleHashCleanup(pInfo->pStDeleted);
848✔
2141
  cleanupGroupResInfo(&pInfo->groupResInfo);
848✔
2142

2143
  taosArrayDestroy(pInfo->historyWins);
848✔
2144
  blockDataDestroy(pInfo->pCheckpointRes);
848✔
2145
  tSimpleHashCleanup(pInfo->pPkDeleted);
848✔
2146

2147
  taosMemoryFreeClear(param);
848!
2148
}
2149

2150
int32_t initBasicInfoEx(SOptrBasicInfo* pBasicInfo, SExprSupp* pSup, SExprInfo* pExprInfo, int32_t numOfCols,
1,693✔
2151
                        SSDataBlock* pResultBlock, SFunctionStateStore* pStore) {
2152
  initBasicInfo(pBasicInfo, pResultBlock);
1,693✔
2153
  int32_t code = initExprSupp(pSup, pExprInfo, numOfCols, pStore);
1,695✔
2154
  if (code != TSDB_CODE_SUCCESS) {
1,694!
UNCOV
2155
    return code;
×
2156
  }
2157

2158
  for (int32_t i = 0; i < numOfCols; ++i) {
28,243✔
2159
    pSup->pCtx[i].saveHandle.pBuf = NULL;
26,549✔
2160
  }
2161

2162
  return TSDB_CODE_SUCCESS;
1,694✔
2163
}
2164

2165
void initDummyFunction(SqlFunctionCtx* pDummy, SqlFunctionCtx* pCtx, int32_t nums) {
1,730✔
2166
  for (int i = 0; i < nums; i++) {
28,528✔
2167
    pDummy[i].functionId = pCtx[i].functionId;
26,798✔
2168
    pDummy[i].isNotNullFunc = pCtx[i].isNotNullFunc;
26,798✔
2169
    pDummy[i].isPseudoFunc = pCtx[i].isPseudoFunc;
26,798✔
2170
    pDummy[i].fpSet.init = pCtx[i].fpSet.init;
26,798✔
2171
  }
2172
}
1,730✔
2173

2174
int32_t initDownStream(SOperatorInfo* downstream, SStreamAggSupporter* pAggSup, uint16_t type, int32_t tsColIndex,
2,218✔
2175
                       STimeWindowAggSupp* pTwSup, struct SSteamOpBasicInfo* pBasic) {
2176
  SExecTaskInfo* pTaskInfo = downstream->pTaskInfo;
2,218✔
2177
  int32_t        code = TSDB_CODE_SUCCESS;
2,218✔
2178
  int32_t        lino = 0;
2,218✔
2179
  if (downstream->operatorType == QUERY_NODE_PHYSICAL_PLAN_STREAM_PARTITION) {
2,218✔
2180
    SStreamPartitionOperatorInfo* pScanInfo = downstream->info;
632✔
2181
    pScanInfo->tsColIndex = tsColIndex;
632✔
2182
    pBasic->primaryPkIndex = pScanInfo->basic.primaryPkIndex;
632✔
2183
  }
2184

2185
  if (downstream->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_SCAN) {
2,218✔
2186
    code = initDownStream(downstream->pDownstream[0], pAggSup, type, tsColIndex, pTwSup, pBasic);
632✔
2187
    return code;
632✔
2188
  }
2189
  SStreamScanInfo* pScanInfo = downstream->info;
1,586✔
2190
  pScanInfo->windowSup = (SWindowSupporter){.pStreamAggSup = pAggSup, .gap = pAggSup->gap, .parentType = type};
1,586✔
2191
  pScanInfo->pState = pAggSup->pState;
1,586✔
2192
  if (!pScanInfo->pUpdateInfo) {
1,586✔
2193
    code = pAggSup->stateStore.updateInfoInit(60000, TSDB_TIME_PRECISION_MILLI, pTwSup->waterMark,
954✔
2194
                                              pScanInfo->igCheckUpdate, pScanInfo->pkColType, pScanInfo->pkColLen,
954✔
2195
                                              &pScanInfo->pUpdateInfo);
954✔
2196
    QUERY_CHECK_CODE(code, lino, _end);
954!
2197
  }
2198
  pScanInfo->twAggSup = *pTwSup;
1,586✔
2199
  pAggSup->pUpdateInfo = pScanInfo->pUpdateInfo;
1,586✔
2200
  if (!hasSrcPrimaryKeyCol(pBasic)) {
1,586✔
2201
    pBasic->primaryPkIndex = pScanInfo->basic.primaryPkIndex;
1,130✔
2202
  }
2203

2204
_end:
456✔
2205
  if (code != TSDB_CODE_SUCCESS) {
1,586!
UNCOV
2206
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
2207
  }
2208
  return code;
1,586✔
2209
}
2210

2211
static TSKEY sesionTs(void* pKey) {
3,181✔
2212
  SSessionKey* pWinKey = (SSessionKey*)pKey;
3,181✔
2213
  return pWinKey->win.skey;
3,181✔
2214
}
2215

2216
int32_t initStreamAggSupporter(SStreamAggSupporter* pSup, SExprSupp* pExpSup, int32_t numOfOutput, int64_t gap,
1,730✔
2217
                               SStreamState* pState, int32_t keySize, int16_t keyType, SStateStore* pStore,
2218
                               SReadHandle* pHandle, STimeWindowAggSupp* pTwAggSup, const char* taskIdStr,
2219
                               SStorageAPI* pApi, int32_t tsIndex, int8_t stateType, int32_t ratio) {
2220
  pSup->resultRowSize = (keySize + getResultRowSize(pExpSup->pCtx, numOfOutput)) * ratio;
1,730✔
2221
  int32_t lino = 0;
1,730✔
2222
  int32_t code = createSpecialDataBlock(STREAM_CLEAR, &pSup->pScanBlock);
1,730✔
2223
  QUERY_CHECK_CODE(code, lino, _end);
1,730!
2224

2225
  pSup->gap = gap;
1,730✔
2226
  pSup->stateKeySize = keySize;
1,730✔
2227
  pSup->stateKeyType = keyType;
1,730✔
2228
  pSup->pDummyCtx = (SqlFunctionCtx*)taosMemoryCalloc(numOfOutput, sizeof(SqlFunctionCtx));
1,730✔
2229
  QUERY_CHECK_NULL(pSup->pDummyCtx, code, lino, _end, terrno);
1,730!
2230

2231
  pSup->stateStore = *pStore;
1,730✔
2232
  pSup->pSessionAPI = pApi;
1,730✔
2233

2234
  initDummyFunction(pSup->pDummyCtx, pExpSup->pCtx, numOfOutput);
1,730✔
2235
  pSup->pState = taosMemoryCalloc(1, sizeof(SStreamState));
1,730✔
2236
  QUERY_CHECK_NULL(pSup->pState, code, lino, _end, terrno);
1,730!
2237

2238
  *(pSup->pState) = *pState;
1,730✔
2239
  pSup->stateStore.streamStateSetNumber(pSup->pState, -1, tsIndex);
1,730✔
2240
  int32_t funResSize = getMaxFunResSize(pExpSup, numOfOutput);
1,730✔
2241
  if (stateType != STREAM_STATE_BUFF_HASH_SORT) {
1,730✔
2242
    // used for backward compatibility of function's result info
2243
    pSup->pState->pResultRowStore.resultRowGet = getResultRowFromBuf;
1,719✔
2244
    pSup->pState->pResultRowStore.resultRowPut = putResultRowToBuf;
1,719✔
2245
    pSup->pState->pExprSupp = pExpSup;
1,719✔
2246
  }
2247

2248
  if (stateType == STREAM_STATE_BUFF_SORT) {
1,730✔
2249
  pSup->pState->pFileState = NULL;
1,695✔
2250
  code = pSup->stateStore.streamFileStateInit(tsStreamBufferSize, sizeof(SSessionKey), pSup->resultRowSize,
1,695✔
2251
                                                funResSize, sesionTs, pSup->pState, pTwAggSup->deleteMark, taskIdStr,
1,695✔
2252
                                                pHandle->checkpointId, stateType, &pSup->pState->pFileState);
1,695✔
2253
  } else if (stateType == STREAM_STATE_BUFF_HASH_SORT || stateType == STREAM_STATE_BUFF_HASH_SEARCH) {
35!
2254
    pSup->pState->pFileState = NULL;
35✔
2255
    code = pSup->stateStore.streamFileStateInit(tsStreamBufferSize, sizeof(SWinKey), pSup->resultRowSize, funResSize,
35✔
2256
                                                compareTs, pSup->pState, pTwAggSup->deleteMark, taskIdStr,
35✔
2257
                                                pHandle->checkpointId, stateType, &pSup->pState->pFileState);
35✔
2258
  }
2259
  QUERY_CHECK_CODE(code, lino, _end);
1,730!
2260

2261
  _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
1,730✔
2262
  pSup->pResultRows = tSimpleHashInit(32, hashFn);
1,730✔
2263
  QUERY_CHECK_NULL(pSup->pResultRows, code, lino, _end, terrno);
1,730!
2264

2265
  for (int32_t i = 0; i < numOfOutput; ++i) {
28,532✔
2266
    pExpSup->pCtx[i].saveHandle.pState = pSup->pState;
26,802✔
2267
  }
2268

2269
_end:
1,730✔
2270
  if (code != TSDB_CODE_SUCCESS) {
1,730!
UNCOV
2271
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
2272
  }
2273
  return code;
1,730✔
2274
}
2275

2276
bool isInTimeWindow(STimeWindow* pWin, TSKEY ts, int64_t gap) {
5,638✔
2277
  if (ts + gap >= pWin->skey && ts - gap <= pWin->ekey) {
5,638✔
2278
    return true;
4,221✔
2279
  }
2280
  return false;
1,417✔
2281
}
2282

2283
bool isInWindow(SResultWindowInfo* pWinInfo, TSKEY ts, int64_t gap) {
4,710✔
2284
  return isInTimeWindow(&pWinInfo->sessionWin.win, ts, gap);
4,710✔
2285
}
2286

2287
void getCurSessionWindow(SStreamAggSupporter* pAggSup, TSKEY startTs, TSKEY endTs, uint64_t groupId,
4,484✔
2288
                         SSessionKey* pKey) {
2289
  pKey->win.skey = startTs;
4,484✔
2290
  pKey->win.ekey = endTs;
4,484✔
2291
  pKey->groupId = groupId;
4,484✔
2292
  int32_t code = pAggSup->stateStore.streamStateSessionGetKeyByRange(pAggSup->pState, pKey, pKey);
4,484✔
2293
  if (code != TSDB_CODE_SUCCESS) {
4,485✔
2294
    SET_SESSION_WIN_KEY_INVALID(pKey);
1,249✔
2295
  }
2296
}
4,485✔
2297

UNCOV
2298
bool isInvalidSessionWin(SResultWindowInfo* pWinInfo) { return pWinInfo->sessionWin.win.skey == 0; }
×
2299

2300
bool inWinRange(STimeWindow* range, STimeWindow* cur) {
51,686✔
2301
  if (cur->skey >= range->skey && cur->ekey <= range->ekey) {
51,686!
2302
    return true;
51,715✔
2303
  }
UNCOV
2304
  return false;
×
2305
}
2306

UNCOV
2307
void clearOutputBuf(void* pState, SRowBuffPos* pPos, SStateStore* pAPI) { pAPI->streamStateClearBuff(pState, pPos); }
×
2308

2309
int32_t setSessionOutputBuf(SStreamAggSupporter* pAggSup, TSKEY startTs, TSKEY endTs, uint64_t groupId,
3,289✔
2310
                            SResultWindowInfo* pCurWin) {
2311
  int32_t code = TSDB_CODE_SUCCESS;
3,289✔
2312
  int32_t lino = 0;
3,289✔
2313
  pCurWin->sessionWin.groupId = groupId;
3,289✔
2314
  pCurWin->sessionWin.win.skey = startTs;
3,289✔
2315
  pCurWin->sessionWin.win.ekey = endTs;
3,289✔
2316
  int32_t size = pAggSup->resultRowSize;
3,289✔
2317
  int32_t winCode = TSDB_CODE_SUCCESS;
3,289✔
2318
  code = pAggSup->stateStore.streamStateSessionAddIfNotExist(pAggSup->pState, &pCurWin->sessionWin, pAggSup->gap,
3,289✔
2319
                                                             (void**)&pCurWin->pStatePos, &size, &winCode);
3,289✔
2320
  QUERY_CHECK_CODE(code, lino, _end);
3,291!
2321

2322
  if (winCode == TSDB_CODE_SUCCESS && !inWinRange(&pAggSup->winRange, &pCurWin->sessionWin.win)) {
3,291!
2323
    winCode = TSDB_CODE_FAILED;
×
UNCOV
2324
    clearOutputBuf(pAggSup->pState, pCurWin->pStatePos, &pAggSup->pSessionAPI->stateStore);
×
2325
  }
2326

2327
  if (winCode == TSDB_CODE_SUCCESS) {
3,291✔
2328
    pCurWin->isOutput = true;
1,022✔
2329
    if (pCurWin->pStatePos->needFree) {
1,022✔
2330
      pAggSup->stateStore.streamStateSessionDel(pAggSup->pState, &pCurWin->sessionWin);
138✔
2331
    }
2332
  } else {
2333
    pCurWin->sessionWin.win.skey = startTs;
2,269✔
2334
    pCurWin->sessionWin.win.ekey = endTs;
2,269✔
2335
  }
2336
  qDebug("===stream===set session window buff .start:%" PRId64 ",end:%" PRId64 ",groupid:%" PRIu64,
3,290✔
2337
         pCurWin->sessionWin.win.skey, pCurWin->sessionWin.win.ekey, pCurWin->sessionWin.groupId);
2338

2339
_end:
1,803✔
2340
  if (code != TSDB_CODE_SUCCESS) {
3,290!
UNCOV
2341
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
2342
  }
2343
  return code;
3,290✔
2344
}
2345

2346
void getSessionWinBuf(SStreamAggSupporter* pAggSup, SStreamStateCur* pCur, SResultWindowInfo* pWinInfo,
249✔
2347
                      int32_t* pWinCode) {
2348
  int32_t size = 0;
249✔
2349
  (*pWinCode) = pAggSup->stateStore.streamStateSessionGetKVByCur(pCur, &pWinInfo->sessionWin,
498✔
2350
                                                                 (void**)&pWinInfo->pStatePos, &size);
249✔
2351
  if ((*pWinCode) != TSDB_CODE_SUCCESS) {
249✔
2352
    return;
214✔
2353
  }
2354

2355
  pAggSup->stateStore.streamStateCurNext(pAggSup->pState, pCur);
35✔
2356
}
2357

2358
int32_t saveDeleteInfo(SArray* pWins, SSessionKey key) {
1,209✔
2359
  int32_t code = TSDB_CODE_SUCCESS;
1,209✔
2360
  int32_t lino = 0;
1,209✔
2361
  void*   res = taosArrayPush(pWins, &key);
1,209✔
2362
  if (!res) {
1,209!
UNCOV
2363
    code = terrno;
×
UNCOV
2364
    QUERY_CHECK_CODE(code, lino, _end);
×
2365
  }
2366

2367
_end:
1,209✔
2368
  if (code != TSDB_CODE_SUCCESS) {
1,209!
UNCOV
2369
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
2370
  }
2371
  return code;
1,209✔
2372
}
2373

2374
int32_t saveDeleteRes(SSHashObj* pStDelete, SSessionKey key) {
45✔
2375
  key.win.ekey = key.win.skey;
45✔
2376
  return tSimpleHashPut(pStDelete, &key, sizeof(SSessionKey), NULL, 0);
45✔
2377
}
2378

2379
void releaseOutputBuf(void* pState, SRowBuffPos* pPos, SStateStore* pAPI) {
7,806✔
2380
  pAPI->streamStateReleaseBuf(pState, pPos, false);
7,806✔
2381
}
7,806✔
2382

2383
void removeSessionResult(SStreamAggSupporter* pAggSup, SSHashObj* pHashMap, SSHashObj* pResMap, SSessionKey* pKey) {
50✔
2384
  int32_t     code = TSDB_CODE_SUCCESS;
50✔
2385
  int32_t     lino = 0;
50✔
2386
  SSessionKey key = {0};
50✔
2387
  getSessionHashKey(pKey, &key);
50✔
2388
  void* pVal = tSimpleHashGet(pHashMap, &key, sizeof(SSessionKey));
50✔
2389
  if (pVal) {
50✔
2390
    releaseOutputBuf(pAggSup->pState, *(void**)pVal, &pAggSup->pSessionAPI->stateStore);
4✔
2391
    int32_t tmpRes = tSimpleHashRemove(pHashMap, &key, sizeof(SSessionKey));
4✔
2392
    qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
4!
2393
  }
2394
  int32_t tmpRes = tSimpleHashRemove(pResMap, &key, sizeof(SSessionKey));
50✔
2395
  qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
50!
2396
}
50✔
2397

2398
void getSessionHashKey(const SSessionKey* pKey, SSessionKey* pHashKey) {
9,449✔
2399
  *pHashKey = *pKey;
9,449✔
2400
  pHashKey->win.ekey = pKey->win.skey;
9,449✔
2401
}
9,449✔
2402

2403
void removeSessionDeleteResults(SSHashObj* pHashMap, SArray* pWins) {
15,146✔
2404
  if (tSimpleHashGetSize(pHashMap) == 0) {
15,146✔
2405
    return;
14,101✔
2406
  }
2407
  int32_t size = taosArrayGetSize(pWins);
1,049✔
2408
  for (int32_t i = 0; i < size; i++) {
2,198✔
2409
    SResultWindowInfo* pWin = taosArrayGet(pWins, i);
1,147✔
2410
    if (!pWin) continue;
1,147!
2411
    SSessionKey key = {0};
1,147✔
2412
    getSessionHashKey(&pWin->sessionWin, &key);
1,147✔
2413
    int32_t tmpRes = tSimpleHashRemove(pHashMap, &key, sizeof(SSessionKey));
1,147✔
2414
    qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
1,147!
2415
  }
2416
}
2417

2418
void removeSessionResults(SStreamAggSupporter* pAggSup, SSHashObj* pHashMap, SArray* pWins) {
1,110✔
2419
  if (tSimpleHashGetSize(pHashMap) == 0) {
1,110✔
2420
    return;
847✔
2421
  }
2422
  int32_t size = taosArrayGetSize(pWins);
263✔
2423
  for (int32_t i = 0; i < size; i++) {
561✔
2424
    SSessionKey* pWin = taosArrayGet(pWins, i);
298✔
2425
    if (!pWin) continue;
298!
2426
    SSessionKey key = {0};
298✔
2427
    getSessionHashKey(pWin, &key);
298✔
2428
    void* pVal = tSimpleHashGet(pHashMap, &key, sizeof(SSessionKey));
298✔
2429
    if (pVal) {
298✔
2430
      releaseOutputBuf(pAggSup->pState, *(void**)pVal, &pAggSup->pSessionAPI->stateStore);
179✔
2431
      int32_t tmpRes = tSimpleHashRemove(pHashMap, &key, sizeof(SSessionKey));
179✔
2432
      qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
179!
2433
    }
2434
  }
2435
}
2436

2437
int32_t updateSessionWindowInfo(SStreamAggSupporter* pAggSup, SResultWindowInfo* pWinInfo, TSKEY* pStartTs,
3,262✔
2438
                                TSKEY* pEndTs, uint64_t groupId, int32_t rows, int32_t start, int64_t gap,
2439
                                SSHashObj* pResultRows, SSHashObj* pStUpdated, SSHashObj* pStDeleted,
2440
                                int32_t* pWinRos) {
2441
  int32_t code = TSDB_CODE_SUCCESS;
3,262✔
2442
  int32_t lino = 0;
3,262✔
2443
  for (int32_t i = start; i < rows; ++i) {
7,427✔
2444
    if (!isInWindow(pWinInfo, pStartTs[i], gap) && (!pEndTs || !isInWindow(pWinInfo, pEndTs[i], gap))) {
4,207!
2445
      (*pWinRos) = i - start;
42✔
2446
      goto _end;
42✔
2447
    }
2448
    if (pWinInfo->sessionWin.win.skey > pStartTs[i]) {
4,165✔
2449
      if (pStDeleted && pWinInfo->isOutput) {
26!
2450
        code = saveDeleteRes(pStDeleted, pWinInfo->sessionWin);
21✔
2451
        QUERY_CHECK_CODE(code, lino, _end);
21!
2452
      }
2453
      removeSessionResult(pAggSup, pStUpdated, pResultRows, &pWinInfo->sessionWin);
26✔
2454
      pWinInfo->sessionWin.win.skey = pStartTs[i];
26✔
2455
    }
2456
    pWinInfo->sessionWin.win.ekey = TMAX(pWinInfo->sessionWin.win.ekey, pStartTs[i]);
4,165✔
2457
    if (pEndTs) {
4,165!
2458
      pWinInfo->sessionWin.win.ekey = TMAX(pWinInfo->sessionWin.win.ekey, pEndTs[i]);
4,165✔
2459
    }
2460
    memcpy(pWinInfo->pStatePos->pKey, &pWinInfo->sessionWin, sizeof(SSessionKey));
4,165✔
2461
  }
2462
  (*pWinRos) = rows - start;
3,220✔
2463

2464
_end:
3,262✔
2465
  if (code != TSDB_CODE_SUCCESS) {
3,262!
UNCOV
2466
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
2467
  }
2468
  return code;
3,262✔
2469
}
2470

2471
static int32_t initSessionOutputBuf(SResultWindowInfo* pWinInfo, SResultRow** pResult, SqlFunctionCtx* pCtx,
12,107✔
2472
                                    int32_t numOfOutput, int32_t* rowEntryInfoOffset) {
2473
  *pResult = (SResultRow*)pWinInfo->pStatePos->pRowBuff;
12,107✔
2474
  // set time window for current result
2475
  (*pResult)->win = pWinInfo->sessionWin.win;
12,107✔
2476
  return setResultRowInitCtx(*pResult, pCtx, numOfOutput, rowEntryInfoOffset);
12,107✔
2477
}
2478

2479
int32_t doOneWindowAggImpl(SColumnInfoData* pTimeWindowData, SResultWindowInfo* pCurWin, SResultRow** pResult,
12,015✔
2480
                           int32_t startIndex, int32_t winRows, int32_t rows, int32_t numOutput,
2481
                           SOperatorInfo* pOperator, int64_t winDelta) {
2482
  int32_t        code = TSDB_CODE_SUCCESS;
12,015✔
2483
  int32_t        lino = 0;
12,015✔
2484
  SExprSupp*     pSup = &pOperator->exprSupp;
12,015✔
2485
  SExecTaskInfo* pTaskInfo = pOperator->pTaskInfo;
12,015✔
2486
  code = initSessionOutputBuf(pCurWin, pResult, pSup->pCtx, numOutput, pSup->rowEntryInfoOffset);
12,015✔
2487
  QUERY_CHECK_CODE(code, lino, _end);
12,012!
2488

2489
  updateTimeWindowInfo(pTimeWindowData, &pCurWin->sessionWin.win, winDelta);
12,012✔
2490
  code = applyAggFunctionOnPartialTuples(pTaskInfo, pSup->pCtx, pTimeWindowData, startIndex, winRows, rows, numOutput);
12,012✔
2491

2492
_end:
12,016✔
2493
  if (code != TSDB_CODE_SUCCESS) {
12,016!
UNCOV
2494
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
2495
  }
2496
  return code;
12,016✔
2497
}
2498

2499
void doDeleteSessionWindow(SStreamAggSupporter* pAggSup, SSessionKey* pKey) {
1,293✔
2500
  pAggSup->stateStore.streamStateSessionDel(pAggSup->pState, pKey);
1,293✔
2501
  SSessionKey hashKey = {0};
1,293✔
2502
  getSessionHashKey(pKey, &hashKey);
1,293✔
2503
  int32_t tmpRes = tSimpleHashRemove(pAggSup->pResultRows, &hashKey, sizeof(SSessionKey));
1,293✔
2504
  qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
1,293!
2505
}
1,293✔
2506

2507
void setSessionWinOutputInfo(SSHashObj* pStUpdated, SResultWindowInfo* pWinInfo) {
15,595✔
2508
  void* pVal = tSimpleHashGet(pStUpdated, &pWinInfo->sessionWin, sizeof(SSessionKey));
15,595✔
2509
  if (pVal) {
15,597✔
2510
    SResultWindowInfo* pWin = pVal;
494✔
2511
    pWinInfo->isOutput = pWin->isOutput;
494✔
2512
  }
2513
}
15,597✔
2514

2515
void getNextSessionWinInfo(SStreamAggSupporter* pAggSup, SSHashObj* pStUpdated, SResultWindowInfo* pCurWin,
3,526✔
2516
                           SResultWindowInfo* pNextWin) {
2517
  SStreamStateCur* pCur = pAggSup->stateStore.streamStateSessionSeekKeyNext(pAggSup->pState, &pCurWin->sessionWin);
3,526✔
2518
  pNextWin->isOutput = true;
3,526✔
2519
  setSessionWinOutputInfo(pStUpdated, pNextWin);
3,526✔
2520
  int32_t size = 0;
3,526✔
2521
  pNextWin->sessionWin = pCurWin->sessionWin;
3,526✔
2522
  int32_t code = pAggSup->stateStore.streamStateSessionGetKVByCur(pCur, &pNextWin->sessionWin,
3,526✔
2523
                                                                  (void**)&pNextWin->pStatePos, &size);
3,526✔
2524
  if (code != TSDB_CODE_SUCCESS) {
3,525✔
2525
    SET_SESSION_WIN_INVALID(*pNextWin);
3,063✔
2526
  }
2527
  pAggSup->stateStore.streamStateFreeCur(pCur);
3,525✔
2528
}
3,527✔
2529

2530
int32_t compactTimeWindow(SExprSupp* pSup, SStreamAggSupporter* pAggSup, STimeWindowAggSupp* pTwAggSup,
19✔
2531
                          SExecTaskInfo* pTaskInfo, SResultWindowInfo* pCurWin, SResultWindowInfo* pNextWin,
2532
                          SSHashObj* pStUpdated, SSHashObj* pStDeleted, bool addGap) {
2533
  int32_t     code = TSDB_CODE_SUCCESS;
19✔
2534
  int32_t     lino = 0;
19✔
2535
  SResultRow* pCurResult = NULL;
19✔
2536
  int32_t     numOfOutput = pSup->numOfExprs;
19✔
2537
  code = initSessionOutputBuf(pCurWin, &pCurResult, pSup->pCtx, numOfOutput, pSup->rowEntryInfoOffset);
19✔
2538
  QUERY_CHECK_CODE(code, lino, _end);
19!
2539

2540
  SResultRow* pWinResult = NULL;
19✔
2541
  code = initSessionOutputBuf(pNextWin, &pWinResult, pAggSup->pDummyCtx, numOfOutput, pSup->rowEntryInfoOffset);
19✔
2542
  QUERY_CHECK_CODE(code, lino, _end);
19!
2543

2544
  pCurWin->sessionWin.win.ekey = TMAX(pCurWin->sessionWin.win.ekey, pNextWin->sessionWin.win.ekey);
19✔
2545
  memcpy(pCurWin->pStatePos->pKey, &pCurWin->sessionWin, sizeof(SSessionKey));
19✔
2546

2547
  int64_t winDelta = 0;
19✔
2548
  if (addGap) {
19✔
2549
    winDelta = pAggSup->gap;
15✔
2550
  }
2551
  updateTimeWindowInfo(&pTwAggSup->timeWindowData, &pCurWin->sessionWin.win, winDelta);
19✔
2552
  code = compactFunctions(pSup->pCtx, pAggSup->pDummyCtx, numOfOutput, pTaskInfo, &pTwAggSup->timeWindowData);
19✔
2553
  QUERY_CHECK_CODE(code, lino, _end);
19✔
2554

2555
  int32_t tmpRes = tSimpleHashRemove(pStUpdated, &pNextWin->sessionWin, sizeof(SSessionKey));
17✔
2556
  qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
17!
2557

2558
  if (pNextWin->isOutput && pStDeleted) {
17!
2559
    qDebug("===stream=== save delete window info %" PRId64 ", %" PRIu64, pNextWin->sessionWin.win.skey,
16!
2560
           pNextWin->sessionWin.groupId);
2561
    code = saveDeleteRes(pStDeleted, pNextWin->sessionWin);
16✔
2562
    QUERY_CHECK_CODE(code, lino, _end);
16!
2563
  }
2564
  removeSessionResult(pAggSup, pStUpdated, pAggSup->pResultRows, &pNextWin->sessionWin);
17✔
2565
  doDeleteSessionWindow(pAggSup, &pNextWin->sessionWin);
17✔
2566
  releaseOutputBuf(pAggSup->pState, pNextWin->pStatePos, &pAggSup->pSessionAPI->stateStore);
17✔
2567

2568
_end:
19✔
2569
  if (code != TSDB_CODE_SUCCESS) {
19✔
2570
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
2!
2571
  }
2572
  return code;
19✔
2573
}
2574

2575
static int32_t compactSessionWindow(SOperatorInfo* pOperator, SResultWindowInfo* pCurWin, SSHashObj* pStUpdated,
3,452✔
2576
                                    SSHashObj* pStDeleted, bool addGap, int32_t* pWinNum) {
2577
  int32_t                        code = TSDB_CODE_SUCCESS;
3,452✔
2578
  int32_t                        lino = 0;
3,452✔
2579
  SExprSupp*                     pSup = &pOperator->exprSupp;
3,452✔
2580
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
3,452✔
2581
  SStorageAPI*                   pAPI = &pOperator->pTaskInfo->storageAPI;
3,452✔
2582
  int32_t                        winNum = 0;
3,452✔
2583
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
3,452✔
2584
  SResultRow*                    pCurResult = NULL;
3,452✔
2585
  int32_t                        numOfOutput = pOperator->exprSupp.numOfExprs;
3,452✔
2586
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
3,452✔
2587

2588
  // Just look for the window behind StartIndex
2589
  while (1) {
13✔
2590
    SResultWindowInfo winInfo = {0};
3,465✔
2591
    getNextSessionWinInfo(pAggSup, pStUpdated, pCurWin, &winInfo);
3,465✔
2592
    if (!IS_VALID_SESSION_WIN(winInfo) || !isInWindow(pCurWin, winInfo.sessionWin.win.skey, pAggSup->gap) ||
3,466✔
2593
        !inWinRange(&pAggSup->winRange, &winInfo.sessionWin.win)) {
15!
2594
      releaseOutputBuf(pAggSup->pState, winInfo.pStatePos, &pAggSup->pSessionAPI->stateStore);
3,451✔
2595
      break;
3,448✔
2596
    }
2597
    code =
2598
        compactTimeWindow(pSup, pAggSup, &pInfo->twAggSup, pTaskInfo, pCurWin, &winInfo, pStUpdated, pStDeleted, true);
15✔
2599
    QUERY_CHECK_CODE(code, lino, _end);
15✔
2600
    winNum++;
13✔
2601
  }
2602
  if (pWinNum) {
3,448✔
2603
    (*pWinNum) = winNum;
162✔
2604
  }
2605

2606
_end:
3,286✔
2607
  if (code != TSDB_CODE_SUCCESS) {
3,450✔
2608
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
2!
2609
  }
2610
  return code;
3,449✔
2611
}
2612

2613
static void compactSessionSemiWindow(SOperatorInfo* pOperator, SResultWindowInfo* pCurWin) {
25✔
2614
  SExprSupp*                     pSup = &pOperator->exprSupp;
25✔
2615
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
25✔
2616
  SStorageAPI*                   pAPI = &pOperator->pTaskInfo->storageAPI;
25✔
2617
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
25✔
2618
  SResultRow*                    pCurResult = NULL;
25✔
2619
  int32_t                        numOfOutput = pOperator->exprSupp.numOfExprs;
25✔
2620
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
25✔
2621
  // Just look for the window behind StartIndex
UNCOV
2622
  while (1) {
×
2623
    SResultWindowInfo winInfo = {0};
25✔
2624
    getNextSessionWinInfo(pAggSup, NULL, pCurWin, &winInfo);
25✔
2625
    if (!IS_VALID_SESSION_WIN(winInfo) || !isInWindow(pCurWin, winInfo.sessionWin.win.skey, pAggSup->gap) ||
25!
UNCOV
2626
        !inWinRange(&pAggSup->winRange, &winInfo.sessionWin.win)) {
×
2627
      releaseOutputBuf(pAggSup->pState, winInfo.pStatePos, &pAggSup->pSessionAPI->stateStore);
25✔
2628
      break;
25✔
2629
    }
UNCOV
2630
    pCurWin->sessionWin.win.ekey = TMAX(pCurWin->sessionWin.win.ekey, winInfo.sessionWin.win.ekey);
×
UNCOV
2631
    memcpy(pCurWin->pStatePos->pKey, &pCurWin->sessionWin, sizeof(SSessionKey));
×
UNCOV
2632
    doDeleteSessionWindow(pAggSup, &winInfo.sessionWin);
×
UNCOV
2633
    releaseOutputBuf(pAggSup->pState, winInfo.pStatePos, &pAggSup->pSessionAPI->stateStore);
×
2634
  }
2635
}
25✔
2636

2637
int32_t saveSessionOutputBuf(SStreamAggSupporter* pAggSup, SResultWindowInfo* pWinInfo) {
12,384✔
2638
  qDebug("===stream===try save session result skey:%" PRId64 ", ekey:%" PRId64 ".pos%d", pWinInfo->sessionWin.win.skey,
12,384✔
2639
         pWinInfo->sessionWin.win.ekey, pWinInfo->pStatePos->needFree);
2640
  return pAggSup->stateStore.streamStateSessionPut(pAggSup->pState, &pWinInfo->sessionWin, pWinInfo->pStatePos,
12,384✔
2641
                                                   pAggSup->resultRowSize);
2642
}
2643

2644
static void doStreamSessionAggImpl(SOperatorInfo* pOperator, SSDataBlock* pSDataBlock, SSHashObj* pStUpdated,
3,247✔
2645
                                   SSHashObj* pStDeleted, bool hasEndTs, bool addGap) {
2646
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
3,247✔
2647
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
3,247✔
2648
  int32_t                        numOfOutput = pOperator->exprSupp.numOfExprs;
3,247✔
2649
  uint64_t                       groupId = pSDataBlock->info.id.groupId;
3,247✔
2650
  int32_t                        code = TSDB_CODE_SUCCESS;
3,247✔
2651
  int32_t                        lino = 0;
3,247✔
2652
  SResultRow*                    pResult = NULL;
3,247✔
2653
  int32_t                        rows = pSDataBlock->info.rows;
3,247✔
2654
  int32_t                        winRows = 0;
3,247✔
2655
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
3,247✔
2656

2657
  pInfo->dataVersion = TMAX(pInfo->dataVersion, pSDataBlock->info.version);
3,247✔
2658
  pAggSup->winRange = pTaskInfo->streamInfo.fillHistoryWindow;
3,247✔
2659
  if (pAggSup->winRange.ekey <= 0) {
3,247!
UNCOV
2660
    pAggSup->winRange.ekey = INT64_MAX;
×
2661
  }
2662

2663
  SColumnInfoData* pStartTsCol = taosArrayGet(pSDataBlock->pDataBlock, pInfo->primaryTsIndex);
3,247✔
2664
  TSKEY*           startTsCols = (int64_t*)pStartTsCol->pData;
3,248✔
2665
  SColumnInfoData* pEndTsCol = NULL;
3,248✔
2666
  if (hasEndTs) {
3,248✔
2667
    pEndTsCol = taosArrayGet(pSDataBlock->pDataBlock, pInfo->endTsIndex);
576✔
2668
  } else {
2669
    pEndTsCol = taosArrayGet(pSDataBlock->pDataBlock, pInfo->primaryTsIndex);
2,672✔
2670
  }
2671

2672
  TSKEY* endTsCols = (int64_t*)pEndTsCol->pData;
3,247✔
2673

2674
  void*            pPkVal = NULL;
3,247✔
2675
  int32_t          pkLen = 0;
3,247✔
2676
  SColumnInfoData* pPkColDataInfo = NULL;
3,247✔
2677
  if (hasSrcPrimaryKeyCol(&pInfo->basic)) {
3,247✔
2678
    pPkColDataInfo = taosArrayGet(pSDataBlock->pDataBlock, pInfo->basic.primaryPkIndex);
288✔
2679
  }
2680

2681
  for (int32_t i = 0; i < rows;) {
6,532✔
2682
    if (hasSrcPrimaryKeyCol(&pInfo->basic) && !IS_FINAL_SESSION_OP(pOperator) && pInfo->ignoreExpiredData) {
3,287!
UNCOV
2683
      pPkVal = colDataGetData(pPkColDataInfo, i);
×
UNCOV
2684
      pkLen = colDataGetRowLength(pPkColDataInfo, i);
×
2685
    }
2686
    if (!IS_FINAL_SESSION_OP(pOperator) && pInfo->ignoreExpiredData &&
3,472✔
2687
        checkExpiredData(&pInfo->streamAggSup.stateStore, pInfo->streamAggSup.pUpdateInfo, &pInfo->twAggSup,
184✔
2688
                         pSDataBlock->info.id.uid, endTsCols[i], pPkVal, pkLen)) {
184✔
2689
      i++;
26✔
2690
      continue;
26✔
2691
    }
2692
    SResultWindowInfo winInfo = {0};
3,262✔
2693
    code = setSessionOutputBuf(pAggSup, startTsCols[i], endTsCols[i], groupId, &winInfo);
3,262✔
2694
    QUERY_CHECK_CODE(code, lino, _end);
3,265!
2695

2696
    // coverity scan error
2697
    if (!winInfo.pStatePos) {
3,263!
UNCOV
2698
      continue;
×
2699
    }
2700
    setSessionWinOutputInfo(pStUpdated, &winInfo);
3,263✔
2701
    code = updateSessionWindowInfo(pAggSup, &winInfo, startTsCols, endTsCols, groupId, rows, i, pAggSup->gap,
3,262✔
2702
                                   pAggSup->pResultRows, pStUpdated, pStDeleted, &winRows);
2703
    QUERY_CHECK_CODE(code, lino, _end);
3,262!
2704

2705
    int64_t winDelta = 0;
3,262✔
2706
    if (addGap) {
3,262✔
2707
      winDelta = pAggSup->gap;
2,618✔
2708
    }
2709
    code = doOneWindowAggImpl(&pInfo->twAggSup.timeWindowData, &winInfo, &pResult, i, winRows, rows, numOfOutput,
3,262✔
2710
                              pOperator, winDelta);
2711
    QUERY_CHECK_CODE(code, lino, _end);
3,263!
2712

2713
    code = compactSessionWindow(pOperator, &winInfo, pStUpdated, pStDeleted, addGap, NULL);
3,263✔
2714
    QUERY_CHECK_CODE(code, lino, _end);
3,260✔
2715

2716
    code = saveSessionOutputBuf(pAggSup, &winInfo);
3,258✔
2717
    QUERY_CHECK_CODE(code, lino, _end);
3,259!
2718

2719
    if (pInfo->destHasPrimaryKey && winInfo.isOutput && IS_NORMAL_SESSION_OP(pOperator)) {
3,259!
UNCOV
2720
      code = saveDeleteRes(pInfo->pPkDeleted, winInfo.sessionWin);
×
UNCOV
2721
      QUERY_CHECK_CODE(code, lino, _end);
×
2722
    }
2723
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_AT_ONCE && pStUpdated) {
3,259✔
2724
      code = saveResult(winInfo, pStUpdated);
2,334✔
2725
      QUERY_CHECK_CODE(code, lino, _end);
2,335!
2726
    }
2727
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_WINDOW_CLOSE) {
3,260✔
2728
      winInfo.pStatePos->beUpdated = true;
626✔
2729
      SSessionKey key = {0};
626✔
2730
      getSessionHashKey(&winInfo.sessionWin, &key);
626✔
2731
      code = tSimpleHashPut(pAggSup->pResultRows, &key, sizeof(SSessionKey), &winInfo, sizeof(SResultWindowInfo));
626✔
2732
      QUERY_CHECK_CODE(code, lino, _end);
626!
2733
    }
2734

2735
    i += winRows;
3,260✔
2736
  }
2737

2738
_end:
3,245✔
2739
  if (code != TSDB_CODE_SUCCESS) {
3,247✔
2740
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
2!
2741
  }
2742
}
3,247✔
2743

2744
int32_t doDeleteTimeWindows(SStreamAggSupporter* pAggSup, SSDataBlock* pBlock, SArray* result) {
1,154✔
2745
  int32_t          code = TSDB_CODE_SUCCESS;
1,154✔
2746
  int32_t          lino = 0;
1,154✔
2747
  SColumnInfoData* pStartTsCol = taosArrayGet(pBlock->pDataBlock, START_TS_COLUMN_INDEX);
1,154✔
2748
  TSKEY*           startDatas = (TSKEY*)pStartTsCol->pData;
1,154✔
2749
  SColumnInfoData* pEndTsCol = taosArrayGet(pBlock->pDataBlock, END_TS_COLUMN_INDEX);
1,154✔
2750
  TSKEY*           endDatas = (TSKEY*)pEndTsCol->pData;
1,153✔
2751
  SColumnInfoData* pGroupCol = taosArrayGet(pBlock->pDataBlock, GROUPID_COLUMN_INDEX);
1,153✔
2752
  uint64_t*        gpDatas = (uint64_t*)pGroupCol->pData;
1,153✔
2753
  for (int32_t i = 0; i < pBlock->info.rows; i++) {
2,355✔
2754
    while (1) {
1,241✔
2755
      SSessionKey curWin = {0};
2,442✔
2756
      getCurSessionWindow(pAggSup, startDatas[i], endDatas[i], gpDatas[i], &curWin);
2,442✔
2757
      if (IS_INVALID_SESSION_WIN_KEY(curWin)) {
2,443✔
2758
        break;
1,202✔
2759
      }
2760
      doDeleteSessionWindow(pAggSup, &curWin);
1,241✔
2761
      if (result) {
1,241✔
2762
        code = saveDeleteInfo(result, curWin);
1,185✔
2763
        QUERY_CHECK_CODE(code, lino, _end);
1,185!
2764
      }
2765
    }
2766
  }
2767

2768
_end:
1,154✔
2769
  if (code != TSDB_CODE_SUCCESS) {
1,154!
UNCOV
2770
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
2771
  }
2772
  return code;
1,154✔
2773
}
2774

2775
inline int32_t sessionKeyCompareAsc(const void* pKey1, const void* pKey2) {
5,214✔
2776
  SResultWindowInfo* pWinInfo1 = (SResultWindowInfo*)pKey1;
5,214✔
2777
  SResultWindowInfo* pWinInfo2 = (SResultWindowInfo*)pKey2;
5,214✔
2778
  SSessionKey*       pWin1 = &pWinInfo1->sessionWin;
5,214✔
2779
  SSessionKey*       pWin2 = &pWinInfo2->sessionWin;
5,214✔
2780

2781
  if (pWin1->groupId > pWin2->groupId) {
5,214✔
2782
    return 1;
2,029✔
2783
  } else if (pWin1->groupId < pWin2->groupId) {
3,185✔
2784
    return -1;
1,780✔
2785
  }
2786

2787
  if (pWin1->win.skey > pWin2->win.skey) {
1,405✔
2788
    return 1;
779✔
2789
  } else if (pWin1->win.skey < pWin2->win.skey) {
626!
2790
    return -1;
626✔
2791
  }
2792

UNCOV
2793
  return 0;
×
2794
}
2795

2796
void doBuildDeleteDataBlock(SOperatorInfo* pOp, SSHashObj* pStDeleted, SSDataBlock* pBlock, void** Ite) {
22,829✔
2797
  int32_t        code = TSDB_CODE_SUCCESS;
22,829✔
2798
  int32_t        lino = 0;
22,829✔
2799
  SStorageAPI*   pAPI = &pOp->pTaskInfo->storageAPI;
22,829✔
2800
  SExecTaskInfo* pTaskInfo = pOp->pTaskInfo;
22,829✔
2801

2802
  blockDataCleanup(pBlock);
22,829✔
2803
  int32_t size = tSimpleHashGetSize(pStDeleted);
22,826✔
2804
  if (size == 0) {
22,827✔
2805
    return;
22,289✔
2806
  }
2807
  code = blockDataEnsureCapacity(pBlock, size);
538✔
2808
  QUERY_CHECK_CODE(code, lino, _end);
538!
2809

2810
  int32_t iter = 0;
538✔
2811
  while (((*Ite) = tSimpleHashIterate(pStDeleted, *Ite, &iter)) != NULL) {
1,152✔
2812
    if (pBlock->info.rows + 1 > pBlock->info.capacity) {
614!
UNCOV
2813
      break;
×
2814
    }
2815
    SSessionKey*     res = tSimpleHashGetKey(*Ite, NULL);
614!
2816
    SColumnInfoData* pStartTsCol = taosArrayGet(pBlock->pDataBlock, START_TS_COLUMN_INDEX);
614✔
2817
    code = colDataSetVal(pStartTsCol, pBlock->info.rows, (const char*)&res->win.skey, false);
614✔
2818
    QUERY_CHECK_CODE(code, lino, _end);
614!
2819

2820
    SColumnInfoData* pEndTsCol = taosArrayGet(pBlock->pDataBlock, END_TS_COLUMN_INDEX);
614✔
2821
    code = colDataSetVal(pEndTsCol, pBlock->info.rows, (const char*)&res->win.skey, false);
614✔
2822
    QUERY_CHECK_CODE(code, lino, _end);
614!
2823

2824
    SColumnInfoData* pUidCol = taosArrayGet(pBlock->pDataBlock, UID_COLUMN_INDEX);
614✔
2825
    colDataSetNULL(pUidCol, pBlock->info.rows);
614!
2826

2827
    SColumnInfoData* pGpCol = taosArrayGet(pBlock->pDataBlock, GROUPID_COLUMN_INDEX);
614✔
2828
    code = colDataSetVal(pGpCol, pBlock->info.rows, (const char*)&res->groupId, false);
614✔
2829
    QUERY_CHECK_CODE(code, lino, _end);
614!
2830

2831
    SColumnInfoData* pCalStCol = taosArrayGet(pBlock->pDataBlock, CALCULATE_START_TS_COLUMN_INDEX);
614✔
2832
    colDataSetNULL(pCalStCol, pBlock->info.rows);
614!
2833

2834
    SColumnInfoData* pCalEdCol = taosArrayGet(pBlock->pDataBlock, CALCULATE_END_TS_COLUMN_INDEX);
614✔
2835
    colDataSetNULL(pCalEdCol, pBlock->info.rows);
614!
2836

2837
    SColumnInfoData* pTableCol = taosArrayGet(pBlock->pDataBlock, TABLE_NAME_COLUMN_INDEX);
614✔
2838
    if (!pTableCol) {
614!
UNCOV
2839
      QUERY_CHECK_CODE(code, lino, _end);
×
2840
    }
2841

2842
    void*   tbname = NULL;
614✔
2843
    int32_t winCode = TSDB_CODE_SUCCESS;
614✔
2844
    code = pAPI->stateStore.streamStateGetParName(pOp->pTaskInfo->streamInfo.pState, res->groupId, &tbname, false,
614✔
2845
                                                  &winCode);
2846
    QUERY_CHECK_CODE(code, lino, _end);
614!
2847

2848
    if (winCode != TSDB_CODE_SUCCESS) {
614✔
2849
      colDataSetNULL(pTableCol, pBlock->info.rows);
158!
2850
    } else {
2851
      char parTbName[VARSTR_HEADER_SIZE + TSDB_TABLE_NAME_LEN];
2852
      STR_WITH_MAXSIZE_TO_VARSTR(parTbName, tbname, sizeof(parTbName));
456✔
2853
      code = colDataSetVal(pTableCol, pBlock->info.rows, (const char*)parTbName, false);
456✔
2854
      QUERY_CHECK_CODE(code, lino, _end);
456!
2855
      pAPI->stateStore.streamStateFreeVal(tbname);
456✔
2856
    }
2857
    pBlock->info.rows += 1;
614✔
2858
  }
2859

2860
_end:
538✔
2861
  if ((*Ite) == NULL) {
538!
2862
    tSimpleHashClear(pStDeleted);
539✔
2863
  }
2864

2865
  if (code != TSDB_CODE_SUCCESS) {
538!
UNCOV
2866
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
2867
  }
2868
}
2869

2870
static int32_t rebuildSessionWindow(SOperatorInfo* pOperator, SArray* pWinArray, SSHashObj* pStUpdated) {
56✔
2871
  int32_t        winCode = TSDB_CODE_SUCCESS;
56✔
2872
  int32_t        code = TSDB_CODE_SUCCESS;
56✔
2873
  int32_t        lino = 0;
56✔
2874
  SExprSupp*     pSup = &pOperator->exprSupp;
56✔
2875
  SExecTaskInfo* pTaskInfo = pOperator->pTaskInfo;
56✔
2876
  SStorageAPI*   pAPI = &pOperator->pTaskInfo->storageAPI;
56✔
2877

2878
  int32_t                        size = taosArrayGetSize(pWinArray);
56✔
2879
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
56✔
2880
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
56✔
2881
  int32_t                        numOfOutput = pSup->numOfExprs;
56✔
2882
  int32_t                        numOfChild = taosArrayGetSize(pInfo->pChildren);
56✔
2883

2884
  for (int32_t i = 0; i < size; i++) {
118✔
2885
    SSessionKey*      pWinKey = taosArrayGet(pWinArray, i);
62✔
2886
    int32_t           num = 0;
62✔
2887
    SResultWindowInfo parentWin = {0};
62✔
2888
    for (int32_t j = 0; j < numOfChild; j++) {
284✔
2889
      SOperatorInfo*                 pChild = taosArrayGetP(pInfo->pChildren, j);
222✔
2890
      SStreamSessionAggOperatorInfo* pChInfo = pChild->info;
222✔
2891
      SStreamAggSupporter*           pChAggSup = &pChInfo->streamAggSup;
222✔
2892
      SSessionKey                    chWinKey = {0};
222✔
2893
      getSessionHashKey(pWinKey, &chWinKey);
222✔
2894
      SStreamStateCur* pCur = pAggSup->stateStore.streamStateSessionSeekKeyCurrentNext(pChAggSup->pState, &chWinKey);
222✔
2895
      SResultRow*      pResult = NULL;
222✔
2896
      SResultRow*      pChResult = NULL;
222✔
2897
      while (1) {
27✔
2898
        SResultWindowInfo childWin = {0};
249✔
2899
        childWin.sessionWin = *pWinKey;
249✔
2900
        getSessionWinBuf(pChAggSup, pCur, &childWin, &winCode);
249✔
2901

2902
        if (winCode == TSDB_CODE_SUCCESS && !inWinRange(&pAggSup->winRange, &childWin.sessionWin.win)) {
249!
UNCOV
2903
          releaseOutputBuf(pAggSup->pState, childWin.pStatePos, &pAggSup->stateStore);
×
UNCOV
2904
          continue;
×
2905
        }
2906

2907
        if (winCode == TSDB_CODE_SUCCESS && inWinRange(&pWinKey->win, &childWin.sessionWin.win)) {
249✔
2908
          if (num == 0) {
27!
2909
            code = setSessionOutputBuf(pAggSup, pWinKey->win.skey, pWinKey->win.ekey, pWinKey->groupId, &parentWin);
27✔
2910
            QUERY_CHECK_CODE(code, lino, _end);
27!
2911

2912
            parentWin.sessionWin = childWin.sessionWin;
27✔
2913
            memcpy(parentWin.pStatePos->pKey, &parentWin.sessionWin, sizeof(SSessionKey));
27✔
2914
            code = initSessionOutputBuf(&parentWin, &pResult, pSup->pCtx, numOfOutput, pSup->rowEntryInfoOffset);
27✔
2915
            QUERY_CHECK_CODE(code, lino, _end);
27!
2916
          }
2917
          num++;
27✔
2918
          parentWin.sessionWin.win.skey = TMIN(parentWin.sessionWin.win.skey, childWin.sessionWin.win.skey);
27✔
2919
          parentWin.sessionWin.win.ekey = TMAX(parentWin.sessionWin.win.ekey, childWin.sessionWin.win.ekey);
27✔
2920
          memcpy(parentWin.pStatePos->pKey, &parentWin.sessionWin, sizeof(SSessionKey));
27✔
2921

2922
          updateTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &parentWin.sessionWin.win, pAggSup->gap);
27✔
2923
          code = initSessionOutputBuf(&childWin, &pChResult, pChild->exprSupp.pCtx, numOfOutput,
27✔
2924
                                      pChild->exprSupp.rowEntryInfoOffset);
2925
          QUERY_CHECK_CODE(code, lino, _end);
27!
2926

2927
          code = compactFunctions(pSup->pCtx, pChild->exprSupp.pCtx, numOfOutput, pTaskInfo,
27✔
2928
                                  &pInfo->twAggSup.timeWindowData);
2929
          QUERY_CHECK_CODE(code, lino, _end);
27!
2930

2931
          code = compactSessionWindow(pOperator, &parentWin, pStUpdated, NULL, true, NULL);
27✔
2932
          QUERY_CHECK_CODE(code, lino, _end);
27!
2933

2934
          releaseOutputBuf(pAggSup->pState, childWin.pStatePos, &pAggSup->stateStore);
27✔
2935
        } else {
2936
          releaseOutputBuf(pAggSup->pState, childWin.pStatePos, &pAggSup->stateStore);
222✔
2937
          break;
222✔
2938
        }
2939
      }
2940
      pAPI->stateStore.streamStateFreeCur(pCur);
222✔
2941
    }
2942
    if (num > 0) {
62✔
2943
      code = saveResult(parentWin, pStUpdated);
27✔
2944
      QUERY_CHECK_CODE(code, lino, _end);
27!
2945

2946
      code = saveSessionOutputBuf(pAggSup, &parentWin);
27✔
2947
      QUERY_CHECK_CODE(code, lino, _end);
27!
2948
    }
2949
  }
2950

2951
_end:
56✔
2952
  if (code != TSDB_CODE_SUCCESS) {
56!
UNCOV
2953
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
2954
  }
2955
  return code;
56✔
2956
}
2957

2958
int32_t closeSessionWindow(SSHashObj* pHashMap, STimeWindowAggSupp* pTwSup, SSHashObj* pClosed) {
15,123✔
2959
  int32_t code = TSDB_CODE_SUCCESS;
15,123✔
2960
  int32_t lino = 0;
15,123✔
2961
  void*   pIte = NULL;
15,123✔
2962
  int32_t iter = 0;
15,123✔
2963
  while ((pIte = tSimpleHashIterate(pHashMap, pIte, &iter)) != NULL) {
17,490✔
2964
    SResultWindowInfo* pWinInfo = pIte;
2,368✔
2965
    if (isCloseWindow(&pWinInfo->sessionWin.win, pTwSup)) {
2,368✔
2966
      if (pTwSup->calTrigger == STREAM_TRIGGER_WINDOW_CLOSE && pClosed) {
495!
2967
        code = saveResult(*pWinInfo, pClosed);
495✔
2968
        QUERY_CHECK_CODE(code, lino, _end);
495!
2969
      }
2970
      SSessionKey* pKey = tSimpleHashGetKey(pIte, NULL);
495!
2971
      code = tSimpleHashIterateRemove(pHashMap, pKey, sizeof(SSessionKey), &pIte, &iter);
495✔
2972
      QUERY_CHECK_CODE(code, lino, _end);
495!
2973
    }
2974
  }
2975
_end:
15,122✔
2976
  if (code != TSDB_CODE_SUCCESS) {
15,122!
UNCOV
2977
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
2978
  }
2979
  return code;
15,126✔
2980
}
2981

2982
static int32_t closeChildSessionWindow(SArray* pChildren, TSKEY maxTs) {
5,983✔
2983
  int32_t code = TSDB_CODE_SUCCESS;
5,983✔
2984
  int32_t lino = 0;
5,983✔
2985

2986
  int32_t size = taosArrayGetSize(pChildren);
5,983✔
2987
  for (int32_t i = 0; i < size; i++) {
6,769✔
2988
    SOperatorInfo*                 pChildOp = taosArrayGetP(pChildren, i);
786✔
2989
    SStreamSessionAggOperatorInfo* pChInfo = pChildOp->info;
786✔
2990
    pChInfo->twAggSup.maxTs = TMAX(pChInfo->twAggSup.maxTs, maxTs);
786✔
2991
    code = closeSessionWindow(pChInfo->streamAggSup.pResultRows, &pChInfo->twAggSup, NULL);
786✔
2992
    QUERY_CHECK_CODE(code, lino, _end);
786!
2993
  }
2994
_end:
5,983✔
2995
  if (code != TSDB_CODE_SUCCESS) {
5,983!
UNCOV
2996
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
2997
  }
2998
  return code;
5,983✔
2999
}
3000

3001
int32_t getAllSessionWindow(SSHashObj* pHashMap, SSHashObj* pStUpdated) {
198✔
3002
  int32_t code = TSDB_CODE_SUCCESS;
198✔
3003
  int32_t lino = 0;
198✔
3004
  void*   pIte = NULL;
198✔
3005
  int32_t iter = 0;
198✔
3006
  while ((pIte = tSimpleHashIterate(pHashMap, pIte, &iter)) != NULL) {
287✔
3007
    SResultWindowInfo* pWinInfo = pIte;
89✔
3008
    if (!pWinInfo->pStatePos->beUpdated) {
89✔
3009
      continue;
3✔
3010
    }
3011
    pWinInfo->pStatePos->beUpdated = false;
86✔
3012
    code = saveResult(*pWinInfo, pStUpdated);
86✔
3013
    QUERY_CHECK_CODE(code, lino, _end);
86!
3014
  }
3015

3016
_end:
198✔
3017
  if (code != TSDB_CODE_SUCCESS) {
198!
UNCOV
3018
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
3019
  }
3020
  return code;
198✔
3021
}
3022

3023
int32_t copyDeleteWindowInfo(SArray* pResWins, SSHashObj* pStDeleted) {
1,110✔
3024
  int32_t code = TSDB_CODE_SUCCESS;
1,110✔
3025
  int32_t lino = 0;
1,110✔
3026
  int32_t size = taosArrayGetSize(pResWins);
1,110✔
3027
  for (int32_t i = 0; i < size; i++) {
2,319✔
3028
    SSessionKey* pWinKey = taosArrayGet(pResWins, i);
1,209✔
3029
    if (!pWinKey) continue;
1,209!
3030
    SSessionKey winInfo = {0};
1,209✔
3031
    getSessionHashKey(pWinKey, &winInfo);
1,209✔
3032
    code = tSimpleHashPut(pStDeleted, &winInfo, sizeof(SSessionKey), NULL, 0);
1,209✔
3033
    QUERY_CHECK_CODE(code, lino, _end);
1,209!
3034
  }
3035

3036
_end:
1,110✔
3037
  if (code != TSDB_CODE_SUCCESS) {
1,110!
UNCOV
3038
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
3039
  }
3040
  return code;
1,110✔
3041
}
3042

3043
// the allocated memory comes from outer function.
3044
void initGroupResInfoFromArrayList(SGroupResInfo* pGroupResInfo, SArray* pArrayList) {
15,148✔
3045
  pGroupResInfo->pRows = pArrayList;
15,148✔
3046
  pGroupResInfo->index = 0;
15,148✔
3047
  pGroupResInfo->pBuf = NULL;
15,148✔
3048
  pGroupResInfo->freeItem = false;
15,148✔
3049
}
15,148✔
3050

3051
int32_t buildSessionResultDataBlock(SOperatorInfo* pOperator, void* pState, SSDataBlock* pBlock, SExprSupp* pSup,
6,179✔
3052
                                    SGroupResInfo* pGroupResInfo) {
3053
  int32_t         code = TSDB_CODE_SUCCESS;
6,179✔
3054
  int32_t         lino = 0;
6,179✔
3055
  SExecTaskInfo*  pTaskInfo = pOperator->pTaskInfo;
6,179✔
3056
  SStorageAPI*    pAPI = &pTaskInfo->storageAPI;
6,179✔
3057
  SExprInfo*      pExprInfo = pSup->pExprInfo;
6,179✔
3058
  int32_t         numOfExprs = pSup->numOfExprs;
6,179✔
3059
  int32_t*        rowEntryOffset = pSup->rowEntryInfoOffset;
6,179✔
3060
  SqlFunctionCtx* pCtx = pSup->pCtx;
6,179✔
3061

3062
  int32_t numOfRows = getNumOfTotalRes(pGroupResInfo);
6,179✔
3063

3064
  for (int32_t i = pGroupResInfo->index; i < numOfRows; i += 1) {
13,085✔
3065
    SResultWindowInfo* pWinInfo = taosArrayGet(pGroupResInfo->pRows, i);
8,465✔
3066
    SRowBuffPos*       pPos = pWinInfo->pStatePos;
8,464✔
3067
    SResultRow*        pRow = NULL;
8,464✔
3068
    SSessionKey*       pKey = (SSessionKey*)pPos->pKey;
8,464✔
3069

3070
    if (pBlock->info.id.groupId == 0) {
8,464✔
3071
      pBlock->info.id.groupId = pKey->groupId;
6,434✔
3072

3073
      void*   tbname = NULL;
6,434✔
3074
      int32_t winCode = TSDB_CODE_SUCCESS;
6,434✔
3075
      code = pAPI->stateStore.streamStateGetParName((void*)pTaskInfo->streamInfo.pState, pBlock->info.id.groupId,
6,434✔
3076
                                                    &tbname, false, &winCode);
3077
      QUERY_CHECK_CODE(code, lino, _end);
6,435!
3078

3079
      if (winCode != TSDB_CODE_SUCCESS) {
6,435✔
3080
        pBlock->info.parTbName[0] = 0;
1,639✔
3081
      } else {
3082
        memcpy(pBlock->info.parTbName, tbname, TSDB_TABLE_NAME_LEN);
4,796✔
3083
      }
3084
      pAPI->stateStore.streamStateFreeVal(tbname);
6,435✔
3085
    } else {
3086
      // current value belongs to different group, it can't be packed into one datablock
3087
      if (pBlock->info.id.groupId != pKey->groupId) {
2,030✔
3088
        break;
1,537✔
3089
      }
3090
    }
3091

3092
    code = pAPI->stateStore.streamStateGetByPos(pState, pPos, (void**)&pRow);
6,928✔
3093
    QUERY_CHECK_CODE(code, lino, _end);
6,928!
3094

3095
    doUpdateNumOfRows(pCtx, pRow, numOfExprs, rowEntryOffset);
6,928✔
3096
    // no results, continue to check the next one
3097
    if (pRow->numOfRows == 0) {
6,927!
UNCOV
3098
      pGroupResInfo->index += 1;
×
UNCOV
3099
      continue;
×
3100
    }
3101

3102
    if (pBlock->info.rows + pRow->numOfRows > pBlock->info.capacity) {
6,927!
UNCOV
3103
      break;
×
3104
    }
3105

3106
    pGroupResInfo->index += 1;
6,927✔
3107

3108
    for (int32_t j = 0; j < numOfExprs; ++j) {
117,890✔
3109
      int32_t slotId = pExprInfo[j].base.resSchema.slotId;
110,984✔
3110

3111
      pCtx[j].resultInfo = getResultEntryInfo(pRow, j, rowEntryOffset);
110,984✔
3112
      if (pCtx[j].fpSet.finalize) {
110,980✔
3113
        int32_t tmpRes = pCtx[j].fpSet.finalize(&pCtx[j], pBlock);
101,807✔
3114
        if (TAOS_FAILED(tmpRes)) {
101,808!
UNCOV
3115
          qError("%s build result data block error, code %s", GET_TASKID(pTaskInfo), tstrerror(tmpRes));
×
UNCOV
3116
          QUERY_CHECK_CODE(code, lino, _end);
×
3117
        }
3118
      } else if (strcmp(pCtx[j].pExpr->pExpr->_function.functionName, "_select_value") == 0) {
9,173!
3119
        // do nothing, todo refactor
3120
      } else {
3121
        // expand the result into multiple rows. E.g., _wstart, top(k, 20)
3122
        // the _wstart needs to copy to 20 following rows, since the results of top-k expands to 20 different rows.
3123
        SColumnInfoData* pColInfoData = taosArrayGet(pBlock->pDataBlock, slotId);
9,229✔
3124
        char*            in = GET_ROWCELL_INTERBUF(pCtx[j].resultInfo);
9,229✔
3125
        for (int32_t k = 0; k < pRow->numOfRows; ++k) {
18,458✔
3126
          code = colDataSetVal(pColInfoData, pBlock->info.rows + k, in, pCtx[j].resultInfo->isNullRes);
9,229✔
3127
          QUERY_CHECK_CODE(code, lino, _end);
9,229!
3128
        }
3129
      }
3130
    }
3131

3132
    pBlock->info.dataLoad = 1;
6,906✔
3133
    pBlock->info.rows += pRow->numOfRows;
6,906✔
3134
  }
3135
  code = blockDataUpdateTsWindow(pBlock, 0);
6,157✔
3136
  QUERY_CHECK_CODE(code, lino, _end);
6,181!
3137

3138
_end:
6,181✔
3139
  if (code != TSDB_CODE_SUCCESS) {
6,181!
UNCOV
3140
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
3141
  }
3142
  return code;
6,181✔
3143
}
3144

3145
void doBuildSessionResult(SOperatorInfo* pOperator, void* pState, SGroupResInfo* pGroupResInfo, SSDataBlock* pBlock) {
22,290✔
3146
  int32_t        code = TSDB_CODE_SUCCESS;
22,290✔
3147
  int32_t        lino = 0;
22,290✔
3148
  SExecTaskInfo* pTaskInfo = pOperator->pTaskInfo;
22,290✔
3149
  // set output datablock version
3150
  pBlock->info.version = pTaskInfo->version;
22,290✔
3151

3152
  blockDataCleanup(pBlock);
22,290✔
3153
  if (!hasRemainResults(pGroupResInfo)) {
22,276✔
3154
    cleanupGroupResInfo(pGroupResInfo);
16,102✔
3155
    goto _end;
16,118✔
3156
  }
3157

3158
  // clear the existed group id
3159
  pBlock->info.id.groupId = 0;
6,179✔
3160
  code = buildSessionResultDataBlock(pOperator, pState, pBlock, &pOperator->exprSupp, pGroupResInfo);
6,179✔
3161
  QUERY_CHECK_CODE(code, lino, _end);
6,181!
3162

3163
  if (pBlock->info.rows == 0) {
6,181!
UNCOV
3164
    cleanupGroupResInfo(pGroupResInfo);
×
3165
  }
3166

3167
_end:
6,181✔
3168
  if (code != TSDB_CODE_SUCCESS) {
22,299!
UNCOV
3169
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
3170
  }
3171
}
22,299✔
3172

3173
static int32_t buildSessionResult(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
10,204✔
3174
  int32_t                        code = TSDB_CODE_SUCCESS;
10,204✔
3175
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
10,204✔
3176
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
10,204✔
3177
  SOptrBasicInfo*                pBInfo = &pInfo->binfo;
10,204✔
3178
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
10,204✔
3179
  doBuildDeleteDataBlock(pOperator, pInfo->pStDeleted, pInfo->pDelRes, &pInfo->pDelIterator);
10,204✔
3180
  if (pInfo->pDelRes->info.rows > 0) {
10,200✔
3181
    printDataBlock(pInfo->pDelRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
254✔
3182
    (*ppRes) = pInfo->pDelRes;
254✔
3183
    return code;
254✔
3184
  }
3185

3186
  doBuildSessionResult(pOperator, pAggSup->pState, &pInfo->groupResInfo, pBInfo->pRes);
9,946✔
3187
  if (pBInfo->pRes->info.rows > 0) {
9,952✔
3188
    printDataBlock(pBInfo->pRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
2,211✔
3189
    (*ppRes) = pBInfo->pRes;
2,210✔
3190
    return code;
2,210✔
3191
  }
3192
  (*ppRes) = NULL;
7,741✔
3193
  return code;
7,741✔
3194
}
3195

3196
int32_t getMaxTsWins(const SArray* pAllWins, SArray* pMaxWins) {
409✔
3197
  int32_t code = TSDB_CODE_SUCCESS;
409✔
3198
  int32_t lino = 0;
409✔
3199
  int32_t size = taosArrayGetSize(pAllWins);
409✔
3200
  if (size == 0) {
409✔
3201
    goto _end;
275✔
3202
  }
3203
  SResultWindowInfo* pWinInfo = taosArrayGet(pAllWins, size - 1);
134✔
3204
  SSessionKey*       pSeKey = &pWinInfo->sessionWin;
134✔
3205
  void*              tmp = taosArrayPush(pMaxWins, pSeKey);
134✔
3206
  if (!tmp) {
134!
UNCOV
3207
    code = terrno;
×
UNCOV
3208
    QUERY_CHECK_CODE(code, lino, _end);
×
3209
  }
3210

3211
  if (pSeKey->groupId == 0) {
134✔
3212
    goto _end;
17✔
3213
  }
3214
  uint64_t preGpId = pSeKey->groupId;
117✔
3215
  for (int32_t i = size - 2; i >= 0; i--) {
455✔
3216
    pWinInfo = taosArrayGet(pAllWins, i);
338✔
3217
    pSeKey = &pWinInfo->sessionWin;
338✔
3218
    if (preGpId != pSeKey->groupId) {
338✔
3219
      void* tmp = taosArrayPush(pMaxWins, pSeKey);
212✔
3220
      if (!tmp) {
212!
UNCOV
3221
        code = terrno;
×
UNCOV
3222
        QUERY_CHECK_CODE(code, lino, _end);
×
3223
      }
3224
      preGpId = pSeKey->groupId;
212✔
3225
    }
3226
  }
3227

3228
_end:
117✔
3229
  if (code != TSDB_CODE_SUCCESS) {
409!
UNCOV
3230
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
3231
  }
3232
  return code;
409✔
3233
}
3234

3235
int32_t encodeSSessionKey(void** buf, SSessionKey* key) {
4✔
3236
  int32_t tlen = 0;
4✔
3237
  tlen += encodeSTimeWindow(buf, &key->win);
4✔
3238
  tlen += taosEncodeFixedU64(buf, key->groupId);
4✔
3239
  return tlen;
4✔
3240
}
3241

UNCOV
3242
void* decodeSSessionKey(void* buf, SSessionKey* key) {
×
3243
  buf = decodeSTimeWindow(buf, &key->win);
×
3244
  buf = taosDecodeFixedU64(buf, &key->groupId);
×
3245
  return buf;
×
3246
}
3247

3248
int32_t encodeSResultWindowInfo(void** buf, SResultWindowInfo* key, int32_t outLen) {
2✔
3249
  int32_t tlen = 0;
2✔
3250
  tlen += taosEncodeFixedBool(buf, key->isOutput);
2✔
3251
  tlen += encodeSSessionKey(buf, &key->sessionWin);
2✔
3252
  return tlen;
2✔
3253
}
3254

3255
void* decodeSResultWindowInfo(void* buf, SResultWindowInfo* key, int32_t outLen) {
×
3256
  buf = taosDecodeFixedBool(buf, &key->isOutput);
×
3257
  buf = decodeSSessionKey(buf, &key->sessionWin);
×
3258
  return buf;
×
3259
}
3260

3261
int32_t doStreamSessionEncodeOpState(void** buf, int32_t len, SOperatorInfo* pOperator, bool isParent) {
×
UNCOV
3262
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
×
UNCOV
3263
  if (!pInfo) {
×
UNCOV
3264
    return 0;
×
3265
  }
3266

UNCOV
3267
  void* pData = (buf == NULL) ? NULL : *buf;
×
3268

3269
  // 1.streamAggSup.pResultRows
3270
  int32_t tlen = 0;
×
3271
  int32_t mapSize = tSimpleHashGetSize(pInfo->streamAggSup.pResultRows);
×
3272
  tlen += taosEncodeFixedI32(buf, mapSize);
×
UNCOV
3273
  void*   pIte = NULL;
×
UNCOV
3274
  size_t  keyLen = 0;
×
UNCOV
3275
  int32_t iter = 0;
×
3276
  while ((pIte = tSimpleHashIterate(pInfo->streamAggSup.pResultRows, pIte, &iter)) != NULL) {
×
UNCOV
3277
    void* key = tSimpleHashGetKey(pIte, &keyLen);
×
UNCOV
3278
    tlen += encodeSSessionKey(buf, key);
×
3279
    tlen += encodeSResultWindowInfo(buf, pIte, pInfo->streamAggSup.resultRowSize);
×
3280
  }
3281

3282
  // 2.twAggSup
UNCOV
3283
  tlen += encodeSTimeWindowAggSupp(buf, &pInfo->twAggSup);
×
3284

3285
  // 3.pChildren
UNCOV
3286
  int32_t size = taosArrayGetSize(pInfo->pChildren);
×
UNCOV
3287
  tlen += taosEncodeFixedI32(buf, size);
×
3288
  for (int32_t i = 0; i < size; i++) {
×
UNCOV
3289
    SOperatorInfo* pChOp = taosArrayGetP(pInfo->pChildren, i);
×
UNCOV
3290
    tlen += doStreamSessionEncodeOpState(buf, 0, pChOp, false);
×
3291
  }
3292

3293
  // 4.dataVersion
3294
  tlen += taosEncodeFixedI64(buf, pInfo->dataVersion);
×
3295

3296
  // 5.checksum
3297
  if (isParent) {
×
3298
    if (buf) {
×
UNCOV
3299
      uint32_t cksum = taosCalcChecksum(0, pData, len - sizeof(uint32_t));
×
3300
      tlen += taosEncodeFixedU32(buf, cksum);
×
3301
    } else {
UNCOV
3302
      tlen += sizeof(uint32_t);
×
3303
    }
3304
  }
3305

3306
  return tlen;
×
3307
}
3308

3309
int32_t doStreamSessionDecodeOpState(void* buf, int32_t len, SOperatorInfo* pOperator, bool isParent, void** ppBuf) {
×
UNCOV
3310
  int32_t                        code = TSDB_CODE_SUCCESS;
×
UNCOV
3311
  int32_t                        lino = 0;
×
UNCOV
3312
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
×
UNCOV
3313
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
×
3314
  if (!pInfo) {
×
3315
    code = TSDB_CODE_FAILED;
×
3316
    QUERY_CHECK_CODE(code, lino, _end);
×
3317
  }
3318
  SStreamAggSupporter* pAggSup = &pInfo->streamAggSup;
×
3319

3320
  // 5.checksum
UNCOV
3321
  if (isParent) {
×
3322
    int32_t dataLen = len - sizeof(uint32_t);
×
3323
    void*   pCksum = POINTER_SHIFT(buf, dataLen);
×
UNCOV
3324
    if (taosCheckChecksum(buf, dataLen, *(uint32_t*)pCksum) != TSDB_CODE_SUCCESS) {
×
3325
      qError("stream session state is invalid");
×
3326
      code = TSDB_CODE_FAILED;
×
UNCOV
3327
      QUERY_CHECK_CODE(code, lino, _end);
×
3328
    }
3329
  }
3330

3331
  // 1.streamAggSup.pResultRows
3332
  int32_t mapSize = 0;
×
UNCOV
3333
  buf = taosDecodeFixedI32(buf, &mapSize);
×
UNCOV
3334
  for (int32_t i = 0; i < mapSize; i++) {
×
3335
    SResultWindowInfo winfo = {0};
×
3336
    buf = decodeSSessionKey(buf, &winfo.sessionWin);
×
3337
    int32_t winCode = TSDB_CODE_SUCCESS;
×
3338
    code = pAggSup->stateStore.streamStateSessionAddIfNotExist(
×
3339
        pAggSup->pState, &winfo.sessionWin, pAggSup->gap, (void**)&winfo.pStatePos, &pAggSup->resultRowSize, &winCode);
3340
    QUERY_CHECK_CODE(code, lino, _end);
×
UNCOV
3341
    QUERY_CHECK_CONDITION((winCode == TSDB_CODE_SUCCESS), code, lino, _end, TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR);
×
3342

UNCOV
3343
    buf = decodeSResultWindowInfo(buf, &winfo, pInfo->streamAggSup.resultRowSize);
×
3344
    code = tSimpleHashPut(pInfo->streamAggSup.pResultRows, &winfo.sessionWin, sizeof(SSessionKey), &winfo,
×
3345
                          sizeof(SResultWindowInfo));
3346
    QUERY_CHECK_CODE(code, lino, _end);
×
3347
  }
3348

3349
  // 2.twAggSup
3350
  buf = decodeSTimeWindowAggSupp(buf, &pInfo->twAggSup);
×
3351

3352
  // 3.pChildren
3353
  int32_t size = 0;
×
UNCOV
3354
  buf = taosDecodeFixedI32(buf, &size);
×
UNCOV
3355
  for (int32_t i = 0; i < size; i++) {
×
UNCOV
3356
    SOperatorInfo* pChOp = taosArrayGetP(pInfo->pChildren, i);
×
UNCOV
3357
    code = doStreamSessionDecodeOpState(buf, 0, pChOp, false, &buf);
×
UNCOV
3358
    QUERY_CHECK_CODE(code, lino, _end);
×
3359
  }
3360

3361
  // 4.dataVersion
3362
  buf = taosDecodeFixedI64(buf, &pInfo->dataVersion);
×
3363
  if (ppBuf) {
×
UNCOV
3364
    (*ppBuf) = buf;
×
3365
  }
3366

3367
_end:
×
UNCOV
3368
  if (code != TSDB_CODE_SUCCESS) {
×
3369
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
3370
  }
UNCOV
3371
  return code;
×
3372
}
3373

3374
void doStreamSessionSaveCheckpoint(SOperatorInfo* pOperator) {
191✔
3375
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
191✔
3376
  if (needSaveStreamOperatorInfo(&pInfo->basic)) {
191!
UNCOV
3377
    int32_t len = doStreamSessionEncodeOpState(NULL, 0, pOperator, true);
×
UNCOV
3378
    void*   buf = taosMemoryCalloc(1, len);
×
UNCOV
3379
    if (!buf) {
×
UNCOV
3380
      qError("%s failed at line %d since %s", __func__, __LINE__, tstrerror(TSDB_CODE_OUT_OF_MEMORY));
×
UNCOV
3381
      return;
×
3382
    }
UNCOV
3383
    void* pBuf = buf;
×
UNCOV
3384
    len = doStreamSessionEncodeOpState(&pBuf, len, pOperator, true);
×
UNCOV
3385
    pInfo->streamAggSup.stateStore.streamStateSaveInfo(pInfo->streamAggSup.pState, STREAM_SESSION_OP_CHECKPOINT_NAME,
×
3386
                                                       strlen(STREAM_SESSION_OP_CHECKPOINT_NAME), buf, len);
UNCOV
3387
    taosMemoryFree(buf);
×
UNCOV
3388
    saveStreamOperatorStateComplete(&pInfo->basic);
×
3389
  }
3390
}
3391

3392
void resetUnCloseSessionWinInfo(SSHashObj* winMap) {
86✔
3393
  void*   pIte = NULL;
86✔
3394
  int32_t iter = 0;
86✔
3395
  while ((pIte = tSimpleHashIterate(winMap, pIte, &iter)) != NULL) {
172✔
3396
    SResultWindowInfo* pResInfo = pIte;
86✔
3397
    pResInfo->pStatePos->beUsed = true;
86✔
3398
  }
3399
}
86✔
3400

3401
int32_t copyDeleteSessionKey(SSHashObj* source, SSHashObj* dest) {
×
UNCOV
3402
  int32_t code = TSDB_CODE_SUCCESS;
×
UNCOV
3403
  int32_t lino = 0;
×
UNCOV
3404
  if (tSimpleHashGetSize(source) == 0) {
×
UNCOV
3405
    goto _end;
×
3406
  }
UNCOV
3407
  void*   pIte = NULL;
×
UNCOV
3408
  int32_t iter = 0;
×
UNCOV
3409
  size_t  keyLen = 0;
×
UNCOV
3410
  while ((pIte = tSimpleHashIterate(source, pIte, &iter)) != NULL) {
×
UNCOV
3411
    SSessionKey* pKey = tSimpleHashGetKey(pIte, &keyLen);
×
UNCOV
3412
    code = saveDeleteRes(dest, *pKey);
×
UNCOV
3413
    QUERY_CHECK_CODE(code, lino, _end);
×
3414
  }
UNCOV
3415
  tSimpleHashClear(source);
×
3416

3417
_end:
×
UNCOV
3418
  if (code != TSDB_CODE_SUCCESS) {
×
UNCOV
3419
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
3420
  }
UNCOV
3421
  return code;
×
3422
}
3423

3424
static int32_t doStreamSessionAggNext(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
8,938✔
3425
  int32_t                        code = TSDB_CODE_SUCCESS;
8,938✔
3426
  int32_t                        lino = 0;
8,938✔
3427
  SExprSupp*                     pSup = &pOperator->exprSupp;
8,938✔
3428
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
8,938✔
3429
  SOptrBasicInfo*                pBInfo = &pInfo->binfo;
8,938✔
3430
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
8,938✔
3431
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
8,938✔
3432
  qDebug("stask:%s  %s status: %d", GET_TASKID(pTaskInfo), getStreamOpName(pOperator->operatorType), pOperator->status);
8,938✔
3433
  if (pOperator->status == OP_EXEC_DONE) {
8,939!
3434
    (*ppRes) = NULL;
×
3435
    return code;
×
3436
  } else if (pOperator->status == OP_RES_TO_RETURN) {
8,939✔
3437
    SSDataBlock* opRes = NULL;
2,121✔
3438
    code = buildSessionResult(pOperator, &opRes);
2,121✔
3439
    QUERY_CHECK_CODE(code, lino, _end);
2,121!
3440
    if (opRes) {
2,121✔
3441
      (*ppRes) = opRes;
270✔
3442
      return code;
2,121✔
3443
    }
3444

3445
    if (pInfo->recvGetAll) {
1,851✔
3446
      pInfo->recvGetAll = false;
83✔
3447
      resetUnCloseSessionWinInfo(pInfo->streamAggSup.pResultRows);
83✔
3448
    }
3449

3450
    if (pInfo->reCkBlock) {
1,851!
UNCOV
3451
      pInfo->reCkBlock = false;
×
UNCOV
3452
      printDataBlock(pInfo->pCheckpointRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
UNCOV
3453
      (*ppRes) = pInfo->pCheckpointRes;
×
UNCOV
3454
      return code;
×
3455
    }
3456

3457
    setStreamOperatorCompleted(pOperator);
1,851✔
3458
    (*ppRes) = NULL;
1,851✔
3459
    return code;
1,851✔
3460
  }
3461

3462
  SOperatorInfo* downstream = pOperator->pDownstream[0];
6,818✔
3463
  if (!pInfo->pUpdated) {
6,818✔
3464
    pInfo->pUpdated = taosArrayInit(16, sizeof(SResultWindowInfo));
5,983✔
3465
    QUERY_CHECK_NULL(pInfo->pUpdated, code, lino, _end, terrno);
5,985!
3466
  }
3467
  if (!pInfo->pStUpdated) {
6,820✔
3468
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
5,915✔
3469
    pInfo->pStUpdated = tSimpleHashInit(64, hashFn);
5,915✔
3470
    QUERY_CHECK_NULL(pInfo->pStUpdated, code, lino, _end, terrno);
5,914!
3471
  }
3472
  while (1) {
3,399✔
3473
    SSDataBlock* pBlock = NULL;
10,218✔
3474
    code = downstream->fpSet.getNextFn(downstream, &pBlock);
10,218✔
3475
    QUERY_CHECK_CODE(code, lino, _end);
10,217!
3476

3477
    if (pBlock == NULL) {
10,217✔
3478
      break;
5,984✔
3479
    }
3480
    printSpecDataBlock(pBlock, getStreamOpName(pOperator->operatorType), "recv", GET_TASKID(pTaskInfo));
4,233✔
3481
    setStreamOperatorState(&pInfo->basic, pBlock->info.type);
4,235✔
3482

3483
    if (pBlock->info.type == STREAM_DELETE_DATA || pBlock->info.type == STREAM_DELETE_RESULT ||
4,234✔
3484
        pBlock->info.type == STREAM_CLEAR) {
3,993✔
3485
      SArray* pWins = taosArrayInit(16, sizeof(SSessionKey));
420✔
3486
      QUERY_CHECK_NULL(pWins, code, lino, _end, terrno);
420!
3487
      // gap must be 0
3488
      code = doDeleteTimeWindows(pAggSup, pBlock, pWins);
420✔
3489
      QUERY_CHECK_CODE(code, lino, _end);
420!
3490

3491
      removeSessionResults(pAggSup, pInfo->pStUpdated, pWins);
420✔
3492
      if (IS_FINAL_SESSION_OP(pOperator)) {
420✔
3493
        int32_t                        childIndex = getChildIndex(pBlock);
56✔
3494
        SOperatorInfo*                 pChildOp = taosArrayGetP(pInfo->pChildren, childIndex);
56✔
3495
        SStreamSessionAggOperatorInfo* pChildInfo = pChildOp->info;
56✔
3496
        // gap must be 0
3497
        code = doDeleteTimeWindows(&pChildInfo->streamAggSup, pBlock, NULL);
56✔
3498
        QUERY_CHECK_CODE(code, lino, _end);
56!
3499

3500
        code = rebuildSessionWindow(pOperator, pWins, pInfo->pStUpdated);
56✔
3501
        QUERY_CHECK_CODE(code, lino, _end);
56!
3502
      }
3503
      code = copyDeleteWindowInfo(pWins, pInfo->pStDeleted);
420✔
3504
      QUERY_CHECK_CODE(code, lino, _end);
420!
3505

3506
      if (pInfo->destHasPrimaryKey && IS_NORMAL_SESSION_OP(pOperator)) {
420!
UNCOV
3507
        code = copyDeleteWindowInfo(pWins, pInfo->pPkDeleted);
×
UNCOV
3508
        QUERY_CHECK_CODE(code, lino, _end);
×
3509
      }
3510
      taosArrayDestroy(pWins);
420✔
3511
      continue;
783✔
3512
    } else if (pBlock->info.type == STREAM_GET_ALL) {
3,814✔
3513
      pInfo->recvGetAll = true;
187✔
3514
      code = getAllSessionWindow(pAggSup->pResultRows, pInfo->pStUpdated);
187✔
3515
      QUERY_CHECK_CODE(code, lino, _end);
187!
3516
      continue;
187✔
3517
    } else if (pBlock->info.type == STREAM_CREATE_CHILD_TABLE) {
3,627✔
3518
      (*ppRes) = pBlock;
836✔
3519
      return code;
836✔
3520
    } else if (pBlock->info.type == STREAM_CHECKPOINT) {
2,791✔
3521
      pAggSup->stateStore.streamStateCommit(pAggSup->pState);
176✔
3522
      doStreamSessionSaveCheckpoint(pOperator);
176✔
3523
      code = copyDataBlock(pInfo->pCheckpointRes, pBlock);
176✔
3524
      QUERY_CHECK_CODE(code, lino, _end);
176!
3525

3526
      continue;
176✔
3527
    } else {
3528
      if (pBlock->info.type != STREAM_NORMAL && pBlock->info.type != STREAM_INVALID) {
2,615!
UNCOV
3529
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
UNCOV
3530
        QUERY_CHECK_CODE(code, lino, _end);
×
3531
      }
3532
    }
3533

3534
    if (pInfo->scalarSupp.pExprInfo != NULL) {
2,615✔
3535
      SExprSupp* pExprSup = &pInfo->scalarSupp;
13✔
3536
      code = projectApplyFunctions(pExprSup->pExprInfo, pBlock, pBlock, pExprSup->pCtx, pExprSup->numOfExprs, NULL);
13✔
3537
      QUERY_CHECK_CODE(code, lino, _end);
13!
3538
    }
3539
    // the pDataBlock are always the same one, no need to call this again
3540
    code = setInputDataBlock(pSup, pBlock, TSDB_ORDER_ASC, MAIN_SCAN, true);
2,615✔
3541
    QUERY_CHECK_CODE(code, lino, _end);
2,617!
3542

3543
    doStreamSessionAggImpl(pOperator, pBlock, pInfo->pStUpdated, pInfo->pStDeleted, IS_FINAL_SESSION_OP(pOperator),
2,617✔
3544
                           true);
3545
    if (IS_FINAL_SESSION_OP(pOperator)) {
2,616✔
3546
      int32_t chIndex = getChildIndex(pBlock);
288✔
3547
      int32_t size = taosArrayGetSize(pInfo->pChildren);
288✔
3548
      // if chIndex + 1 - size > 0, add new child
3549
      for (int32_t i = 0; i < chIndex + 1 - size; i++) {
288!
UNCOV
3550
        SOperatorInfo* pChildOp = NULL;
×
UNCOV
3551
        code = createStreamFinalSessionAggOperatorInfo(NULL, pInfo->pPhyNode, pOperator->pTaskInfo, 0, NULL, &pChildOp);
×
UNCOV
3552
        if (pChildOp == NULL || code != 0) {
×
UNCOV
3553
          qError("%s create stream child of final session error", GET_TASKID(pTaskInfo));
×
UNCOV
3554
          code = TSDB_CODE_FAILED;
×
UNCOV
3555
          QUERY_CHECK_CODE(code, lino, _end);
×
3556
        }
3557

UNCOV
3558
        void* tmp = taosArrayPush(pInfo->pChildren, &pChildOp);
×
UNCOV
3559
        if (!tmp) {
×
UNCOV
3560
          code = terrno;
×
UNCOV
3561
          QUERY_CHECK_CODE(code, lino, _end);
×
3562
        }
3563
      }
3564

3565
      SOperatorInfo* pChildOp = taosArrayGetP(pInfo->pChildren, chIndex);
288✔
3566
      code = setInputDataBlock(&pChildOp->exprSupp, pBlock, TSDB_ORDER_ASC, MAIN_SCAN, true);
288✔
3567
      QUERY_CHECK_CODE(code, lino, _end);
288!
3568
      doStreamSessionAggImpl(pChildOp, pBlock, NULL, NULL, true, false);
288✔
3569
    }
3570
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.window.ekey);
2,616✔
3571
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.watermark);
2,616✔
3572
  }
3573
  // restore the value
3574
  pOperator->status = OP_RES_TO_RETURN;
5,984✔
3575

3576
  code = closeSessionWindow(pAggSup->pResultRows, &pInfo->twAggSup, pInfo->pStUpdated);
5,984✔
3577
  QUERY_CHECK_CODE(code, lino, _end);
5,984!
3578

3579
  code = closeChildSessionWindow(pInfo->pChildren, pInfo->twAggSup.maxTs);
5,984✔
3580
  QUERY_CHECK_CODE(code, lino, _end);
5,982!
3581

3582
  code = copyUpdateResult(&pInfo->pStUpdated, pInfo->pUpdated, sessionKeyCompareAsc);
5,982✔
3583
  QUERY_CHECK_CODE(code, lino, _end);
5,983!
3584

3585
  if (!pInfo->destHasPrimaryKey) {
5,983!
3586
    removeSessionDeleteResults(pInfo->pStDeleted, pInfo->pUpdated);
5,985✔
3587
  }
3588
  if (pInfo->isHistoryOp) {
5,984✔
3589
    code = getMaxTsWins(pInfo->pUpdated, pInfo->historyWins);
208✔
3590
    QUERY_CHECK_CODE(code, lino, _end);
208!
3591
  }
3592
  if (pInfo->destHasPrimaryKey && IS_NORMAL_SESSION_OP(pOperator)) {
5,984!
3593
    code = copyDeleteSessionKey(pInfo->pPkDeleted, pInfo->pStDeleted);
×
3594
    QUERY_CHECK_CODE(code, lino, _end);
×
3595
  }
3596
  initGroupResInfoFromArrayList(&pInfo->groupResInfo, pInfo->pUpdated);
5,984✔
3597
  pInfo->pUpdated = NULL;
5,984✔
3598
  code = blockDataEnsureCapacity(pInfo->binfo.pRes, pOperator->resultInfo.capacity);
5,984✔
3599
  QUERY_CHECK_CODE(code, lino, _end);
5,985!
3600

3601
  SSDataBlock* opRes = NULL;
5,985✔
3602
  code = buildSessionResult(pOperator, &opRes);
5,985✔
3603
  QUERY_CHECK_CODE(code, lino, _end);
5,985!
3604
  if (opRes) {
5,985✔
3605
    (*ppRes) = opRes;
1,850✔
3606
    return code;
1,850✔
3607
  }
3608

3609
_end:
4,135✔
3610
  if (code != TSDB_CODE_SUCCESS) {
4,135!
UNCOV
3611
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
UNCOV
3612
    pTaskInfo->code = code;
×
UNCOV
3613
    T_LONG_JMP(pTaskInfo->env, code);
×
3614
  }
3615
  setStreamOperatorCompleted(pOperator);
4,135✔
3616
  (*ppRes) = NULL;
4,132✔
3617
  return code;
4,132✔
3618
}
3619

UNCOV
3620
static SSDataBlock* doStreamSessionAgg(SOperatorInfo* pOperator) {
×
UNCOV
3621
  SSDataBlock* pRes = NULL;
×
UNCOV
3622
  int32_t      code = doStreamSessionAggNext(pOperator, &pRes);
×
UNCOV
3623
  return pRes;
×
3624
}
3625

3626
void streamSessionReleaseState(SOperatorInfo* pOperator) {
191✔
3627
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
191✔
3628
  int32_t                        winSize = taosArrayGetSize(pInfo->historyWins) * sizeof(SSessionKey);
191✔
3629
  int32_t                        resSize = winSize + sizeof(TSKEY);
191✔
3630
  char*                          pBuff = taosMemoryCalloc(1, resSize);
191✔
3631
  if (!pBuff) {
191!
UNCOV
3632
    return;
×
3633
  }
3634
  memcpy(pBuff, pInfo->historyWins->pData, winSize);
191✔
3635
  memcpy(pBuff + winSize, &pInfo->twAggSup.maxTs, sizeof(TSKEY));
191✔
3636
  pInfo->streamAggSup.stateStore.streamStateSaveInfo(pInfo->streamAggSup.pState, STREAM_SESSION_OP_STATE_NAME,
191✔
3637
                                                     strlen(STREAM_SESSION_OP_STATE_NAME), pBuff, resSize);
3638
  pInfo->streamAggSup.stateStore.streamStateCommit(pInfo->streamAggSup.pState);
191✔
3639
  taosMemoryFreeClear(pBuff);
191!
3640
  SOperatorInfo* downstream = pOperator->pDownstream[0];
191✔
3641
  if (downstream->fpSet.releaseStreamStateFn) {
191!
3642
    downstream->fpSet.releaseStreamStateFn(downstream);
191✔
3643
  }
3644
}
3645

3646
void resetWinRange(STimeWindow* winRange) {
350✔
3647
  winRange->skey = INT64_MIN;
350✔
3648
  winRange->ekey = INT64_MAX;
350✔
3649
}
350✔
3650

3651
int32_t getSessionWindowInfoByKey(SStreamAggSupporter* pAggSup, SSessionKey* pKey, SResultWindowInfo* pWinInfo) {
346✔
3652
  int32_t code = TSDB_CODE_SUCCESS;
346✔
3653
  int32_t lino = 0;
346✔
3654
  int32_t rowSize = pAggSup->resultRowSize;
346✔
3655
  int32_t winCode = TSDB_CODE_SUCCESS;
346✔
3656
  code = pAggSup->stateStore.streamStateSessionGet(pAggSup->pState, pKey, (void**)&pWinInfo->pStatePos, &rowSize,
346✔
3657
                                                   &winCode);
3658
  QUERY_CHECK_CODE(code, lino, _end);
346!
3659

3660
  if (winCode == TSDB_CODE_SUCCESS) {
346!
3661
    pWinInfo->sessionWin = *pKey;
346✔
3662
    pWinInfo->isOutput = true;
346✔
3663
    if (pWinInfo->pStatePos->needFree) {
346!
3664
      pAggSup->stateStore.streamStateSessionDel(pAggSup->pState, &pWinInfo->sessionWin);
346✔
3665
    }
3666
  } else {
UNCOV
3667
    SET_SESSION_WIN_INVALID((*pWinInfo));
×
3668
  }
3669

3670
_end:
346✔
3671
  if (code != TSDB_CODE_SUCCESS) {
346!
UNCOV
3672
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
3673
  }
3674
  return code;
346✔
3675
}
3676

3677
void reloadAggSupFromDownStream(SOperatorInfo* downstream, SStreamAggSupporter* pAggSup) {
635✔
3678
  SStateStore* pAPI = &downstream->pTaskInfo->storageAPI.stateStore;
635✔
3679

3680
  if (downstream->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_SCAN) {
635✔
3681
    reloadAggSupFromDownStream(downstream->pDownstream[0], pAggSup);
205✔
3682
    return;
205✔
3683
  }
3684

3685
  SStreamScanInfo* pScanInfo = downstream->info;
430✔
3686
  pAggSup->pUpdateInfo = pScanInfo->pUpdateInfo;
430✔
3687
}
3688

3689
void streamSessionSemiReloadState(SOperatorInfo* pOperator) {
15✔
3690
  int32_t                        code = TSDB_CODE_SUCCESS;
15✔
3691
  int32_t                        lino = 0;
15✔
3692
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
15✔
3693
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
15✔
3694
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
15✔
3695
  resetWinRange(&pAggSup->winRange);
15✔
3696

3697
  SResultWindowInfo winInfo = {0};
15✔
3698
  int32_t           size = 0;
15✔
3699
  void*             pBuf = NULL;
15✔
3700
  code = pAggSup->stateStore.streamStateGetInfo(pAggSup->pState, STREAM_SESSION_OP_STATE_NAME,
15✔
3701
                                                strlen(STREAM_SESSION_OP_STATE_NAME), &pBuf, &size);
3702
  QUERY_CHECK_CODE(code, lino, _end);
15!
3703

3704
  int32_t      num = (size - sizeof(TSKEY)) / sizeof(SSessionKey);
15✔
3705
  SSessionKey* pSeKeyBuf = (SSessionKey*)pBuf;
15✔
3706
  for (int32_t i = 0; i < num; i++) {
40✔
3707
    SResultWindowInfo winInfo = {0};
25✔
3708
    code = getSessionWindowInfoByKey(pAggSup, pSeKeyBuf + i, &winInfo);
25✔
3709
    QUERY_CHECK_CODE(code, lino, _end);
25!
3710
    if (!IS_VALID_SESSION_WIN(winInfo)) {
25!
UNCOV
3711
      continue;
×
3712
    }
3713
    compactSessionSemiWindow(pOperator, &winInfo);
25✔
3714
    code = saveSessionOutputBuf(pAggSup, &winInfo);
25✔
3715
    QUERY_CHECK_CODE(code, lino, _end);
25!
3716
  }
3717
  TSKEY ts = *(TSKEY*)((char*)pBuf + size - sizeof(TSKEY));
15✔
3718
  taosMemoryFree(pBuf);
15✔
3719
  pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, ts);
15✔
3720
  pAggSup->stateStore.streamStateReloadInfo(pAggSup->pState, ts);
15✔
3721

3722
  SOperatorInfo* downstream = pOperator->pDownstream[0];
15✔
3723
  if (downstream->fpSet.reloadStreamStateFn) {
15!
3724
    downstream->fpSet.reloadStreamStateFn(downstream);
15✔
3725
  }
3726
  reloadAggSupFromDownStream(downstream, &pInfo->streamAggSup);
15✔
3727

3728
_end:
15✔
3729
  if (code != TSDB_CODE_SUCCESS) {
15!
UNCOV
3730
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
3731
  }
3732
}
15✔
3733

3734
void streamSessionReloadState(SOperatorInfo* pOperator) {
176✔
3735
  int32_t                        code = TSDB_CODE_SUCCESS;
176✔
3736
  int32_t                        lino = 0;
176✔
3737
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
176✔
3738
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
176✔
3739
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
176✔
3740
  resetWinRange(&pAggSup->winRange);
176✔
3741

3742
  int32_t size = 0;
176✔
3743
  void*   pBuf = NULL;
176✔
3744
  code = pAggSup->stateStore.streamStateGetInfo(pAggSup->pState, STREAM_SESSION_OP_STATE_NAME,
176✔
3745
                                                strlen(STREAM_SESSION_OP_STATE_NAME), &pBuf, &size);
3746

3747
  QUERY_CHECK_CODE(code, lino, _end);
176!
3748

3749
  int32_t      num = (size - sizeof(TSKEY)) / sizeof(SSessionKey);
176✔
3750
  SSessionKey* pSeKeyBuf = (SSessionKey*)pBuf;
176✔
3751

3752
  TSKEY ts = *(TSKEY*)((char*)pBuf + size - sizeof(TSKEY));
176✔
3753
  pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, ts);
176✔
3754
  pAggSup->stateStore.streamStateReloadInfo(pAggSup->pState, ts);
176✔
3755

3756
  if (!pInfo->pStUpdated && num > 0) {
176!
3757
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
70✔
3758
    pInfo->pStUpdated = tSimpleHashInit(64, hashFn);
70✔
3759
    QUERY_CHECK_NULL(pInfo->pStUpdated, code, lino, _end, terrno);
70!
3760
  }
3761
  for (int32_t i = 0; i < num; i++) {
338✔
3762
    SResultWindowInfo winInfo = {0};
162✔
3763
    code = getSessionWindowInfoByKey(pAggSup, pSeKeyBuf + i, &winInfo);
162✔
3764
    QUERY_CHECK_CODE(code, lino, _end);
162!
3765
    if (!IS_VALID_SESSION_WIN(winInfo)) {
162!
3766
      continue;
×
3767
    }
3768

3769
    int32_t winNum = 0;
162✔
3770
    code = compactSessionWindow(pOperator, &winInfo, pInfo->pStUpdated, pInfo->pStDeleted, true, &winNum);
162✔
3771
    QUERY_CHECK_CODE(code, lino, _end);
162!
3772

3773
    if (winNum > 0) {
162!
UNCOV
3774
      qDebug("===stream=== reload state. save result %" PRId64 ", %" PRIu64, winInfo.sessionWin.win.skey,
×
3775
             winInfo.sessionWin.groupId);
UNCOV
3776
      if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_AT_ONCE) {
×
UNCOV
3777
        code = saveResult(winInfo, pInfo->pStUpdated);
×
UNCOV
3778
        QUERY_CHECK_CODE(code, lino, _end);
×
UNCOV
3779
      } else if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_WINDOW_CLOSE) {
×
UNCOV
3780
        if (!isCloseWindow(&winInfo.sessionWin.win, &pInfo->twAggSup)) {
×
UNCOV
3781
          code = saveDeleteRes(pInfo->pStDeleted, winInfo.sessionWin);
×
UNCOV
3782
          QUERY_CHECK_CODE(code, lino, _end);
×
3783
        }
UNCOV
3784
        SSessionKey key = {0};
×
3785
        getSessionHashKey(&winInfo.sessionWin, &key);
×
UNCOV
3786
        code = tSimpleHashPut(pAggSup->pResultRows, &key, sizeof(SSessionKey), &winInfo, sizeof(SResultWindowInfo));
×
UNCOV
3787
        QUERY_CHECK_CODE(code, lino, _end);
×
3788
      }
3789
    }
3790
    code = saveSessionOutputBuf(pAggSup, &winInfo);
162✔
3791
    QUERY_CHECK_CODE(code, lino, _end);
162!
3792
  }
3793
  taosMemoryFree(pBuf);
176✔
3794

3795
  SOperatorInfo* downstream = pOperator->pDownstream[0];
176✔
3796
  if (downstream->fpSet.reloadStreamStateFn) {
176!
3797
    downstream->fpSet.reloadStreamStateFn(downstream);
176✔
3798
  }
3799
  reloadAggSupFromDownStream(downstream, &pInfo->streamAggSup);
176✔
3800

3801
_end:
176✔
3802
  if (code != TSDB_CODE_SUCCESS) {
176!
UNCOV
3803
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
3804
  }
3805
}
176✔
3806

3807
int32_t createStreamSessionAggOperatorInfo(SOperatorInfo* downstream, SPhysiNode* pPhyNode, SExecTaskInfo* pTaskInfo,
848✔
3808
                                           SReadHandle* pHandle, SOperatorInfo** pOptrInfo) {
3809
  QRY_PARAM_CHECK(pOptrInfo);
848!
3810

3811
  SSessionWinodwPhysiNode*       pSessionNode = (SSessionWinodwPhysiNode*)pPhyNode;
848✔
3812
  int32_t                        numOfCols = 0;
848✔
3813
  int32_t                        code = TSDB_CODE_OUT_OF_MEMORY;
848✔
3814
  int32_t                        lino = 0;
848✔
3815
  SStreamSessionAggOperatorInfo* pInfo = taosMemoryCalloc(1, sizeof(SStreamSessionAggOperatorInfo));
848✔
3816
  SOperatorInfo*                 pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo));
848✔
3817
  if (pInfo == NULL || pOperator == NULL) {
848!
UNCOV
3818
    code = terrno;
×
UNCOV
3819
    goto _error;
×
3820
  }
3821

3822
  pOperator->pTaskInfo = pTaskInfo;
848✔
3823

3824
  initResultSizeInfo(&pOperator->resultInfo, 4096);
848✔
3825
  if (pSessionNode->window.pExprs != NULL) {
848✔
3826
    int32_t    numOfScalar = 0;
1✔
3827
    SExprInfo* pScalarExprInfo = NULL;
1✔
3828
    code = createExprInfo(pSessionNode->window.pExprs, NULL, &pScalarExprInfo, &numOfScalar);
1✔
3829
    QUERY_CHECK_CODE(code, lino, _error);
1!
3830

3831
    code = initExprSupp(&pInfo->scalarSupp, pScalarExprInfo, numOfScalar, &pTaskInfo->storageAPI.functionStore);
1✔
3832
    if (code != TSDB_CODE_SUCCESS) {
1!
UNCOV
3833
      goto _error;
×
3834
    }
3835
  }
3836
  SExprSupp* pExpSup = &pOperator->exprSupp;
848✔
3837

3838
  SSDataBlock* pResBlock = createDataBlockFromDescNode(pPhyNode->pOutputDataBlockDesc);
848✔
3839
  QUERY_CHECK_NULL(pResBlock, code, lino, _error, terrno);
848!
3840
  pInfo->binfo.pRes = pResBlock;
848✔
3841

3842
  SExprInfo* pExprInfo = NULL;
848✔
3843
  code = createExprInfo(pSessionNode->window.pFuncs, NULL, &pExprInfo, &numOfCols);
848✔
3844
  QUERY_CHECK_CODE(code, lino, _error);
848!
3845

3846
  code = initBasicInfoEx(&pInfo->binfo, pExpSup, pExprInfo, numOfCols, pResBlock, &pTaskInfo->storageAPI.functionStore);
848✔
3847
  QUERY_CHECK_CODE(code, lino, _error);
848!
3848

3849
  pInfo->twAggSup = (STimeWindowAggSupp){
848✔
3850
      .waterMark = pSessionNode->window.watermark,
848✔
3851
      .calTrigger = pSessionNode->window.triggerType,
848✔
3852
      .maxTs = INT64_MIN,
3853
      .minTs = INT64_MAX,
3854
      .deleteMark = getDeleteMark(&pSessionNode->window, 0),
848✔
3855
  };
3856

3857
  pInfo->primaryTsIndex = ((SColumnNode*)pSessionNode->window.pTspk)->slotId;
848✔
3858
  code =
3859
      initStreamAggSupporter(&pInfo->streamAggSup, pExpSup, numOfCols, pSessionNode->gap, pTaskInfo->streamInfo.pState,
848✔
3860
                             0, 0, &pTaskInfo->storageAPI.stateStore, pHandle, &pInfo->twAggSup, GET_TASKID(pTaskInfo),
848✔
3861
                             &pTaskInfo->storageAPI, pInfo->primaryTsIndex, STREAM_STATE_BUFF_SORT, 1);
3862
  if (code != TSDB_CODE_SUCCESS) {
848!
UNCOV
3863
    goto _error;
×
3864
  }
3865

3866
  code = initExecTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &pTaskInfo->window);
848✔
3867
  QUERY_CHECK_CODE(code, lino, _error);
848!
3868

3869
  if (pSessionNode->window.pTsEnd) {
848!
3870
    pInfo->endTsIndex = ((SColumnNode*)pSessionNode->window.pTsEnd)->slotId;
848✔
3871
  }
3872

3873
  pInfo->order = TSDB_ORDER_ASC;
848✔
3874
  _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
848✔
3875
  pInfo->pStDeleted = tSimpleHashInit(64, hashFn);
848✔
3876
  QUERY_CHECK_NULL(pInfo->pStDeleted, code, lino, _error, terrno);
848!
3877
  pInfo->pDelIterator = NULL;
848✔
3878
  code = createSpecialDataBlock(STREAM_DELETE_RESULT, &pInfo->pDelRes);
848✔
3879
  QUERY_CHECK_CODE(code, lino, _error);
848!
3880

3881
  pInfo->pChildren = NULL;
848✔
3882
  pInfo->pPhyNode = pPhyNode;
848✔
3883
  pInfo->ignoreExpiredData = pSessionNode->window.igExpired;
848✔
3884
  pInfo->ignoreExpiredDataSaved = false;
848✔
3885
  pInfo->pUpdated = NULL;
848✔
3886
  pInfo->pStUpdated = NULL;
848✔
3887
  pInfo->dataVersion = 0;
848✔
3888
  pInfo->historyWins = taosArrayInit(4, sizeof(SSessionKey));
848✔
3889
  if (!pInfo->historyWins) {
848!
UNCOV
3890
    goto _error;
×
3891
  }
3892
  if (pHandle) {
848!
3893
    pInfo->isHistoryOp = pHandle->fillHistory;
848✔
3894
  }
3895

3896
  code = createSpecialDataBlock(STREAM_CHECKPOINT, &pInfo->pCheckpointRes);
848✔
3897
  QUERY_CHECK_CODE(code, lino, _error);
848!
3898

3899
  pInfo->clearState = false;
848✔
3900
  pInfo->recvGetAll = false;
848✔
3901
  pInfo->destHasPrimaryKey = pSessionNode->window.destHasPrimaryKey;
848✔
3902
  pInfo->pPkDeleted = tSimpleHashInit(64, hashFn);
848✔
3903
  QUERY_CHECK_NULL(pInfo->pPkDeleted, code, lino, _error, terrno);
848!
3904
  pInfo->pOperator = pOperator;
848✔
3905

3906
  pOperator->operatorType = QUERY_NODE_PHYSICAL_PLAN_STREAM_SESSION;
848✔
3907
  setOperatorInfo(pOperator, getStreamOpName(pOperator->operatorType), QUERY_NODE_PHYSICAL_PLAN_STREAM_SESSION, true,
848✔
3908
                  OP_NOT_OPENED, pInfo, pTaskInfo);
3909
  if (pPhyNode->type != QUERY_NODE_PHYSICAL_PLAN_STREAM_FINAL_SESSION) {
848✔
3910
    // for stream
3911
    void*   buff = NULL;
705✔
3912
    int32_t len = 0;
705✔
3913
    int32_t res =
3914
        pInfo->streamAggSup.stateStore.streamStateGetInfo(pInfo->streamAggSup.pState, STREAM_SESSION_OP_CHECKPOINT_NAME,
705✔
3915
                                                          strlen(STREAM_SESSION_OP_CHECKPOINT_NAME), &buff, &len);
3916
    if (res == TSDB_CODE_SUCCESS) {
705!
UNCOV
3917
      code = doStreamSessionDecodeOpState(buff, len, pOperator, true, NULL);
×
UNCOV
3918
      taosMemoryFree(buff);
×
UNCOV
3919
      QUERY_CHECK_CODE(code, lino, _error);
×
3920
    }
3921
  }
3922
  pOperator->fpSet =
3923
      createOperatorFpSet(optrDummyOpenFn, doStreamSessionAggNext, NULL, destroyStreamSessionAggOperatorInfo,
848✔
3924
                          optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
3925
  setOperatorStreamStateFn(pOperator, streamSessionReleaseState, streamSessionReloadState);
848✔
3926

3927
  if (downstream) {
848✔
3928
    pInfo->basic.primaryPkIndex = -1;
739✔
3929
    code = initDownStream(downstream, &pInfo->streamAggSup, pOperator->operatorType, pInfo->primaryTsIndex,
739✔
3930
                          &pInfo->twAggSup, &pInfo->basic);
739✔
3931
    QUERY_CHECK_CODE(code, lino, _error);
739!
3932

3933
    code = appendDownstream(pOperator, &downstream, 1);
739✔
3934
    QUERY_CHECK_CODE(code, lino, _error);
739!
3935
  }
3936

3937
  *pOptrInfo = pOperator;
848✔
3938
  return TSDB_CODE_SUCCESS;
848✔
3939

UNCOV
3940
_error:
×
UNCOV
3941
  if (pInfo != NULL) {
×
UNCOV
3942
    destroyStreamSessionAggOperatorInfo(pInfo);
×
3943
  }
3944
  destroyOperatorAndDownstreams(pOperator, &downstream, 1);
×
UNCOV
3945
  pTaskInfo->code = code;
×
UNCOV
3946
  qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
UNCOV
3947
  return code;
×
3948
}
3949

3950
static void clearStreamSessionOperator(SStreamSessionAggOperatorInfo* pInfo) {
807✔
3951
  tSimpleHashClear(pInfo->streamAggSup.pResultRows);
807✔
3952
  pInfo->streamAggSup.stateStore.streamStateSessionClear(pInfo->streamAggSup.pState);
807✔
3953
  pInfo->clearState = false;
807✔
3954
}
807✔
3955

3956
int32_t deleteSessionWinState(SStreamAggSupporter* pAggSup, SSDataBlock* pBlock, SSHashObj* pMapUpdate,
618✔
3957
                              SSHashObj* pMapDelete, SSHashObj* pPkDelete, bool needAdd) {
3958
  int32_t code = TSDB_CODE_SUCCESS;
618✔
3959
  int32_t lino = 0;
618✔
3960
  SArray* pWins = taosArrayInit(16, sizeof(SSessionKey));
618✔
3961
  if (!pWins) {
617!
UNCOV
3962
    code = terrno;
×
UNCOV
3963
    QUERY_CHECK_CODE(code, lino, _end);
×
3964
  }
3965
  code = doDeleteTimeWindows(pAggSup, pBlock, pWins);
617✔
3966
  QUERY_CHECK_CODE(code, lino, _end);
618!
3967

3968
  removeSessionResults(pAggSup, pMapUpdate, pWins);
618✔
3969
  code = copyDeleteWindowInfo(pWins, pMapDelete);
618✔
3970
  QUERY_CHECK_CODE(code, lino, _end);
618!
3971

3972
  if (needAdd) {
618!
UNCOV
3973
    code = copyDeleteWindowInfo(pWins, pPkDelete);
×
UNCOV
3974
    QUERY_CHECK_CODE(code, lino, _end);
×
3975
  }
3976
  taosArrayDestroy(pWins);
618✔
3977

3978
_end:
618✔
3979
  if (code != TSDB_CODE_SUCCESS) {
618!
UNCOV
3980
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
3981
  }
3982
  return code;
618✔
3983
}
3984

3985
static int32_t doStreamSessionSemiAggNext(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
1,294✔
3986
  int32_t                        code = TSDB_CODE_SUCCESS;
1,294✔
3987
  int32_t                        lino = 0;
1,294✔
3988
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
1,294✔
3989
  SOptrBasicInfo*                pBInfo = &pInfo->binfo;
1,294✔
3990
  TSKEY                          maxTs = INT64_MIN;
1,294✔
3991
  SExprSupp*                     pSup = &pOperator->exprSupp;
1,294✔
3992
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
1,294✔
3993
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
1,294✔
3994

3995
  qDebug("stask:%s  %s status: %d", GET_TASKID(pTaskInfo), getStreamOpName(pOperator->operatorType), pOperator->status);
1,294✔
3996
  if (pOperator->status == OP_EXEC_DONE) {
1,294!
UNCOV
3997
    (*ppRes) = NULL;
×
UNCOV
3998
    return code;
×
3999
  }
4000

4001
  {
4002
    SSDataBlock* opRes = NULL;
1,294✔
4003
    code = buildSessionResult(pOperator, &opRes);
1,294✔
4004
    QUERY_CHECK_CODE(code, lino, _end);
1,294!
4005
    if (opRes) {
1,294✔
4006
      (*ppRes) = opRes;
53✔
4007
      return code;
288✔
4008
    }
4009

4010
    if (pInfo->clearState) {
1,241✔
4011
      clearFunctionContext(&pOperator->exprSupp);
56✔
4012
      // semi session operator clear disk buffer
4013
      clearStreamSessionOperator(pInfo);
56✔
4014
    }
4015

4016
    if (pOperator->status == OP_RES_TO_RETURN) {
1,240✔
4017
      if (pInfo->reCkBlock) {
235!
UNCOV
4018
        pInfo->reCkBlock = false;
×
UNCOV
4019
        printDataBlock(pInfo->pCheckpointRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
UNCOV
4020
        (*ppRes) = pInfo->pCheckpointRes;
×
UNCOV
4021
        return code;
×
4022
      }
4023
      clearFunctionContext(&pOperator->exprSupp);
235✔
4024
      // semi session operator clear disk buffer
4025
      clearStreamSessionOperator(pInfo);
235✔
4026
      setStreamOperatorCompleted(pOperator);
235✔
4027
      (*ppRes) = NULL;
235✔
4028
      return code;
235✔
4029
    }
4030
  }
4031

4032
  SOperatorInfo* downstream = pOperator->pDownstream[0];
1,005✔
4033
  if (!pInfo->pUpdated) {
1,005✔
4034
    pInfo->pUpdated = taosArrayInit(16, sizeof(SResultWindowInfo));
806✔
4035
    QUERY_CHECK_NULL(pInfo->pUpdated, code, lino, _end, terrno);
807!
4036
  }
4037
  if (!pInfo->pStUpdated) {
1,006✔
4038
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
807✔
4039
    pInfo->pStUpdated = tSimpleHashInit(64, hashFn);
807✔
4040
    QUERY_CHECK_NULL(pInfo->pStUpdated, code, lino, _end, terrno);
807!
4041
  }
4042
  while (1) {
357✔
4043
    SSDataBlock* pBlock = NULL;
1,363✔
4044
    code = downstream->fpSet.getNextFn(downstream, &pBlock);
1,363✔
4045
    QUERY_CHECK_CODE(code, lino, _end);
1,362!
4046

4047
    if (pBlock == NULL) {
1,362✔
4048
      pOperator->status = OP_RES_TO_RETURN;
750✔
4049
      break;
750✔
4050
    }
4051
    printSpecDataBlock(pBlock, getStreamOpName(pOperator->operatorType), "recv", GET_TASKID(pTaskInfo));
612✔
4052
    setStreamOperatorState(&pInfo->basic, pBlock->info.type);
612✔
4053

4054
    if (pBlock->info.type == STREAM_DELETE_DATA || pBlock->info.type == STREAM_DELETE_RESULT ||
612✔
4055
        pBlock->info.type == STREAM_CLEAR) {
561✔
4056
      // gap must be 0
4057
      code = deleteSessionWinState(pAggSup, pBlock, pInfo->pStUpdated, pInfo->pStDeleted, NULL, false);
56✔
4058
      QUERY_CHECK_CODE(code, lino, _end);
56!
4059
      pInfo->clearState = true;
56✔
4060
      break;
56✔
4061
    } else if (pBlock->info.type == STREAM_GET_ALL) {
556!
4062
      code = getAllSessionWindow(pInfo->streamAggSup.pResultRows, pInfo->pStUpdated);
×
4063
      QUERY_CHECK_CODE(code, lino, _end);
×
4064
      continue;
15✔
4065
    } else if (pBlock->info.type == STREAM_CREATE_CHILD_TABLE) {
556✔
4066
      (*ppRes) = pBlock;
199✔
4067
      return code;
199✔
4068
    } else if (pBlock->info.type == STREAM_CHECKPOINT) {
357✔
4069
      pAggSup->stateStore.streamStateCommit(pAggSup->pState);
15✔
4070
      doStreamSessionSaveCheckpoint(pOperator);
15✔
4071
      continue;
15✔
4072
    } else {
4073
      if (pBlock->info.type != STREAM_NORMAL && pBlock->info.type != STREAM_INVALID) {
342!
UNCOV
4074
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
UNCOV
4075
        QUERY_CHECK_CODE(code, lino, _end);
×
4076
      }
4077
    }
4078

4079
    if (pInfo->scalarSupp.pExprInfo != NULL) {
342!
UNCOV
4080
      SExprSupp* pExprSup = &pInfo->scalarSupp;
×
UNCOV
4081
      code = projectApplyFunctions(pExprSup->pExprInfo, pBlock, pBlock, pExprSup->pCtx, pExprSup->numOfExprs, NULL);
×
UNCOV
4082
      QUERY_CHECK_CODE(code, lino, _end);
×
4083
    }
4084
    // the pDataBlock are always the same one, no need to call this again
4085
    code = setInputDataBlock(pSup, pBlock, TSDB_ORDER_ASC, MAIN_SCAN, true);
342✔
4086
    QUERY_CHECK_CODE(code, lino, _end);
342!
4087
    doStreamSessionAggImpl(pOperator, pBlock, pInfo->pStUpdated, NULL, false, false);
342✔
4088
    maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.window.ekey);
342✔
4089
  }
4090

4091
  pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, maxTs);
806✔
4092
  pBInfo->pRes->info.watermark = pInfo->twAggSup.maxTs;
806✔
4093

4094
  code = copyUpdateResult(&pInfo->pStUpdated, pInfo->pUpdated, sessionKeyCompareAsc);
806✔
4095
  QUERY_CHECK_CODE(code, lino, _end);
807!
4096

4097
  removeSessionDeleteResults(pInfo->pStDeleted, pInfo->pUpdated);
807✔
4098

4099
  if (pInfo->isHistoryOp) {
807✔
4100
    code = getMaxTsWins(pInfo->pUpdated, pInfo->historyWins);
15✔
4101
    QUERY_CHECK_CODE(code, lino, _end);
15!
4102
  }
4103

4104
  initGroupResInfoFromArrayList(&pInfo->groupResInfo, pInfo->pUpdated);
807✔
4105
  pInfo->pUpdated = NULL;
807✔
4106
  code = blockDataEnsureCapacity(pBInfo->pRes, pOperator->resultInfo.capacity);
807✔
4107
  QUERY_CHECK_CODE(code, lino, _end);
807!
4108

4109
  SSDataBlock* opRes = NULL;
807✔
4110
  code = buildSessionResult(pOperator, &opRes);
807✔
4111
  QUERY_CHECK_CODE(code, lino, _end);
807!
4112
  if (opRes) {
807✔
4113
    (*ppRes) = opRes;
291✔
4114
    return code;
291✔
4115
  }
4116

4117
_end:
516✔
4118
  if (code != TSDB_CODE_SUCCESS) {
516!
UNCOV
4119
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
UNCOV
4120
    pTaskInfo->code = code;
×
UNCOV
4121
    T_LONG_JMP(pTaskInfo->env, code);
×
4122
  }
4123

4124
  clearFunctionContext(&pOperator->exprSupp);
516✔
4125
  // semi session operator clear disk buffer
4126
  clearStreamSessionOperator(pInfo);
516✔
4127
  setStreamOperatorCompleted(pOperator);
516✔
4128
  (*ppRes) = NULL;
516✔
4129
  return code;
516✔
4130
}
4131

UNCOV
4132
static SSDataBlock* doStreamSessionSemiAgg(SOperatorInfo* pOperator) {
×
UNCOV
4133
  SSDataBlock* pRes = NULL;
×
UNCOV
4134
  int32_t      code = doStreamSessionSemiAggNext(pOperator, &pRes);
×
UNCOV
4135
  return pRes;
×
4136
}
4137

4138
int32_t createStreamFinalSessionAggOperatorInfo(SOperatorInfo* downstream, SPhysiNode* pPhyNode,
251✔
4139
                                                SExecTaskInfo* pTaskInfo, int32_t numOfChild, SReadHandle* pHandle,
4140
                                                SOperatorInfo** pOptrInfo) {
4141
  QRY_PARAM_CHECK(pOptrInfo);
251!
4142

4143
  int32_t        code = TSDB_CODE_SUCCESS;
251✔
4144
  int32_t        lino = 0;
251✔
4145
  SOperatorInfo* pOperator = NULL;
251✔
4146
  code = createStreamSessionAggOperatorInfo(downstream, pPhyNode, pTaskInfo, pHandle, &pOperator);
251✔
4147
  if (pOperator == NULL || code != 0) {
252!
UNCOV
4148
    downstream = NULL;
×
UNCOV
4149
    QUERY_CHECK_CODE(code, lino, _error);
×
4150
  }
4151

4152
  SStorageAPI*                   pAPI = &pTaskInfo->storageAPI;
252✔
4153
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
252✔
4154
  pOperator->operatorType = pPhyNode->type;
252✔
4155
  pInfo->pOperator = pOperator;
252✔
4156

4157
  if (pPhyNode->type != QUERY_NODE_PHYSICAL_PLAN_STREAM_FINAL_SESSION) {
252✔
4158
    pOperator->fpSet =
109✔
4159
        createOperatorFpSet(optrDummyOpenFn, doStreamSessionSemiAggNext, NULL, destroyStreamSessionAggOperatorInfo,
109✔
4160
                            optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
4161
    setOperatorStreamStateFn(pOperator, streamSessionReleaseState, streamSessionSemiReloadState);
109✔
4162
  }
4163
  setOperatorInfo(pOperator, getStreamOpName(pOperator->operatorType), pPhyNode->type, false, OP_NOT_OPENED, pInfo,
252✔
4164
                  pTaskInfo);
4165

4166
  if (numOfChild > 0) {
252✔
4167
    pInfo->pChildren = taosArrayInit(numOfChild, sizeof(void*));
34✔
4168
    QUERY_CHECK_NULL(pInfo->pChildren, code, lino, _error, terrno);
34!
4169
    for (int32_t i = 0; i < numOfChild; i++) {
143✔
4170
      SOperatorInfo* pChildOp = NULL;
109✔
4171
      code = createStreamFinalSessionAggOperatorInfo(NULL, pPhyNode, pTaskInfo, 0, pHandle, &pChildOp);
109✔
4172
      if (pChildOp == NULL || code != 0) {
109!
4173
        QUERY_CHECK_CODE(code, lino, _error);
×
4174
      }
4175

4176
      SStreamSessionAggOperatorInfo* pChInfo = pChildOp->info;
109✔
4177
      pChInfo->twAggSup.calTrigger = STREAM_TRIGGER_AT_ONCE;
109✔
4178
      pAPI->stateStore.streamStateSetNumber(pChInfo->streamAggSup.pState, i, pInfo->primaryTsIndex);
109✔
4179
      void* tmp = taosArrayPush(pInfo->pChildren, &pChildOp);
109✔
4180
      if (!tmp) {
109!
UNCOV
4181
        code = terrno;
×
UNCOV
4182
        QUERY_CHECK_CODE(code, lino, _error);
×
4183
      }
4184
    }
4185

4186
    void*   buff = NULL;
34✔
4187
    int32_t len = 0;
34✔
4188
    int32_t res =
4189
        pInfo->streamAggSup.stateStore.streamStateGetInfo(pInfo->streamAggSup.pState, STREAM_SESSION_OP_CHECKPOINT_NAME,
34✔
4190
                                                          strlen(STREAM_SESSION_OP_CHECKPOINT_NAME), &buff, &len);
4191
    if (res == TSDB_CODE_SUCCESS) {
34!
4192
      code = doStreamSessionDecodeOpState(buff, len, pOperator, true, NULL);
×
UNCOV
4193
      taosMemoryFree(buff);
×
4194
      QUERY_CHECK_CODE(code, lino, _error);
×
4195
    }
4196
  }
4197

4198
  if (!IS_FINAL_SESSION_OP(pOperator) || numOfChild == 0) {
252✔
4199
    pInfo->twAggSup.calTrigger = STREAM_TRIGGER_AT_ONCE;
218✔
4200
  }
4201

4202
  *pOptrInfo = pOperator;
252✔
4203
  return code;
252✔
4204

UNCOV
4205
_error:
×
UNCOV
4206
  if (pInfo != NULL) {
×
UNCOV
4207
    destroyStreamSessionAggOperatorInfo(pInfo);
×
4208
  }
UNCOV
4209
  if (pOperator != NULL) {
×
UNCOV
4210
    pOperator->info = NULL;
×
UNCOV
4211
    destroyOperator(pOperator);
×
4212
  }
UNCOV
4213
  pTaskInfo->code = code;
×
UNCOV
4214
  if (code != TSDB_CODE_SUCCESS) {
×
UNCOV
4215
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
4216
  }
UNCOV
4217
  return code;
×
4218
}
4219

4220
void destroyStreamStateOperatorInfo(void* param) {
328✔
4221
  if (param == NULL) {
328!
4222
    return;
×
4223
  }
4224
  SStreamStateAggOperatorInfo* pInfo = (SStreamStateAggOperatorInfo*)param;
328✔
4225
  cleanupBasicInfo(&pInfo->binfo);
328✔
4226
  if (pInfo->pOperator) {
328!
4227
    cleanupResultInfoInStream(pInfo->pOperator->pTaskInfo, pInfo->streamAggSup.pState, &pInfo->pOperator->exprSupp,
328✔
4228
                              &pInfo->groupResInfo);
4229
    pInfo->pOperator = NULL;
328✔
4230
  }
4231
  destroyStreamAggSupporter(&pInfo->streamAggSup);
328✔
4232
  clearGroupResInfo(&pInfo->groupResInfo);
328✔
4233
  taosArrayDestroyP(pInfo->pUpdated, destroyFlusedPos);
328✔
4234
  pInfo->pUpdated = NULL;
328✔
4235

4236
  cleanupExprSupp(&pInfo->scalarSupp);
328✔
4237
  if (pInfo->pChildren != NULL) {
328!
UNCOV
4238
    int32_t size = taosArrayGetSize(pInfo->pChildren);
×
UNCOV
4239
    for (int32_t i = 0; i < size; i++) {
×
UNCOV
4240
      SOperatorInfo* pChild = taosArrayGetP(pInfo->pChildren, i);
×
UNCOV
4241
      destroyOperator(pChild);
×
4242
    }
UNCOV
4243
    taosArrayDestroy(pInfo->pChildren);
×
4244
  }
4245
  colDataDestroy(&pInfo->twAggSup.timeWindowData);
328✔
4246
  blockDataDestroy(pInfo->pDelRes);
328✔
4247
  tSimpleHashCleanup(pInfo->pSeUpdated);
328✔
4248
  tSimpleHashCleanup(pInfo->pSeDeleted);
328✔
4249
  cleanupGroupResInfo(&pInfo->groupResInfo);
328✔
4250

4251
  taosArrayDestroy(pInfo->historyWins);
328✔
4252
  blockDataDestroy(pInfo->pCheckpointRes);
328✔
4253
  tSimpleHashCleanup(pInfo->pPkDeleted);
328✔
4254

4255
  taosMemoryFreeClear(param);
328!
4256
}
4257

4258
bool isTsInWindow(SStateWindowInfo* pWin, TSKEY ts) {
3,500✔
4259
  if (pWin->winInfo.sessionWin.win.skey <= ts && ts <= pWin->winInfo.sessionWin.win.ekey) {
3,500✔
4260
    return true;
1,118✔
4261
  }
4262
  return false;
2,382✔
4263
}
4264

4265
bool isEqualStateKey(SStateWindowInfo* pWin, char* pKeyData) {
5,836✔
4266
  return pKeyData && compareVal(pKeyData, pWin->pStateKey);
5,836!
4267
}
4268

4269
bool compareStateKey(void* data, void* key) {
2,316✔
4270
  if (!data || !key) {
2,316!
UNCOV
4271
    return true;
×
4272
  }
4273
  SStateKeys* stateKey = (SStateKeys*)key;
2,316✔
4274
  stateKey->pData = (char*)key + sizeof(SStateKeys);
2,316✔
4275
  return compareVal(data, stateKey);
2,316✔
4276
}
4277

4278
bool compareWinStateKey(SStateKeys* left, SStateKeys* right) {
131✔
4279
  if (!left || !right) {
131!
4280
    return false;
131✔
4281
  }
UNCOV
4282
  return compareVal(left->pData, right);
×
4283
}
4284

4285
int32_t getStateWindowInfoByKey(SStreamAggSupporter* pAggSup, SSessionKey* pKey, SStateWindowInfo* pCurWin,
131✔
4286
                                SStateWindowInfo* pNextWin) {
4287
  int32_t          code = TSDB_CODE_SUCCESS;
131✔
4288
  int32_t          lino = 0;
131✔
4289
  SStreamStateCur* pCur = NULL;
131✔
4290
  int32_t          size = pAggSup->resultRowSize;
131✔
4291
  pCurWin->winInfo.sessionWin.groupId = pKey->groupId;
131✔
4292
  pCurWin->winInfo.sessionWin.win.skey = pKey->win.skey;
131✔
4293
  pCurWin->winInfo.sessionWin.win.ekey = pKey->win.ekey;
131✔
4294
  code = getSessionWindowInfoByKey(pAggSup, pKey, &pCurWin->winInfo);
131✔
4295
  QUERY_CHECK_CODE(code, lino, _end);
131!
4296
  QUERY_CHECK_CONDITION((IS_VALID_SESSION_WIN(pCurWin->winInfo)), code, lino, _end,
131!
4297
                        TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR);
4298

4299
  pCurWin->pStateKey =
131✔
4300
      (SStateKeys*)((char*)pCurWin->winInfo.pStatePos->pRowBuff + (pAggSup->resultRowSize - pAggSup->stateKeySize));
131✔
4301
  pCurWin->pStateKey->bytes = pAggSup->stateKeySize - sizeof(SStateKeys);
131✔
4302
  pCurWin->pStateKey->type = pAggSup->stateKeyType;
131✔
4303
  pCurWin->pStateKey->pData = (char*)pCurWin->pStateKey + sizeof(SStateKeys);
131✔
4304
  pCurWin->pStateKey->isNull = false;
131✔
4305
  pCurWin->winInfo.isOutput = true;
131✔
4306
  if (pCurWin->winInfo.pStatePos->needFree) {
131!
4307
    pAggSup->stateStore.streamStateSessionDel(pAggSup->pState, &pCurWin->winInfo.sessionWin);
131✔
4308
  }
4309

4310
  qDebug("===stream===get state cur win buff. skey:%" PRId64 ", endkey:%" PRId64, pCurWin->winInfo.sessionWin.win.skey,
131✔
4311
         pCurWin->winInfo.sessionWin.win.ekey);
4312

4313
  pNextWin->winInfo.sessionWin = pCurWin->winInfo.sessionWin;
131✔
4314
  pCur = pAggSup->stateStore.streamStateSessionSeekKeyNext(pAggSup->pState, &pNextWin->winInfo.sessionWin);
131✔
4315
  int32_t nextSize = pAggSup->resultRowSize;
131✔
4316
  int32_t winCode = pAggSup->stateStore.streamStateSessionGetKVByCur(pCur, &pNextWin->winInfo.sessionWin,
131✔
4317
                                                                     (void**)&pNextWin->winInfo.pStatePos, &nextSize);
131✔
4318
  if (winCode != TSDB_CODE_SUCCESS) {
131!
4319
    SET_SESSION_WIN_INVALID(pNextWin->winInfo);
131✔
4320
  } else {
UNCOV
4321
    pNextWin->pStateKey =
×
UNCOV
4322
        (SStateKeys*)((char*)pNextWin->winInfo.pStatePos->pRowBuff + (pAggSup->resultRowSize - pAggSup->stateKeySize));
×
UNCOV
4323
    pNextWin->pStateKey->bytes = pAggSup->stateKeySize - sizeof(SStateKeys);
×
UNCOV
4324
    pNextWin->pStateKey->type = pAggSup->stateKeyType;
×
UNCOV
4325
    pNextWin->pStateKey->pData = (char*)pNextWin->pStateKey + sizeof(SStateKeys);
×
UNCOV
4326
    pNextWin->pStateKey->isNull = false;
×
UNCOV
4327
    pNextWin->winInfo.isOutput = true;
×
4328
  }
4329

4330
_end:
131✔
4331
  pAggSup->stateStore.streamStateFreeCur(pCur);
131✔
4332
  qDebug("===stream===get state next win buff. skey:%" PRId64 ", endkey:%" PRId64,
131✔
4333
         pNextWin->winInfo.sessionWin.win.skey, pNextWin->winInfo.sessionWin.win.ekey);
4334
  if (code != TSDB_CODE_SUCCESS) {
131!
UNCOV
4335
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
4336
  }
4337
  return code;
131✔
4338
}
4339

4340
int32_t setStateOutputBuf(SStreamAggSupporter* pAggSup, TSKEY ts, uint64_t groupId, char* pKeyData,
3,025✔
4341
                          SStateWindowInfo* pCurWin, SStateWindowInfo* pNextWin) {
4342
  int32_t          size = pAggSup->resultRowSize;
3,025✔
4343
  SStreamStateCur* pCur = NULL;
3,025✔
4344
  pCurWin->winInfo.sessionWin.groupId = groupId;
3,025✔
4345
  pCurWin->winInfo.sessionWin.win.skey = ts;
3,025✔
4346
  pCurWin->winInfo.sessionWin.win.ekey = ts;
3,025✔
4347
  int32_t code = TSDB_CODE_SUCCESS;
3,025✔
4348
  int32_t lino = 0;
3,025✔
4349
  int32_t winCode = TSDB_CODE_SUCCESS;
3,025✔
4350
  code = pAggSup->stateStore.streamStateStateAddIfNotExist(pAggSup->pState, &pCurWin->winInfo.sessionWin, pKeyData,
3,025✔
4351
                                                           pAggSup->stateKeySize, compareStateKey,
4352
                                                           (void**)&pCurWin->winInfo.pStatePos, &size, &winCode);
3,025✔
4353
  QUERY_CHECK_CODE(code, lino, _end);
3,025!
4354

4355
  pCurWin->pStateKey =
3,025✔
4356
      (SStateKeys*)((char*)pCurWin->winInfo.pStatePos->pRowBuff + (pAggSup->resultRowSize - pAggSup->stateKeySize));
3,025✔
4357
  pCurWin->pStateKey->bytes = pAggSup->stateKeySize - sizeof(SStateKeys);
3,025✔
4358
  pCurWin->pStateKey->type = pAggSup->stateKeyType;
3,025✔
4359
  pCurWin->pStateKey->pData = (char*)pCurWin->pStateKey + sizeof(SStateKeys);
3,025✔
4360
  pCurWin->pStateKey->isNull = false;
3,025✔
4361

4362
  if (winCode == TSDB_CODE_SUCCESS && !inWinRange(&pAggSup->winRange, &pCurWin->winInfo.sessionWin.win)) {
3,025!
UNCOV
4363
    winCode = TSDB_CODE_FAILED;
×
UNCOV
4364
    clearOutputBuf(pAggSup->pState, pCurWin->winInfo.pStatePos, &pAggSup->pSessionAPI->stateStore);
×
UNCOV
4365
    pCurWin->pStateKey =
×
4366
        (SStateKeys*)((char*)pCurWin->winInfo.pStatePos->pRowBuff + (pAggSup->resultRowSize - pAggSup->stateKeySize));
×
UNCOV
4367
    pCurWin->pStateKey->bytes = pAggSup->stateKeySize - sizeof(SStateKeys);
×
UNCOV
4368
    pCurWin->pStateKey->type = pAggSup->stateKeyType;
×
UNCOV
4369
    pCurWin->pStateKey->pData = (char*)pCurWin->pStateKey + sizeof(SStateKeys);
×
UNCOV
4370
    pCurWin->pStateKey->isNull = false;
×
UNCOV
4371
    pCurWin->winInfo.sessionWin.groupId = groupId;
×
UNCOV
4372
    pCurWin->winInfo.sessionWin.win.skey = ts;
×
UNCOV
4373
    pCurWin->winInfo.sessionWin.win.ekey = ts;
×
UNCOV
4374
    qDebug("===stream===reset state win key. skey:%" PRId64 ", endkey:%" PRId64, pCurWin->winInfo.sessionWin.win.skey,
×
4375
           pCurWin->winInfo.sessionWin.win.ekey);
4376
  }
4377

4378
  if (winCode == TSDB_CODE_SUCCESS) {
3,025✔
4379
    pCurWin->winInfo.isOutput = true;
1,941✔
4380
    if (pCurWin->winInfo.pStatePos->needFree) {
1,941✔
4381
      pAggSup->stateStore.streamStateSessionDel(pAggSup->pState, &pCurWin->winInfo.sessionWin);
7✔
4382
    }
4383
  } else if (pKeyData) {
1,084!
4384
    if (IS_VAR_DATA_TYPE(pAggSup->stateKeyType)) {
1,084!
4385
      varDataCopy(pCurWin->pStateKey->pData, pKeyData);
4✔
4386
    } else {
4387
      memcpy(pCurWin->pStateKey->pData, pKeyData, pCurWin->pStateKey->bytes);
1,080✔
4388
    }
4389
  }
4390

4391
  qDebug("===stream===set state cur win buff. skey:%" PRId64 ", endkey:%" PRId64, pCurWin->winInfo.sessionWin.win.skey,
3,025✔
4392
         pCurWin->winInfo.sessionWin.win.ekey);
4393

4394
  pNextWin->winInfo.sessionWin = pCurWin->winInfo.sessionWin;
3,025✔
4395
  pCur = pAggSup->stateStore.streamStateSessionSeekKeyNext(pAggSup->pState, &pNextWin->winInfo.sessionWin);
3,025✔
4396
  int32_t nextSize = pAggSup->resultRowSize;
3,025✔
4397
  winCode = pAggSup->stateStore.streamStateSessionGetKVByCur(pCur, &pNextWin->winInfo.sessionWin,
6,050✔
4398
                                                             (void**)&pNextWin->winInfo.pStatePos, &nextSize);
3,025✔
4399
  if (winCode != TSDB_CODE_SUCCESS) {
3,025✔
4400
    SET_SESSION_WIN_INVALID(pNextWin->winInfo);
2,980✔
4401
  } else {
4402
    pNextWin->pStateKey =
45✔
4403
        (SStateKeys*)((char*)pNextWin->winInfo.pStatePos->pRowBuff + (pAggSup->resultRowSize - pAggSup->stateKeySize));
45✔
4404
    pNextWin->pStateKey->bytes = pAggSup->stateKeySize - sizeof(SStateKeys);
45✔
4405
    pNextWin->pStateKey->type = pAggSup->stateKeyType;
45✔
4406
    pNextWin->pStateKey->pData = (char*)pNextWin->pStateKey + sizeof(SStateKeys);
45✔
4407
    pNextWin->pStateKey->isNull = false;
45✔
4408
    pNextWin->winInfo.isOutput = true;
45✔
4409
  }
4410
  qDebug("===stream===set state next win buff. skey:%" PRId64 ", endkey:%" PRId64,
3,025✔
4411
         pNextWin->winInfo.sessionWin.win.skey, pNextWin->winInfo.sessionWin.win.ekey);
4412
_end:
1,457✔
4413
  pAggSup->stateStore.streamStateFreeCur(pCur);
3,025✔
4414
  if (code != TSDB_CODE_SUCCESS) {
3,025!
4415
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
4416
  }
4417
  return code;
3,025✔
4418
}
4419

4420
int32_t updateStateWindowInfo(SStreamAggSupporter* pAggSup, SStateWindowInfo* pWinInfo, SStateWindowInfo* pNextWin,
3,025✔
4421
                              TSKEY* pTs, uint64_t groupId, SColumnInfoData* pKeyCol, int32_t rows, int32_t start,
4422
                              bool* allEqual, SSHashObj* pResultRows, SSHashObj* pSeUpdated, SSHashObj* pSeDeleted,
4423
                              int32_t* pWinRows) {
4424
  int32_t code = TSDB_CODE_SUCCESS;
3,025✔
4425
  int32_t lino = 0;
3,025✔
4426
  *allEqual = true;
3,025✔
4427
  for (int32_t i = start; i < rows; ++i) {
6,479✔
4428
    char* pKeyData = colDataGetData(pKeyCol, i);
3,500!
4429
    if (!isTsInWindow(pWinInfo, pTs[i])) {
3,500✔
4430
      if (isEqualStateKey(pWinInfo, pKeyData)) {
2,382✔
4431
        if (IS_VALID_SESSION_WIN(pNextWin->winInfo)) {
2,336✔
4432
          // ts belongs to the next window
4433
          if (pTs[i] >= pNextWin->winInfo.sessionWin.win.skey) {
22!
UNCOV
4434
            (*pWinRows) = i - start;
×
UNCOV
4435
            goto _end;
×
4436
          }
4437
        }
4438
      } else {
4439
        (*pWinRows) = i - start;
46✔
4440
        goto _end;
46✔
4441
      }
4442
    }
4443

4444
    if (pWinInfo->winInfo.sessionWin.win.skey > pTs[i]) {
3,454✔
4445
      if (pSeDeleted && pWinInfo->winInfo.isOutput) {
2!
4446
        code = saveDeleteRes(pSeDeleted, pWinInfo->winInfo.sessionWin);
2✔
4447
        QUERY_CHECK_CODE(code, lino, _end);
2!
4448
      }
4449
      removeSessionResult(pAggSup, pSeUpdated, pResultRows, &pWinInfo->winInfo.sessionWin);
2✔
4450
      pWinInfo->winInfo.sessionWin.win.skey = pTs[i];
2✔
4451
    }
4452
    pWinInfo->winInfo.sessionWin.win.ekey = TMAX(pWinInfo->winInfo.sessionWin.win.ekey, pTs[i]);
3,454✔
4453
    memcpy(pWinInfo->winInfo.pStatePos->pKey, &pWinInfo->winInfo.sessionWin, sizeof(SSessionKey));
3,454✔
4454
    if (!isEqualStateKey(pWinInfo, pKeyData)) {
3,454✔
4455
      *allEqual = false;
11✔
4456
    }
4457
  }
4458
  (*pWinRows) = rows - start;
2,979✔
4459

4460
_end:
3,025✔
4461
  if (code != TSDB_CODE_SUCCESS) {
3,025!
UNCOV
4462
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
4463
  }
4464
  return code;
3,025✔
4465
}
4466

4467
static void doStreamStateAggImpl(SOperatorInfo* pOperator, SSDataBlock* pSDataBlock, SSHashObj* pSeUpdated,
2,988✔
4468
                                 SSHashObj* pStDeleted) {
4469
  SExecTaskInfo* pTaskInfo = pOperator->pTaskInfo;
2,988✔
4470
  SStorageAPI*   pAPI = &pOperator->pTaskInfo->storageAPI;
2,988✔
4471

4472
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
2,988✔
4473
  int32_t                      numOfOutput = pOperator->exprSupp.numOfExprs;
2,988✔
4474
  uint64_t                     groupId = pSDataBlock->info.id.groupId;
2,988✔
4475
  int32_t                      code = TSDB_CODE_SUCCESS;
2,988✔
4476
  int32_t                      lino = 0;
2,988✔
4477
  TSKEY*                       tsCols = NULL;
2,988✔
4478
  SResultRow*                  pResult = NULL;
2,988✔
4479
  int32_t                      winRows = 0;
2,988✔
4480
  SStreamAggSupporter*         pAggSup = &pInfo->streamAggSup;
2,988✔
4481

4482
  pInfo->dataVersion = TMAX(pInfo->dataVersion, pSDataBlock->info.version);
2,988✔
4483
  pAggSup->winRange = pTaskInfo->streamInfo.fillHistoryWindow;
2,988✔
4484
  if (pAggSup->winRange.ekey <= 0) {
2,988!
UNCOV
4485
    pAggSup->winRange.ekey = INT64_MAX;
×
4486
  }
4487

4488
  if (pSDataBlock->pDataBlock != NULL) {
2,988!
4489
    SColumnInfoData* pColDataInfo = taosArrayGet(pSDataBlock->pDataBlock, pInfo->primaryTsIndex);
2,988✔
4490
    if (!pColDataInfo) {
2,988!
UNCOV
4491
      code = TSDB_CODE_FAILED;
×
UNCOV
4492
      QUERY_CHECK_CODE(code, lino, _end);
×
4493
    }
4494
    tsCols = (int64_t*)pColDataInfo->pData;
2,988✔
4495
  } else {
UNCOV
4496
    return;
×
4497
  }
4498

4499
  int32_t rows = pSDataBlock->info.rows;
2,988✔
4500
  code = blockDataEnsureCapacity(pAggSup->pScanBlock, rows);
2,988✔
4501
  QUERY_CHECK_CODE(code, lino, _end);
2,988!
4502

4503
  SColumnInfoData* pKeyColInfo = taosArrayGet(pSDataBlock->pDataBlock, pInfo->stateCol.slotId);
2,988✔
4504
  for (int32_t i = 0; i < rows; i += winRows) {
6,022✔
4505
    if (pInfo->ignoreExpiredData && checkExpiredData(&pInfo->streamAggSup.stateStore, pInfo->streamAggSup.pUpdateInfo,
3,056✔
4506
                                                     &pInfo->twAggSup, pSDataBlock->info.id.uid, tsCols[i], NULL, 0) ||
22✔
4507
        colDataIsNull_s(pKeyColInfo, i)) {
6,066✔
4508
      i++;
9✔
4509
      continue;
20✔
4510
    }
4511
    char*            pKeyData = colDataGetData(pKeyColInfo, i);
3,025!
4512
    int32_t          winIndex = 0;
3,025✔
4513
    bool             allEqual = true;
3,025✔
4514
    SStateWindowInfo curWin = {0};
3,025✔
4515
    SStateWindowInfo nextWin = {0};
3,025✔
4516
    code = setStateOutputBuf(pAggSup, tsCols[i], groupId, pKeyData, &curWin, &nextWin);
3,025✔
4517
    QUERY_CHECK_CODE(code, lino, _end);
3,025!
4518

4519
    releaseOutputBuf(pAggSup->pState, nextWin.winInfo.pStatePos, &pAPI->stateStore);
3,025✔
4520

4521
    setSessionWinOutputInfo(pSeUpdated, &curWin.winInfo);
3,025✔
4522
    code = updateStateWindowInfo(pAggSup, &curWin, &nextWin, tsCols, groupId, pKeyColInfo, rows, i, &allEqual,
3,025✔
4523
                                 pAggSup->pResultRows, pSeUpdated, pStDeleted, &winRows);
4524
    QUERY_CHECK_CODE(code, lino, _end);
3,025!
4525

4526
    if (!allEqual) {
3,025✔
4527
      uint64_t uid = 0;
11✔
4528
      code = appendDataToSpecialBlock(pAggSup->pScanBlock, &curWin.winInfo.sessionWin.win.skey,
11✔
4529
                                      &curWin.winInfo.sessionWin.win.ekey, &uid, &groupId, NULL);
4530
      QUERY_CHECK_CODE(code, lino, _end);
11!
4531
      int32_t tmpRes = tSimpleHashRemove(pSeUpdated, &curWin.winInfo.sessionWin, sizeof(SSessionKey));
11✔
4532
      qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
11!
4533

4534
      doDeleteSessionWindow(pAggSup, &curWin.winInfo.sessionWin);
11✔
4535
      releaseOutputBuf(pAggSup->pState, curWin.winInfo.pStatePos, &pAPI->stateStore);
11✔
4536
      continue;
11✔
4537
    }
4538

4539
    code = doOneWindowAggImpl(&pInfo->twAggSup.timeWindowData, &curWin.winInfo, &pResult, i, winRows, rows, numOfOutput,
3,014✔
4540
                              pOperator, 0);
4541
    QUERY_CHECK_CODE(code, lino, _end);
3,014!
4542

4543
    code = saveSessionOutputBuf(pAggSup, &curWin.winInfo);
3,014✔
4544
    QUERY_CHECK_CODE(code, lino, _end);
3,014!
4545

4546
    if (pInfo->destHasPrimaryKey && curWin.winInfo.isOutput && IS_NORMAL_STATE_OP(pOperator)) {
3,014!
UNCOV
4547
      code = saveDeleteRes(pInfo->pPkDeleted, curWin.winInfo.sessionWin);
×
UNCOV
4548
      QUERY_CHECK_CODE(code, lino, _end);
×
4549
    }
4550

4551
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_AT_ONCE) {
3,014✔
4552
      code = saveResult(curWin.winInfo, pSeUpdated);
2,773✔
4553
      QUERY_CHECK_CODE(code, lino, _end);
2,773!
4554
    }
4555

4556
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_WINDOW_CLOSE) {
3,014✔
4557
      curWin.winInfo.pStatePos->beUpdated = true;
241✔
4558
      SSessionKey key = {0};
241✔
4559
      getSessionHashKey(&curWin.winInfo.sessionWin, &key);
241✔
4560
      code =
4561
          tSimpleHashPut(pAggSup->pResultRows, &key, sizeof(SSessionKey), &curWin.winInfo, sizeof(SResultWindowInfo));
241✔
4562
      QUERY_CHECK_CODE(code, lino, _end);
241!
4563
    }
4564
  }
4565

4566
_end:
2,988✔
4567
  if (code != TSDB_CODE_SUCCESS) {
2,988!
UNCOV
4568
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
4569
  }
4570
}
4571

4572
int32_t doStreamStateEncodeOpState(void** buf, int32_t len, SOperatorInfo* pOperator, bool isParent) {
2✔
4573
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
2✔
4574
  if (!pInfo) {
2!
UNCOV
4575
    return 0;
×
4576
  }
4577

4578
  void* pData = (buf == NULL) ? NULL : *buf;
2✔
4579

4580
  // 1.streamAggSup.pResultRows
4581
  int32_t tlen = 0;
2✔
4582
  int32_t mapSize = tSimpleHashGetSize(pInfo->streamAggSup.pResultRows);
2✔
4583
  tlen += taosEncodeFixedI32(buf, mapSize);
2✔
4584
  void*   pIte = NULL;
2✔
4585
  size_t  keyLen = 0;
2✔
4586
  int32_t iter = 0;
2✔
4587
  while ((pIte = tSimpleHashIterate(pInfo->streamAggSup.pResultRows, pIte, &iter)) != NULL) {
4✔
4588
    void* key = tSimpleHashGetKey(pIte, &keyLen);
2✔
4589
    tlen += encodeSSessionKey(buf, key);
2✔
4590
    tlen += encodeSResultWindowInfo(buf, pIte, pInfo->streamAggSup.resultRowSize);
2✔
4591
  }
4592

4593
  // 2.twAggSup
4594
  tlen += encodeSTimeWindowAggSupp(buf, &pInfo->twAggSup);
2✔
4595

4596
  // 3.pChildren
4597
  int32_t size = taosArrayGetSize(pInfo->pChildren);
2✔
4598
  tlen += taosEncodeFixedI32(buf, size);
2✔
4599
  for (int32_t i = 0; i < size; i++) {
2!
UNCOV
4600
    SOperatorInfo* pChOp = taosArrayGetP(pInfo->pChildren, i);
×
4601
    tlen += doStreamStateEncodeOpState(buf, 0, pChOp, false);
×
4602
  }
4603

4604
  // 4.dataVersion
4605
  tlen += taosEncodeFixedI64(buf, pInfo->dataVersion);
2✔
4606

4607
  // 5.checksum
4608
  if (isParent) {
2!
4609
    if (buf) {
2✔
4610
      uint32_t cksum = taosCalcChecksum(0, pData, len - sizeof(uint32_t));
2!
4611
      tlen += taosEncodeFixedU32(buf, cksum);
1✔
4612
    } else {
4613
      tlen += sizeof(uint32_t);
1✔
4614
    }
4615
  }
4616

4617
  return tlen;
2✔
4618
}
4619

UNCOV
4620
int32_t doStreamStateDecodeOpState(void* buf, int32_t len, SOperatorInfo* pOperator, bool isParent, void** ppBuf) {
×
UNCOV
4621
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
×
UNCOV
4622
  int32_t                      code = TSDB_CODE_SUCCESS;
×
UNCOV
4623
  int32_t                      lino = 0;
×
4624
  SStreamAggSupporter*         pAggSup = &pInfo->streamAggSup;
×
4625
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
×
4626
  if (!pInfo) {
×
4627
    code = TSDB_CODE_FAILED;
×
4628
    QUERY_CHECK_CODE(code, lino, _end);
×
4629
  }
4630

4631
  // 5.checksum
UNCOV
4632
  if (isParent) {
×
4633
    int32_t dataLen = len - sizeof(uint32_t);
×
UNCOV
4634
    void*   pCksum = POINTER_SHIFT(buf, dataLen);
×
4635
    if (taosCheckChecksum(buf, dataLen, *(uint32_t*)pCksum) != TSDB_CODE_SUCCESS) {
×
4636
      qError("stream state_window state is invalid");
×
UNCOV
4637
      code = TSDB_CODE_FAILED;
×
4638
      QUERY_CHECK_CODE(code, lino, _end);
×
4639
    }
4640
  }
4641

4642
  // 1.streamAggSup.pResultRows
UNCOV
4643
  int32_t mapSize = 0;
×
UNCOV
4644
  buf = taosDecodeFixedI32(buf, &mapSize);
×
4645
  for (int32_t i = 0; i < mapSize; i++) {
×
4646
    SResultWindowInfo winfo = {0};
×
4647
    buf = decodeSSessionKey(buf, &winfo.sessionWin);
×
4648
    int32_t winCode = TSDB_CODE_SUCCESS;
×
4649
    code = pAggSup->stateStore.streamStateStateAddIfNotExist(
×
4650
        pAggSup->pState, &winfo.sessionWin, NULL, pAggSup->stateKeySize, compareStateKey, (void**)&winfo.pStatePos,
4651
        &pAggSup->resultRowSize, &winCode);
UNCOV
4652
    QUERY_CHECK_CODE(code, lino, _end);
×
4653

4654
    buf = decodeSResultWindowInfo(buf, &winfo, pInfo->streamAggSup.resultRowSize);
×
UNCOV
4655
    code = tSimpleHashPut(pInfo->streamAggSup.pResultRows, &winfo.sessionWin, sizeof(SSessionKey), &winfo,
×
4656
                          sizeof(SResultWindowInfo));
4657
    QUERY_CHECK_CODE(code, lino, _end);
×
4658
  }
4659

4660
  // 2.twAggSup
4661
  buf = decodeSTimeWindowAggSupp(buf, &pInfo->twAggSup);
×
4662

4663
  // 3.pChildren
4664
  int32_t size = 0;
×
UNCOV
4665
  buf = taosDecodeFixedI32(buf, &size);
×
UNCOV
4666
  for (int32_t i = 0; i < size; i++) {
×
UNCOV
4667
    SOperatorInfo* pChOp = taosArrayGetP(pInfo->pChildren, i);
×
UNCOV
4668
    code = doStreamStateDecodeOpState(buf, 0, pChOp, false, &buf);
×
UNCOV
4669
    QUERY_CHECK_CODE(code, lino, _end);
×
4670
  }
4671

4672
  // 4.dataVersion
4673
  buf = taosDecodeFixedI64(buf, &pInfo->dataVersion);
×
4674

UNCOV
4675
  if (ppBuf) {
×
UNCOV
4676
    (*ppBuf) = buf;
×
4677
  }
4678

UNCOV
4679
_end:
×
UNCOV
4680
  if (code != TSDB_CODE_SUCCESS) {
×
UNCOV
4681
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
4682
  }
UNCOV
4683
  return code;
×
4684
}
4685

4686
void doStreamStateSaveCheckpoint(SOperatorInfo* pOperator) {
457✔
4687
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
457✔
4688
  if (needSaveStreamOperatorInfo(&pInfo->basic)) {
457✔
4689
    int32_t len = doStreamStateEncodeOpState(NULL, 0, pOperator, true);
1✔
4690
    void*   buf = taosMemoryCalloc(1, len);
1✔
4691
    if (!buf) {
1!
UNCOV
4692
      qError("%s failed at line %d since %s", __func__, __LINE__, tstrerror(TSDB_CODE_OUT_OF_MEMORY));
×
UNCOV
4693
      return;
×
4694
    }
4695
    void* pBuf = buf;
1✔
4696
    len = doStreamStateEncodeOpState(&pBuf, len, pOperator, true);
1✔
4697
    pInfo->streamAggSup.stateStore.streamStateSaveInfo(pInfo->streamAggSup.pState, STREAM_STATE_OP_CHECKPOINT_NAME,
1✔
4698
                                                       strlen(STREAM_STATE_OP_CHECKPOINT_NAME), buf, len);
4699
    taosMemoryFree(buf);
1✔
4700
    saveStreamOperatorStateComplete(&pInfo->basic);
1✔
4701
  }
4702
}
4703

4704
static int32_t buildStateResult(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
4,729✔
4705
  int32_t                      code = TSDB_CODE_SUCCESS;
4,729✔
4706
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
4,729✔
4707
  SOptrBasicInfo*              pBInfo = &pInfo->binfo;
4,729✔
4708
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
4,729✔
4709

4710
  doBuildDeleteDataBlock(pOperator, pInfo->pSeDeleted, pInfo->pDelRes, &pInfo->pDelIterator);
4,729✔
4711
  if (pInfo->pDelRes->info.rows > 0) {
4,729✔
4712
    printDataBlock(pInfo->pDelRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
195✔
4713
    (*ppRes) = pInfo->pDelRes;
195✔
4714
    return code;
195✔
4715
  }
4716

4717
  doBuildSessionResult(pOperator, pInfo->streamAggSup.pState, &pInfo->groupResInfo, pBInfo->pRes);
4,534✔
4718
  if (pBInfo->pRes->info.rows > 0) {
4,533✔
4719
    printDataBlock(pBInfo->pRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
1,380✔
4720
    (*ppRes) = pBInfo->pRes;
1,382✔
4721
    return code;
1,382✔
4722
  }
4723
  (*ppRes) = NULL;
3,153✔
4724
  return code;
3,153✔
4725
}
4726

4727
static int32_t doStreamStateAggNext(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
5,132✔
4728
  if (pOperator->status == OP_EXEC_DONE) {
5,132!
UNCOV
4729
    (*ppRes) = NULL;
×
UNCOV
4730
    return TSDB_CODE_SUCCESS;
×
4731
  }
4732

4733
  int32_t                      code = TSDB_CODE_SUCCESS;
5,132✔
4734
  int32_t                      lino = 0;
5,132✔
4735
  SExprSupp*                   pSup = &pOperator->exprSupp;
5,132✔
4736
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
5,132✔
4737
  SOptrBasicInfo*              pBInfo = &pInfo->binfo;
5,132✔
4738
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
5,132✔
4739
  qDebug("===stream=== stream state agg");
5,132✔
4740
  if (pOperator->status == OP_RES_TO_RETURN) {
5,132✔
4741
    SSDataBlock* resBlock = NULL;
1,577✔
4742
    code = buildStateResult(pOperator, &resBlock);
1,577✔
4743
    QUERY_CHECK_CODE(code, lino, _end);
1,577!
4744
    if (resBlock != NULL) {
1,577✔
4745
      (*ppRes) = resBlock;
348✔
4746
      return code;
1,577✔
4747
    }
4748

4749
    if (pInfo->recvGetAll) {
1,229✔
4750
      pInfo->recvGetAll = false;
2✔
4751
      resetUnCloseSessionWinInfo(pInfo->streamAggSup.pResultRows);
2✔
4752
    }
4753

4754
    if (pInfo->reCkBlock) {
1,229!
UNCOV
4755
      pInfo->reCkBlock = false;
×
UNCOV
4756
      printDataBlock(pInfo->pCheckpointRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
UNCOV
4757
      (*ppRes) = pInfo->pCheckpointRes;
×
UNCOV
4758
      return code;
×
4759
    }
4760

4761
    setStreamOperatorCompleted(pOperator);
1,229✔
4762
    (*ppRes) = NULL;
1,229✔
4763
    return code;
1,229✔
4764
  }
4765

4766
  SOperatorInfo* downstream = pOperator->pDownstream[0];
3,555✔
4767
  if (!pInfo->pUpdated) {
3,555✔
4768
    pInfo->pUpdated = taosArrayInit(16, sizeof(SResultWindowInfo));
3,154✔
4769
    QUERY_CHECK_NULL(pInfo->pUpdated, code, lino, _end, terrno);
3,154!
4770
  }
4771
  if (!pInfo->pSeUpdated) {
3,555✔
4772
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
3,120✔
4773
    pInfo->pSeUpdated = tSimpleHashInit(64, hashFn);
3,120✔
4774
    QUERY_CHECK_NULL(pInfo->pSeUpdated, code, lino, _end, terrno);
3,119!
4775
  }
4776
  while (1) {
3,958✔
4777
    SSDataBlock* pBlock = NULL;
7,512✔
4778
    code = downstream->fpSet.getNextFn(downstream, &pBlock);
7,512✔
4779
    QUERY_CHECK_CODE(code, lino, _end);
7,511!
4780

4781
    if (pBlock == NULL) {
7,511✔
4782
      break;
3,153✔
4783
    }
4784
    printSpecDataBlock(pBlock, getStreamOpName(pOperator->operatorType), "recv", GET_TASKID(pTaskInfo));
4,358✔
4785
    setStreamOperatorState(&pInfo->basic, pBlock->info.type);
4,355✔
4786

4787
    if (pBlock->info.type == STREAM_DELETE_DATA || pBlock->info.type == STREAM_DELETE_RESULT ||
4,358✔
4788
        pBlock->info.type == STREAM_CLEAR) {
3,881✔
4789
      bool add = pInfo->destHasPrimaryKey && IS_NORMAL_STATE_OP(pOperator);
498!
4790
      code = deleteSessionWinState(&pInfo->streamAggSup, pBlock, pInfo->pSeUpdated, pInfo->pSeDeleted,
498✔
4791
                                   pInfo->pPkDeleted, add);
4792
      QUERY_CHECK_CODE(code, lino, _end);
498!
4793
      continue;
970✔
4794
    } else if (pBlock->info.type == STREAM_GET_ALL) {
3,860✔
4795
      pInfo->recvGetAll = true;
9✔
4796
      code = getAllSessionWindow(pInfo->streamAggSup.pResultRows, pInfo->pSeUpdated);
9✔
4797
      QUERY_CHECK_CODE(code, lino, _end);
9!
4798
      continue;
9✔
4799
    } else if (pBlock->info.type == STREAM_CREATE_CHILD_TABLE) {
3,851✔
4800
      (*ppRes) = pBlock;
402✔
4801
      return code;
402✔
4802
    } else if (pBlock->info.type == STREAM_CHECKPOINT) {
3,449✔
4803
      pInfo->streamAggSup.stateStore.streamStateCommit(pInfo->streamAggSup.pState);
459✔
4804
      doStreamStateSaveCheckpoint(pOperator);
456✔
4805
      code = copyDataBlock(pInfo->pCheckpointRes, pBlock);
453✔
4806
      QUERY_CHECK_CODE(code, lino, _end);
463!
4807

4808
      continue;
463✔
4809
    } else {
4810
      if (pBlock->info.type != STREAM_NORMAL && pBlock->info.type != STREAM_INVALID) {
2,990!
UNCOV
4811
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
UNCOV
4812
        QUERY_CHECK_CODE(code, lino, _end);
×
4813
      }
4814
    }
4815

4816
    if (pInfo->scalarSupp.pExprInfo != NULL) {
2,990✔
4817
      SExprSupp* pExprSup = &pInfo->scalarSupp;
256✔
4818
      code = projectApplyFunctions(pExprSup->pExprInfo, pBlock, pBlock, pExprSup->pCtx, pExprSup->numOfExprs, NULL);
256✔
4819
      QUERY_CHECK_CODE(code, lino, _end);
256!
4820
    }
4821
    // the pDataBlock are always the same one, no need to call this again
4822
    code = setInputDataBlock(pSup, pBlock, TSDB_ORDER_ASC, MAIN_SCAN, true);
2,990✔
4823
    QUERY_CHECK_CODE(code, lino, _end);
2,988!
4824
    doStreamStateAggImpl(pOperator, pBlock, pInfo->pSeUpdated, pInfo->pSeDeleted);
2,988✔
4825
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.window.ekey);
2,988✔
4826
  }
4827
  // restore the value
4828
  pOperator->status = OP_RES_TO_RETURN;
3,153✔
4829

4830
  code = closeSessionWindow(pInfo->streamAggSup.pResultRows, &pInfo->twAggSup, pInfo->pSeUpdated);
3,153✔
4831
  QUERY_CHECK_CODE(code, lino, _end);
3,152!
4832

4833
  code = copyUpdateResult(&pInfo->pSeUpdated, pInfo->pUpdated, sessionKeyCompareAsc);
3,152✔
4834
  QUERY_CHECK_CODE(code, lino, _end);
3,152!
4835

4836
  removeSessionDeleteResults(pInfo->pSeDeleted, pInfo->pUpdated);
3,152✔
4837

4838
  if (pInfo->isHistoryOp) {
3,154✔
4839
    code = getMaxTsWins(pInfo->pUpdated, pInfo->historyWins);
104✔
4840
    QUERY_CHECK_CODE(code, lino, _end);
104!
4841
  }
4842
  if (pInfo->destHasPrimaryKey && IS_NORMAL_STATE_OP(pOperator)) {
3,154!
4843
    code = copyDeleteSessionKey(pInfo->pPkDeleted, pInfo->pSeDeleted);
×
4844
    QUERY_CHECK_CODE(code, lino, _end);
×
4845
  }
4846

4847
  initGroupResInfoFromArrayList(&pInfo->groupResInfo, pInfo->pUpdated);
3,154✔
4848
  pInfo->pUpdated = NULL;
3,149✔
4849
  code = blockDataEnsureCapacity(pInfo->binfo.pRes, pOperator->resultInfo.capacity);
3,149✔
4850
  QUERY_CHECK_CODE(code, lino, _end);
3,152!
4851

4852
  SSDataBlock* resBlock = NULL;
3,152✔
4853
  code = buildStateResult(pOperator, &resBlock);
3,152✔
4854
  QUERY_CHECK_CODE(code, lino, _end);
3,153!
4855
  if (resBlock != NULL) {
3,153✔
4856
    (*ppRes) = resBlock;
1,229✔
4857
    return code;
1,229✔
4858
  }
4859

4860
_end:
1,924✔
4861
  if (code != TSDB_CODE_SUCCESS) {
1,924!
UNCOV
4862
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
UNCOV
4863
    pTaskInfo->code = code;
×
4864
    T_LONG_JMP(pTaskInfo->env, code);
×
4865
  }
4866
  setStreamOperatorCompleted(pOperator);
1,924✔
4867
  (*ppRes) = NULL;
1,922✔
4868
  return code;
1,922✔
4869
}
4870

UNCOV
4871
static SSDataBlock* doStreamStateAgg(SOperatorInfo* pOperator) {
×
UNCOV
4872
  SSDataBlock* pRes = NULL;
×
UNCOV
4873
  int32_t      code = doStreamStateAggNext(pOperator, &pRes);
×
UNCOV
4874
  return pRes;
×
4875
}
4876

4877
void streamStateReleaseState(SOperatorInfo* pOperator) {
87✔
4878
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
87✔
4879
  int32_t                      winSize = taosArrayGetSize(pInfo->historyWins) * sizeof(SSessionKey);
87✔
4880
  int32_t                      resSize = winSize + sizeof(TSKEY);
87✔
4881
  char*                        pBuff = taosMemoryCalloc(1, resSize);
87✔
4882
  if (!pBuff) {
87!
4883
    return;
×
4884
  }
4885
  memcpy(pBuff, pInfo->historyWins->pData, winSize);
87✔
4886
  memcpy(pBuff + winSize, &pInfo->twAggSup.maxTs, sizeof(TSKEY));
87✔
4887
  qDebug("===stream=== relase state. save result count:%d", (int32_t)taosArrayGetSize(pInfo->historyWins));
87✔
4888
  pInfo->streamAggSup.stateStore.streamStateSaveInfo(pInfo->streamAggSup.pState, STREAM_STATE_OP_STATE_NAME,
87✔
4889
                                                     strlen(STREAM_STATE_OP_STATE_NAME), pBuff, resSize);
4890
  pInfo->streamAggSup.stateStore.streamStateCommit(pInfo->streamAggSup.pState);
86✔
4891
  taosMemoryFreeClear(pBuff);
87!
4892

4893
  SOperatorInfo* downstream = pOperator->pDownstream[0];
87✔
4894
  if (downstream->fpSet.releaseStreamStateFn) {
87!
4895
    downstream->fpSet.releaseStreamStateFn(downstream);
87✔
4896
  }
4897
}
4898

UNCOV
4899
static int32_t compactStateWindow(SOperatorInfo* pOperator, SResultWindowInfo* pCurWin, SResultWindowInfo* pNextWin,
×
4900
                                  SSHashObj* pStUpdated, SSHashObj* pStDeleted) {
UNCOV
4901
  SExprSupp*                   pSup = &pOperator->exprSupp;
×
UNCOV
4902
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
×
UNCOV
4903
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
×
UNCOV
4904
  return compactTimeWindow(pSup, &pInfo->streamAggSup, &pInfo->twAggSup, pTaskInfo, pCurWin, pNextWin, pStUpdated,
×
4905
                           pStDeleted, false);
4906
}
4907

4908
void streamStateReloadState(SOperatorInfo* pOperator) {
87✔
4909
  int32_t                      code = TSDB_CODE_SUCCESS;
87✔
4910
  int32_t                      lino = 0;
87✔
4911
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
87✔
4912
  SStreamAggSupporter*         pAggSup = &pInfo->streamAggSup;
87✔
4913
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
87✔
4914
  resetWinRange(&pAggSup->winRange);
87✔
4915

4916
  SSessionKey seKey = {.win.skey = INT64_MIN, .win.ekey = INT64_MIN, .groupId = 0};
87✔
4917
  int32_t     size = 0;
87✔
4918
  void*       pBuf = NULL;
87✔
4919
  code = pAggSup->stateStore.streamStateGetInfo(pAggSup->pState, STREAM_STATE_OP_STATE_NAME,
87✔
4920
                                                strlen(STREAM_STATE_OP_STATE_NAME), &pBuf, &size);
4921
  QUERY_CHECK_CODE(code, lino, _end);
87!
4922

4923
  int32_t num = (size - sizeof(TSKEY)) / sizeof(SSessionKey);
87✔
4924
  qDebug("===stream=== reload state. get result count:%d", num);
87✔
4925
  SSessionKey* pSeKeyBuf = (SSessionKey*)pBuf;
87✔
4926

4927
  TSKEY ts = *(TSKEY*)((char*)pBuf + size - sizeof(TSKEY));
87✔
4928
  pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, ts);
87✔
4929
  pAggSup->stateStore.streamStateReloadInfo(pAggSup->pState, ts);
87✔
4930

4931
  if (!pInfo->pSeUpdated && num > 0) {
87!
4932
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
34✔
4933
    pInfo->pSeUpdated = tSimpleHashInit(64, hashFn);
34✔
4934
    QUERY_CHECK_NULL(pInfo->pSeUpdated, code, lino, _end, terrno);
34!
4935
  }
4936
  if (!pInfo->pSeDeleted && num > 0) {
87!
4937
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
×
UNCOV
4938
    pInfo->pSeDeleted = tSimpleHashInit(64, hashFn);
×
4939
    QUERY_CHECK_NULL(pInfo->pSeDeleted, code, lino, _end, terrno);
×
4940
  }
4941
  for (int32_t i = 0; i < num; i++) {
218✔
4942
    SStateWindowInfo curInfo = {0};
131✔
4943
    SStateWindowInfo nextInfo = {0};
131✔
4944
    qDebug("===stream=== reload state. try process result %" PRId64 ", %" PRIu64 ", index:%d", pSeKeyBuf[i].win.skey,
131✔
4945
           pSeKeyBuf[i].groupId, i);
4946
    code = getStateWindowInfoByKey(pAggSup, pSeKeyBuf + i, &curInfo, &nextInfo);
131✔
4947
    QUERY_CHECK_CODE(code, lino, _end);
131!
4948

4949
    bool cpRes = compareWinStateKey(curInfo.pStateKey, nextInfo.pStateKey);
131✔
4950
    qDebug("===stream=== reload state. next window info %" PRId64 ", %" PRIu64 ", compare:%d",
131✔
4951
           nextInfo.winInfo.sessionWin.win.skey, nextInfo.winInfo.sessionWin.groupId, cpRes);
4952
    if (cpRes) {
131!
UNCOV
4953
      code = compactStateWindow(pOperator, &curInfo.winInfo, &nextInfo.winInfo, pInfo->pSeUpdated, pInfo->pSeDeleted);
×
4954
      qDebug("===stream=== reload state. save result %" PRId64 ", %" PRIu64, curInfo.winInfo.sessionWin.win.skey,
×
4955
             curInfo.winInfo.sessionWin.groupId);
UNCOV
4956
      QUERY_CHECK_CODE(code, lino, _end);
×
4957

UNCOV
4958
      if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_AT_ONCE) {
×
UNCOV
4959
        code = saveResult(curInfo.winInfo, pInfo->pSeUpdated);
×
UNCOV
4960
        QUERY_CHECK_CODE(code, lino, _end);
×
UNCOV
4961
      } else if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_WINDOW_CLOSE) {
×
UNCOV
4962
        if (!isCloseWindow(&curInfo.winInfo.sessionWin.win, &pInfo->twAggSup)) {
×
UNCOV
4963
          code = saveDeleteRes(pInfo->pSeDeleted, curInfo.winInfo.sessionWin);
×
UNCOV
4964
          QUERY_CHECK_CODE(code, lino, _end);
×
4965
        }
UNCOV
4966
        SSessionKey key = {0};
×
UNCOV
4967
        getSessionHashKey(&curInfo.winInfo.sessionWin, &key);
×
UNCOV
4968
        code = tSimpleHashPut(pAggSup->pResultRows, &key, sizeof(SSessionKey), &curInfo.winInfo,
×
4969
                              sizeof(SResultWindowInfo));
UNCOV
4970
        QUERY_CHECK_CODE(code, lino, _end);
×
4971
      }
4972
    } else if (IS_VALID_SESSION_WIN(nextInfo.winInfo)) {
131!
4973
      releaseOutputBuf(pAggSup->pState, nextInfo.winInfo.pStatePos, &pAggSup->pSessionAPI->stateStore);
×
4974
    }
4975

4976
    if (IS_VALID_SESSION_WIN(curInfo.winInfo)) {
131!
4977
      code = saveSessionOutputBuf(pAggSup, &curInfo.winInfo);
131✔
4978
      QUERY_CHECK_CODE(code, lino, _end);
131!
4979
    }
4980
  }
4981
  taosMemoryFreeClear(pBuf);
87!
4982

4983
  SOperatorInfo* downstream = pOperator->pDownstream[0];
87✔
4984
  if (downstream->fpSet.reloadStreamStateFn) {
87!
4985
    downstream->fpSet.reloadStreamStateFn(downstream);
87✔
4986
  }
4987
  reloadAggSupFromDownStream(downstream, &pInfo->streamAggSup);
87✔
4988

4989
_end:
87✔
4990
  taosMemoryFreeClear(pBuf);
87!
4991
  if (code != TSDB_CODE_SUCCESS) {
87!
UNCOV
4992
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
4993
  }
4994
}
87✔
4995

4996
int32_t createStreamStateAggOperatorInfo(SOperatorInfo* downstream, SPhysiNode* pPhyNode, SExecTaskInfo* pTaskInfo,
327✔
4997
                                         SReadHandle* pHandle, SOperatorInfo** pOptrInfo) {
4998
  QRY_PARAM_CHECK(pOptrInfo);
327!
4999
  int32_t code = 0;
327✔
5000
  int32_t lino = 0;
327✔
5001

5002
  SStreamStateWinodwPhysiNode* pStateNode = (SStreamStateWinodwPhysiNode*)pPhyNode;
327✔
5003
  int32_t                      tsSlotId = ((SColumnNode*)pStateNode->window.pTspk)->slotId;
327✔
5004
  SColumnNode*                 pColNode = (SColumnNode*)(pStateNode->pStateKey);
327✔
5005
  SStreamStateAggOperatorInfo* pInfo = taosMemoryCalloc(1, sizeof(SStreamStateAggOperatorInfo));
327✔
5006
  SOperatorInfo*               pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo));
328✔
5007
  if (pInfo == NULL || pOperator == NULL) {
328!
UNCOV
5008
    code = terrno;
×
UNCOV
5009
    QUERY_CHECK_CODE(code, lino, _error);
×
5010
  }
5011

5012
  pInfo->stateCol = extractColumnFromColumnNode(pColNode);
328✔
5013
  initResultSizeInfo(&pOperator->resultInfo, 4096);
328✔
5014
  if (pStateNode->window.pExprs != NULL) {
328✔
5015
    int32_t    numOfScalar = 0;
25✔
5016
    SExprInfo* pScalarExprInfo = NULL;
25✔
5017
    code = createExprInfo(pStateNode->window.pExprs, NULL, &pScalarExprInfo, &numOfScalar);
25✔
5018
    QUERY_CHECK_CODE(code, lino, _error);
25!
5019

5020
    code = initExprSupp(&pInfo->scalarSupp, pScalarExprInfo, numOfScalar, &pTaskInfo->storageAPI.functionStore);
25✔
5021
    QUERY_CHECK_CODE(code, lino, _error);
25!
5022
  }
5023

5024
  pInfo->twAggSup = (STimeWindowAggSupp){
328✔
5025
      .waterMark = pStateNode->window.watermark,
328✔
5026
      .calTrigger = pStateNode->window.triggerType,
328✔
5027
      .maxTs = INT64_MIN,
5028
      .minTs = INT64_MAX,
5029
      .deleteMark = getDeleteMark(&pStateNode->window, 0),
328✔
5030
  };
5031

5032
  code = initExecTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &pTaskInfo->window);
328✔
5033
  QUERY_CHECK_CODE(code, lino, _error);
328!
5034

5035
  SSDataBlock* pResBlock = createDataBlockFromDescNode(pPhyNode->pOutputDataBlockDesc);
328✔
5036
  QUERY_CHECK_NULL(pResBlock, code, lino, _error, terrno);
328!
5037
  pInfo->binfo.pRes = pResBlock;
328✔
5038

5039
  SExprSupp* pExpSup = &pOperator->exprSupp;
328✔
5040
  int32_t    numOfCols = 0;
328✔
5041
  SExprInfo* pExprInfo = NULL;
328✔
5042
  code = createExprInfo(pStateNode->window.pFuncs, NULL, &pExprInfo, &numOfCols);
328✔
5043
  QUERY_CHECK_CODE(code, lino, _error);
328!
5044

5045
  code = initBasicInfoEx(&pInfo->binfo, pExpSup, pExprInfo, numOfCols, pResBlock, &pTaskInfo->storageAPI.functionStore);
328✔
5046
  if (code != TSDB_CODE_SUCCESS) {
328!
UNCOV
5047
    goto _error;
×
5048
  }
5049
  int32_t keySize = sizeof(SStateKeys) + pColNode->node.resType.bytes;
328✔
5050
  int16_t type = pColNode->node.resType.type;
328✔
5051
  pInfo->primaryTsIndex = tsSlotId;
328✔
5052
  code =
5053
      initStreamAggSupporter(&pInfo->streamAggSup, pExpSup, numOfCols, 0, pTaskInfo->streamInfo.pState, keySize, type,
328✔
5054
                             &pTaskInfo->storageAPI.stateStore, pHandle, &pInfo->twAggSup, GET_TASKID(pTaskInfo),
328✔
5055
                             &pTaskInfo->storageAPI, pInfo->primaryTsIndex, STREAM_STATE_BUFF_SORT, 1);
5056
  QUERY_CHECK_CODE(code, lino, _error);
328!
5057

5058
  _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
328✔
5059
  pInfo->pSeDeleted = tSimpleHashInit(64, hashFn);
328✔
5060
  QUERY_CHECK_NULL(pInfo->pSeDeleted, code, lino, _error, terrno);
328!
5061
  pInfo->pDelIterator = NULL;
328✔
5062

5063
  code = createSpecialDataBlock(STREAM_DELETE_RESULT, &pInfo->pDelRes);
328✔
5064
  QUERY_CHECK_CODE(code, lino, _error);
328!
5065

5066
  pInfo->pChildren = NULL;
328✔
5067
  pInfo->ignoreExpiredData = pStateNode->window.igExpired;
328✔
5068
  pInfo->ignoreExpiredDataSaved = false;
328✔
5069
  pInfo->pUpdated = NULL;
328✔
5070
  pInfo->pSeUpdated = NULL;
328✔
5071
  pInfo->dataVersion = 0;
328✔
5072
  pInfo->historyWins = taosArrayInit(4, sizeof(SSessionKey));
328✔
5073
  if (!pInfo->historyWins) {
328!
UNCOV
5074
    code = terrno;
×
UNCOV
5075
    QUERY_CHECK_CODE(code, lino, _error);
×
5076
  }
5077

5078
  if (pHandle) {
328!
5079
    pInfo->isHistoryOp = pHandle->fillHistory;
328✔
5080
  }
5081

5082
  code = createSpecialDataBlock(STREAM_CHECKPOINT, &pInfo->pCheckpointRes);
328✔
5083
  QUERY_CHECK_CODE(code, lino, _error);
328!
5084

5085
  pInfo->recvGetAll = false;
328✔
5086
  pInfo->pPkDeleted = tSimpleHashInit(64, hashFn);
328✔
5087
  QUERY_CHECK_NULL(pInfo->pPkDeleted, code, lino, _error, terrno);
328!
5088
  pInfo->destHasPrimaryKey = pStateNode->window.destHasPrimaryKey;
328✔
5089
  pInfo->pOperator = pOperator;
328✔
5090

5091
  setOperatorInfo(pOperator, "StreamStateAggOperator", QUERY_NODE_PHYSICAL_PLAN_STREAM_STATE, true, OP_NOT_OPENED,
328✔
5092
                  pInfo, pTaskInfo);
5093
  // for stream
5094
  void*   buff = NULL;
328✔
5095
  int32_t len = 0;
328✔
5096
  int32_t res =
5097
      pInfo->streamAggSup.stateStore.streamStateGetInfo(pInfo->streamAggSup.pState, STREAM_STATE_OP_CHECKPOINT_NAME,
328✔
5098
                                                        strlen(STREAM_STATE_OP_CHECKPOINT_NAME), &buff, &len);
5099
  if (res == TSDB_CODE_SUCCESS) {
328!
5100
    code = doStreamStateDecodeOpState(buff, len, pOperator, true, NULL);
×
5101
    taosMemoryFree(buff);
×
5102
    QUERY_CHECK_CODE(code, lino, _error);
×
5103
  }
5104

5105
  pOperator->fpSet = createOperatorFpSet(optrDummyOpenFn, doStreamStateAggNext, NULL, destroyStreamStateOperatorInfo,
328✔
5106
                                         optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
5107
  setOperatorStreamStateFn(pOperator, streamStateReleaseState, streamStateReloadState);
328✔
5108
  code = initDownStream(downstream, &pInfo->streamAggSup, pOperator->operatorType, pInfo->primaryTsIndex,
328✔
5109
                        &pInfo->twAggSup, &pInfo->basic);
328✔
5110
  QUERY_CHECK_CODE(code, lino, _error);
328!
5111

5112
  code = appendDownstream(pOperator, &downstream, 1);
328✔
5113
  QUERY_CHECK_CODE(code, lino, _error);
328!
5114

5115
  *pOptrInfo = pOperator;
328✔
5116
  return TSDB_CODE_SUCCESS;
328✔
5117

UNCOV
5118
_error:
×
UNCOV
5119
  if (pInfo != NULL) destroyStreamStateOperatorInfo(pInfo);
×
UNCOV
5120
  destroyOperatorAndDownstreams(pOperator, &downstream, 1);
×
UNCOV
5121
  pTaskInfo->code = code;
×
UNCOV
5122
  qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
UNCOV
5123
  return code;
×
5124
}
5125

5126
#ifdef BUILD_NO_CALL
5127
static void setInverFunction(SqlFunctionCtx* pCtx, int32_t num, EStreamType type) {
5128
  for (int i = 0; i < num; i++) {
5129
    if (type == STREAM_INVERT) {
5130
      fmSetInvertFunc(pCtx[i].functionId, &(pCtx[i].fpSet));
5131
    } else if (type == STREAM_NORMAL) {
5132
      fmSetNormalFunc(pCtx[i].functionId, &(pCtx[i].fpSet));
5133
    }
5134
  }
5135
}
5136
#endif
5137

5138
static int32_t doStreamIntervalAggNext(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
157,259✔
5139
  int32_t                      code = TSDB_CODE_SUCCESS;
157,259✔
5140
  int32_t                      lino = 0;
157,259✔
5141
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
157,259✔
5142
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
157,259✔
5143
  SStorageAPI*                 pAPI = &pOperator->pTaskInfo->storageAPI;
157,259✔
5144
  SExprSupp*                   pSup = &pOperator->exprSupp;
157,259✔
5145

5146
  qDebug("stask:%s  %s status: %d", GET_TASKID(pTaskInfo), getStreamOpName(pOperator->operatorType), pOperator->status);
157,259✔
5147

5148
  if (pOperator->status == OP_EXEC_DONE) {
157,261✔
5149
    (*ppRes) = NULL;
669✔
5150
    return code;
669✔
5151
  }
5152

5153
  if (pOperator->status == OP_RES_TO_RETURN) {
156,592✔
5154
    SSDataBlock* resBlock = NULL;
123,737✔
5155
    code = buildIntervalResult(pOperator, &resBlock);
123,737✔
5156
    QUERY_CHECK_CODE(code, lino, _end);
123,737!
5157
    if (resBlock != NULL) {
123,737✔
5158
      (*ppRes) = resBlock;
106,601✔
5159
      return code;
123,737✔
5160
    }
5161

5162
    if (pInfo->recvGetAll) {
17,136✔
5163
      pInfo->recvGetAll = false;
183✔
5164
      resetUnCloseWinInfo(pInfo->aggSup.pResultRowHashTable);
183✔
5165
    }
5166

5167
    if (pInfo->reCkBlock) {
17,135✔
5168
      pInfo->reCkBlock = false;
116✔
5169
      printDataBlock(pInfo->pCheckpointRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
116✔
5170
      (*ppRes) = pInfo->pCheckpointRes;
116✔
5171
      return code;
116✔
5172
    }
5173

5174
    setStreamOperatorCompleted(pOperator);
17,019✔
5175
    (*ppRes) = NULL;
17,020✔
5176
    return code;
17,020✔
5177
  }
5178

5179
  SOperatorInfo* downstream = pOperator->pDownstream[0];
32,855✔
5180

5181
  if (!pInfo->pUpdated) {
32,855✔
5182
    pInfo->pUpdated = taosArrayInit(4096, POINTER_BYTES);
30,000✔
5183
    QUERY_CHECK_NULL(pInfo->pUpdated, code, lino, _end, terrno);
29,992!
5184
  }
5185

5186
  if (!pInfo->pUpdatedMap) {
32,847✔
5187
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
29,993✔
5188
    pInfo->pUpdatedMap = tSimpleHashInit(4096, hashFn);
29,998✔
5189
    QUERY_CHECK_NULL(pInfo->pUpdatedMap, code, lino, _end, terrno);
29,997!
5190
  }
5191

5192
  while (1) {
524,377✔
5193
    SSDataBlock* pBlock = NULL;
557,228✔
5194
    code = downstream->fpSet.getNextFn(downstream, &pBlock);
557,228✔
5195
    QUERY_CHECK_CODE(code, lino, _end);
557,226!
5196

5197
    if (pBlock == NULL) {
557,226✔
5198
      qDebug("===stream===return data:%s. recv datablock num:%" PRIu64, getStreamOpName(pOperator->operatorType),
30,002✔
5199
             pInfo->numOfDatapack);
5200
      pInfo->numOfDatapack = 0;
30,001✔
5201
      break;
30,001✔
5202
    }
5203

5204
    pInfo->numOfDatapack++;
527,224✔
5205
    printSpecDataBlock(pBlock, getStreamOpName(pOperator->operatorType), "recv", GET_TASKID(pTaskInfo));
527,224✔
5206
    setStreamOperatorState(&pInfo->basic, pBlock->info.type);
527,224✔
5207

5208
    if (pBlock->info.type == STREAM_DELETE_DATA || pBlock->info.type == STREAM_DELETE_RESULT ||
527,223✔
5209
        pBlock->info.type == STREAM_CLEAR) {
526,701✔
5210
      code = doDeleteWindows(pOperator, &pInfo->interval, pBlock, pInfo->pDelWins, pInfo->pUpdatedMap, NULL);
1,476✔
5211
      QUERY_CHECK_CODE(code, lino, _end);
1,477!
5212
      continue;
3,818✔
5213
    } else if (pBlock->info.type == STREAM_GET_ALL) {
525,747✔
5214
      pInfo->recvGetAll = true;
997✔
5215
      code = getAllIntervalWindow(pInfo->aggSup.pResultRowHashTable, pInfo->pUpdatedMap);
997✔
5216
      QUERY_CHECK_CODE(code, lino, _end);
998!
5217
      continue;
998✔
5218
    } else if (pBlock->info.type == STREAM_CREATE_CHILD_TABLE || pBlock->info.type == STREAM_DROP_CHILD_TABLE) {
524,750✔
5219
      printDataBlock(pBlock, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
2,855✔
5220
      (*ppRes) = pBlock;
2,855✔
5221
      return code;
2,855✔
5222
    } else if (pBlock->info.type == STREAM_CHECKPOINT) {
521,895✔
5223
      pAPI->stateStore.streamStateCommit(pInfo->pState);
1,343✔
5224
      doStreamIntervalSaveCheckpoint(pOperator);
1,343✔
5225
      pInfo->reCkBlock = true;
1,343✔
5226
      code = copyDataBlock(pInfo->pCheckpointRes, pBlock);
1,343✔
5227
      QUERY_CHECK_CODE(code, lino, _end);
1,343!
5228

5229
      continue;
1,343✔
5230
    } else {
5231
      if (pBlock->info.type != STREAM_NORMAL && pBlock->info.type != STREAM_INVALID) {
520,552!
UNCOV
5232
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
UNCOV
5233
        QUERY_CHECK_CODE(code, lino, _end);
×
5234
      }
5235
    }
5236

5237
    if (pBlock->info.type == STREAM_NORMAL && pBlock->info.version != 0) {
520,552✔
5238
      // set input version
5239
      pTaskInfo->version = pBlock->info.version;
350,902✔
5240
    }
5241

5242
    if (pInfo->scalarSupp.pExprInfo != NULL) {
520,552✔
5243
      SExprSupp* pExprSup = &pInfo->scalarSupp;
13✔
5244
      code = projectApplyFunctions(pExprSup->pExprInfo, pBlock, pBlock, pExprSup->pCtx, pExprSup->numOfExprs, NULL);
13✔
5245
      QUERY_CHECK_CODE(code, lino, _end);
13!
5246
    }
5247

5248
    // The timewindow that overlaps the timestamps of the input pBlock need to be recalculated and return to the
5249
    // caller. Note that all the time window are not close till now.
5250
    // the pDataBlock are always the same one, no need to call this again
5251
    code = setInputDataBlock(pSup, pBlock, TSDB_ORDER_ASC, MAIN_SCAN, true);
520,552✔
5252
    QUERY_CHECK_CODE(code, lino, _end);
520,555!
5253
#ifdef BUILD_NO_CALL
5254
    if (pInfo->invertible) {
5255
      setInverFunction(pSup->pCtx, pOperator->exprSupp.numOfExprs, pBlock->info.type);
5256
    }
5257
#endif
5258

5259
    code = doStreamIntervalAggImpl(pOperator, pBlock, pBlock->info.id.groupId, pInfo->pUpdatedMap, pInfo->pDeletedMap);
520,555✔
5260
    if (code == TSDB_CODE_STREAM_INTERNAL_ERROR) {
520,559!
UNCOV
5261
      pOperator->status = OP_RES_TO_RETURN;
×
UNCOV
5262
      code = TSDB_CODE_SUCCESS;
×
UNCOV
5263
      break;
×
5264
    }
5265
    QUERY_CHECK_CODE(code, lino, _end);
520,559!
5266
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.window.ekey);
520,559✔
5267
    pInfo->twAggSup.minTs = TMIN(pInfo->twAggSup.minTs, pBlock->info.window.skey);
520,559✔
5268
  }
5269
  pOperator->status = OP_RES_TO_RETURN;
30,001✔
5270
  if (!pInfo->destHasPrimaryKey) {
30,001!
5271
    removeDeleteResults(pInfo->pUpdatedMap, pInfo->pDelWins);
30,002✔
5272
  }
5273
  code = closeStreamIntervalWindow(pInfo->aggSup.pResultRowHashTable, &pInfo->twAggSup, &pInfo->interval, NULL,
29,998✔
5274
                                   pInfo->pUpdatedMap, pInfo->pDelWins, pOperator);
5275
  QUERY_CHECK_CODE(code, lino, _end);
29,998!
5276

5277
  if (pInfo->destHasPrimaryKey && IS_NORMAL_INTERVAL_OP(pOperator)) {
29,998!
UNCOV
5278
    code = copyIntervalDeleteKey(pInfo->pDeletedMap, pInfo->pDelWins);
×
UNCOV
5279
    QUERY_CHECK_CODE(code, lino, _end);
×
5280
  }
5281

5282
  void*   pIte = NULL;
29,998✔
5283
  int32_t iter = 0;
29,998✔
5284
  while ((pIte = tSimpleHashIterate(pInfo->pUpdatedMap, pIte, &iter)) != NULL) {
11,686,278✔
5285
    void* tmp = taosArrayPush(pInfo->pUpdated, pIte);
11,656,547✔
5286
    if (!tmp) {
11,656,280!
5287
      code = terrno;
×
5288
      QUERY_CHECK_CODE(code, lino, _end);
×
5289
    }
5290
  }
5291
  taosArraySort(pInfo->pUpdated, winPosCmprImpl);
29,983✔
5292

5293
  initMultiResInfoFromArrayList(&pInfo->groupResInfo, pInfo->pUpdated);
30,004✔
5294
  pInfo->pUpdated = NULL;
30,002✔
5295
  code = blockDataEnsureCapacity(pInfo->binfo.pRes, pOperator->resultInfo.capacity);
30,002✔
5296
  QUERY_CHECK_CODE(code, lino, _end);
30,003!
5297

5298
  tSimpleHashCleanup(pInfo->pUpdatedMap);
30,003✔
5299
  pInfo->pUpdatedMap = NULL;
30,003✔
5300

5301
  code = buildIntervalResult(pOperator, ppRes);
30,003✔
5302
  QUERY_CHECK_CODE(code, lino, _end);
29,998!
5303

5304
  return code;
29,998✔
5305

UNCOV
5306
_end:
×
UNCOV
5307
  if (code != TSDB_CODE_SUCCESS) {
×
5308
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
5309
    pTaskInfo->code = code;
×
UNCOV
5310
    T_LONG_JMP(pTaskInfo->env, code);
×
5311
  }
UNCOV
5312
  setStreamOperatorCompleted(pOperator);
×
UNCOV
5313
  (*ppRes) = NULL;
×
UNCOV
5314
  return code;
×
5315
}
5316

5317
static int32_t createStreamSingleIntervalOperatorInfo(SOperatorInfo* downstream, SPhysiNode* pPhyNode, SExecTaskInfo* pTaskInfo,
3,119✔
5318
                                                      SReadHandle* pHandle, SOperatorInfo** pOptrInfo) {
5319
  QRY_PARAM_CHECK(pOptrInfo);
3,119!
5320

5321
  int32_t code = TSDB_CODE_SUCCESS;
3,119✔
5322
  int32_t lino = 0;
3,119✔
5323
  int32_t numOfCols = 0;
3,119✔
5324

5325
  SStreamIntervalOperatorInfo* pInfo = taosMemoryCalloc(1, sizeof(SStreamIntervalOperatorInfo));
3,119✔
5326
  SOperatorInfo*               pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo));
3,119✔
5327
  if (pInfo == NULL || pOperator == NULL) {
3,119!
UNCOV
5328
    code = terrno;
×
UNCOV
5329
    QUERY_CHECK_CODE(code, lino, _error);
×
5330
  }
5331

5332
  SStreamIntervalPhysiNode* pIntervalPhyNode = (SStreamIntervalPhysiNode*)pPhyNode;
3,119✔
5333

5334
  SSDataBlock* pResBlock = createDataBlockFromDescNode(pPhyNode->pOutputDataBlockDesc);
3,119✔
5335
  QUERY_CHECK_NULL(pResBlock, code, lino, _error, terrno);
3,119!
5336
  initBasicInfo(&pInfo->binfo, pResBlock);
3,119✔
5337

5338
  pInfo->interval = (SInterval){
3,119✔
5339
      .interval = pIntervalPhyNode->interval,
3,119✔
5340
      .sliding = pIntervalPhyNode->sliding,
3,119✔
5341
      .intervalUnit = pIntervalPhyNode->intervalUnit,
3,119✔
5342
      .slidingUnit = pIntervalPhyNode->slidingUnit,
3,119✔
5343
      .offset = pIntervalPhyNode->offset,
3,119✔
5344
      .precision = ((SColumnNode*)pIntervalPhyNode->window.pTspk)->node.resType.precision,
3,119✔
5345
  };
5346

5347
  pInfo->twAggSup =
3,119✔
5348
      (STimeWindowAggSupp){.waterMark = pIntervalPhyNode->window.watermark,
3,119✔
5349
                           .calTrigger = pIntervalPhyNode->window.triggerType,
3,119✔
5350
                           .maxTs = INT64_MIN,
5351
                           .minTs = INT64_MAX,
5352
                           .deleteMark = getDeleteMark(&pIntervalPhyNode->window, pIntervalPhyNode->interval)};
3,119✔
5353

5354
  pOperator->pTaskInfo = pTaskInfo;
3,119✔
5355
  SStorageAPI* pAPI = &pOperator->pTaskInfo->storageAPI;
3,119✔
5356

5357
  pInfo->ignoreExpiredData = pIntervalPhyNode->window.igExpired;
3,119✔
5358
  pInfo->ignoreExpiredDataSaved = false;
3,119✔
5359

5360
  SExprSupp* pSup = &pOperator->exprSupp;
3,119✔
5361
  pSup->hasWindowOrGroup = true;
3,119✔
5362

5363
  code = initExecTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &pTaskInfo->window);
3,119✔
5364
  QUERY_CHECK_CODE(code, lino, _error);
3,119!
5365

5366
  pInfo->primaryTsIndex = ((SColumnNode*)pIntervalPhyNode->window.pTspk)->slotId;
3,119✔
5367
  initResultSizeInfo(&pOperator->resultInfo, 4096);
3,119✔
5368

5369
  pInfo->pState = taosMemoryCalloc(1, sizeof(SStreamState));
3,119✔
5370
  QUERY_CHECK_NULL(pInfo->pState, code, lino, _error, terrno);
3,119!
5371
  *(pInfo->pState) = *(pTaskInfo->streamInfo.pState);
3,119✔
5372
  pAPI->stateStore.streamStateSetNumber(pInfo->pState, -1, pInfo->primaryTsIndex);
3,119✔
5373

5374
  size_t     keyBufSize = sizeof(int64_t) + sizeof(int64_t) + POINTER_BYTES;
3,119✔
5375
  SExprInfo* pExprInfo = NULL;
3,119✔
5376
  code = createExprInfo(pIntervalPhyNode->window.pFuncs, NULL, &pExprInfo, &numOfCols);
3,119✔
5377
  QUERY_CHECK_CODE(code, lino, _error);
3,119!
5378
  code = initAggSup(pSup, &pInfo->aggSup, pExprInfo, numOfCols, keyBufSize, pTaskInfo->id.str, pInfo->pState,
3,119✔
5379
                    &pTaskInfo->storageAPI.functionStore);
5380
  QUERY_CHECK_CODE(code, lino, _error);
3,119!
5381

5382
  if (pIntervalPhyNode->window.pExprs != NULL) {
3,119✔
5383
    int32_t    numOfScalar = 0;
1✔
5384
    SExprInfo* pScalarExprInfo = NULL;
1✔
5385

5386
    code = createExprInfo(pIntervalPhyNode->window.pExprs, NULL, &pScalarExprInfo, &numOfScalar);
1✔
5387
    QUERY_CHECK_CODE(code, lino, _error);
1!
5388

5389
    code = initExprSupp(&pInfo->scalarSupp, pScalarExprInfo, numOfScalar, &pTaskInfo->storageAPI.functionStore);
1✔
5390
    QUERY_CHECK_CODE(code, lino, _error);
1!
5391
  }
5392

5393
  pInfo->invertible = false;
3,119✔
5394
  pInfo->pDelWins = taosArrayInit(4, sizeof(SWinKey));
3,119✔
5395
  QUERY_CHECK_NULL(pInfo->pDelWins, code, lino, _error, terrno);
3,119!
5396
  pInfo->delIndex = 0;
3,119✔
5397

5398
  code = createSpecialDataBlock(STREAM_DELETE_RESULT, &pInfo->pDelRes);
3,119✔
5399
  QUERY_CHECK_CODE(code, lino, _error);
3,119!
5400

5401
  initResultRowInfo(&pInfo->binfo.resultRowInfo);
3,119✔
5402

5403
  pInfo->pPhyNode = NULL;  // create new child
3,119✔
5404
  pInfo->pPullDataMap = NULL;
3,119✔
5405
  pInfo->pFinalPullDataMap = NULL;
3,119✔
5406
  pInfo->pPullWins = NULL;  // SPullWindowInfo
3,119✔
5407
  pInfo->pullIndex = 0;
3,119✔
5408
  pInfo->pPullDataRes = NULL;
3,119✔
5409
  pInfo->numOfChild = 0;
3,119✔
5410
  pInfo->delKey.ts = INT64_MAX;
3,119✔
5411
  pInfo->delKey.groupId = 0;
3,119✔
5412
  pInfo->numOfDatapack = 0;
3,119✔
5413
  pInfo->pUpdated = NULL;
3,119✔
5414
  pInfo->pUpdatedMap = NULL;
3,119✔
5415
  int32_t funResSize = getMaxFunResSize(pSup, numOfCols);
3,119✔
5416

5417
  pInfo->stateStore = pTaskInfo->storageAPI.stateStore;
3,118✔
5418
  pInfo->pState->pFileState = NULL;
3,118✔
5419

5420
  // used for backward compatibility of function's result info
5421
  pInfo->pState->pResultRowStore.resultRowGet = getResultRowFromBuf;
3,118✔
5422
  pInfo->pState->pResultRowStore.resultRowPut = putResultRowToBuf;
3,118✔
5423
  pInfo->pState->pExprSupp = &pOperator->exprSupp;
3,118✔
5424

5425
  code = pTaskInfo->storageAPI.stateStore.streamFileStateInit(
3,118✔
5426
      tsStreamBufferSize, sizeof(SWinKey), pInfo->aggSup.resultRowSize, funResSize, compareTs, pInfo->pState,
3,118✔
5427
      pInfo->twAggSup.deleteMark, GET_TASKID(pTaskInfo), pHandle->checkpointId, STREAM_STATE_BUFF_HASH,
3,118✔
5428
      &pInfo->pState->pFileState);
3,118✔
5429
  QUERY_CHECK_CODE(code, lino, _error);
3,119!
5430

5431
  pInfo->pOperator = pOperator;
3,119✔
5432
  setOperatorInfo(pOperator, "StreamIntervalOperator", QUERY_NODE_PHYSICAL_PLAN_STREAM_INTERVAL, true, OP_NOT_OPENED,
3,119✔
5433
                  pInfo, pTaskInfo);
5434
  pOperator->fpSet =
5435
      createOperatorFpSet(optrDummyOpenFn, doStreamIntervalAggNext, NULL, destroyStreamFinalIntervalOperatorInfo,
3,119✔
5436
                          optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
5437
  setOperatorStreamStateFn(pOperator, streamIntervalReleaseState, streamIntervalReloadState);
3,119✔
5438

5439
  pInfo->recvGetAll = false;
3,119✔
5440

5441
  code = createSpecialDataBlock(STREAM_CHECKPOINT, &pInfo->pCheckpointRes);
3,119✔
5442
  QUERY_CHECK_CODE(code, lino, _error);
3,119!
5443

5444
  _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
3,119✔
5445
  pInfo->pDeletedMap = tSimpleHashInit(4096, hashFn);
3,119✔
5446
  QUERY_CHECK_NULL(pInfo->pDeletedMap, code, lino, _error, terrno);
3,119!
5447
  pInfo->destHasPrimaryKey = pIntervalPhyNode->window.destHasPrimaryKey;
3,119✔
5448

5449
  // for stream
5450
  void*   buff = NULL;
3,119✔
5451
  int32_t len = 0;
3,119✔
5452
  int32_t res = pAPI->stateStore.streamStateGetInfo(pInfo->pState, STREAM_INTERVAL_OP_CHECKPOINT_NAME,
3,119✔
5453
                                                    strlen(STREAM_INTERVAL_OP_CHECKPOINT_NAME), &buff, &len);
5454
  if (res == TSDB_CODE_SUCCESS) {
3,119✔
5455
    doStreamIntervalDecodeOpState(buff, len, pOperator);
8✔
5456
    taosMemoryFree(buff);
8✔
5457
  }
5458

5459
  pInfo->basic.primaryPkIndex = -1;
3,119✔
5460
  code = initIntervalDownStream(downstream, pPhyNode->type, pInfo, &pInfo->basic);
3,119✔
5461
  QUERY_CHECK_CODE(code, lino, _error);
3,119!
5462

5463
  code = appendDownstream(pOperator, &downstream, 1);
3,119✔
5464
  QUERY_CHECK_CODE(code, lino, _error);
3,119!
5465

5466
  *pOptrInfo = pOperator;
3,119✔
5467
  return TSDB_CODE_SUCCESS;
3,119✔
5468

5469
_error:
×
5470
  if (pInfo != NULL) destroyStreamFinalIntervalOperatorInfo(pInfo);
×
5471
  destroyOperatorAndDownstreams(pOperator, &downstream, 1);
×
5472
  pTaskInfo->code = code;
×
UNCOV
5473
  return code;
×
5474
}
5475

5476
int32_t createStreamIntervalOperatorInfo(SOperatorInfo* downstream, SPhysiNode* pPhyNode, SExecTaskInfo* pTaskInfo,
3,142✔
5477
                                         SReadHandle* pHandle, SOperatorInfo** pOptrInfo) {
5478
  SStreamIntervalPhysiNode* pIntervalPhyNode = (SStreamIntervalPhysiNode*)pPhyNode;
3,142✔
5479
  if (pIntervalPhyNode->window.triggerType == STREAM_TRIGGER_FORCE_WINDOW_CLOSE) {
3,142✔
5480
    return createStreamIntervalSliceOperatorInfo(downstream, pPhyNode, pTaskInfo, pHandle, pOptrInfo);
24✔
5481
  } else {
5482
    return createStreamSingleIntervalOperatorInfo(downstream, pPhyNode, pTaskInfo, pHandle, pOptrInfo);
3,118✔
5483
  }
5484
  return TSDB_CODE_SUCCESS;
5485
}
5486

5487
static void doStreamMidIntervalAggImpl(SOperatorInfo* pOperator, SSDataBlock* pSDataBlock, SSHashObj* pUpdatedMap) {
38✔
5488
  int32_t                      code = TSDB_CODE_SUCCESS;
38✔
5489
  int32_t                      lino = 0;
38✔
5490
  SStreamIntervalOperatorInfo* pInfo = (SStreamIntervalOperatorInfo*)pOperator->info;
38✔
5491
  pInfo->dataVersion = TMAX(pInfo->dataVersion, pSDataBlock->info.version);
38✔
5492

5493
  SResultRowInfo*  pResultRowInfo = &(pInfo->binfo.resultRowInfo);
38✔
5494
  SExecTaskInfo*   pTaskInfo = pOperator->pTaskInfo;
38✔
5495
  SExprSupp*       pSup = &pOperator->exprSupp;
38✔
5496
  int32_t          numOfOutput = pSup->numOfExprs;
38✔
5497
  int32_t          step = 1;
38✔
5498
  SRowBuffPos*     pResPos = NULL;
38✔
5499
  SResultRow*      pResult = NULL;
38✔
5500
  int32_t          forwardRows = 1;
38✔
5501
  uint64_t         groupId = pSDataBlock->info.id.groupId;
38✔
5502
  SColumnInfoData* pColDataInfo = taosArrayGet(pSDataBlock->pDataBlock, pInfo->primaryTsIndex);
38✔
5503
  TSKEY*           tsCol = (int64_t*)pColDataInfo->pData;
38✔
5504

5505
  int32_t     startPos = 0;
38✔
5506
  TSKEY       ts = getStartTsKey(&pSDataBlock->info.window, tsCol);
38✔
5507
  STimeWindow nextWin = getFinalTimeWindow(ts, &pInfo->interval);
38✔
5508

5509
  while (1) {
1,256✔
5510
    SWinKey key = {
1,294✔
5511
        .ts = nextWin.skey,
1,294✔
5512
        .groupId = groupId,
5513
    };
5514
    void*   chIds = taosHashGet(pInfo->pPullDataMap, &key, sizeof(SWinKey));
1,294✔
5515
    int32_t index = -1;
1,294✔
5516
    SArray* chArray = NULL;
1,294✔
5517
    int32_t chId = 0;
1,294✔
5518
    if (chIds) {
1,294✔
5519
      chArray = *(void**)chIds;
4✔
5520
      chId = getChildIndex(pSDataBlock);
4✔
5521
      index = taosArraySearchIdx(chArray, &chId, compareInt32Val, TD_EQ);
4✔
5522
    }
5523
    if (!(index == -1 || pSDataBlock->info.type == STREAM_PULL_DATA)) {
1,294!
UNCOV
5524
      startPos = getNextQualifiedFinalWindow(&pInfo->interval, &nextWin, &pSDataBlock->info, tsCol, startPos);
×
5525
      if (startPos < 0) {
×
5526
        break;
38✔
5527
      }
5528
      continue;
×
5529
    }
5530

5531
    if (!inSlidingWindow(&pInfo->interval, &nextWin, &pSDataBlock->info)) {
1,294!
5532
      startPos = getNexWindowPos(&pInfo->interval, &pSDataBlock->info, tsCol, startPos, nextWin.ekey, &nextWin);
×
UNCOV
5533
      if (startPos < 0) {
×
5534
        break;
×
5535
      }
5536
      continue;
×
5537
    }
5538

5539
    int32_t winCode = TSDB_CODE_SUCCESS;
1,294✔
5540
    code = setIntervalOutputBuf(pInfo->pState, &nextWin, &pResPos, groupId, pSup->pCtx, numOfOutput,
1,294✔
5541
                                pSup->rowEntryInfoOffset, &pInfo->aggSup, &pInfo->stateStore, &winCode);
5542
    QUERY_CHECK_CODE(code, lino, _end);
1,294!
5543

5544
    pResult = (SResultRow*)pResPos->pRowBuff;
1,294✔
5545

5546
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_AT_ONCE) {
1,294!
5547
      code = saveWinResult(&key, pResPos, pUpdatedMap);
1,294✔
5548
      QUERY_CHECK_CODE(code, lino, _end);
1,294!
5549
    }
5550

5551
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_WINDOW_CLOSE) {
1,294!
UNCOV
5552
      code = tSimpleHashPut(pInfo->aggSup.pResultRowHashTable, &key, sizeof(SWinKey), &pResPos, POINTER_BYTES);
×
UNCOV
5553
      QUERY_CHECK_CODE(code, lino, _end);
×
5554
    }
5555

5556
    updateTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &nextWin, 1);
1,294✔
5557
    code = applyAggFunctionOnPartialTuples(pTaskInfo, pSup->pCtx, &pInfo->twAggSup.timeWindowData, startPos,
1,294✔
5558
                                           forwardRows, pSDataBlock->info.rows, numOfOutput);
1,294✔
5559
    QUERY_CHECK_CODE(code, lino, _end);
1,294!
5560
    key.ts = nextWin.skey;
1,294✔
5561

5562
    if (pInfo->delKey.ts > key.ts) {
1,294✔
5563
      pInfo->delKey = key;
10✔
5564
    }
5565
    int32_t prevEndPos = (forwardRows - 1) * step + startPos;
1,294✔
5566
    if (pSDataBlock->info.window.skey <= 0 || pSDataBlock->info.window.ekey <= 0) {
1,294!
5567
      qError("table uid %" PRIu64 " data block timestamp range may not be calculated! minKey %" PRId64
×
5568
             ",maxKey %" PRId64,
5569
             pSDataBlock->info.id.uid, pSDataBlock->info.window.skey, pSDataBlock->info.window.ekey);
5570
      code = blockDataUpdateTsWindow(pSDataBlock, 0);
×
UNCOV
5571
      QUERY_CHECK_CODE(code, lino, _end);
×
5572

5573
      // timestamp of the data is incorrect
5574
      if (pSDataBlock->info.window.skey <= 0 || pSDataBlock->info.window.ekey <= 0) {
×
5575
        qError("table uid %" PRIu64 " data block timestamp is out of range! minKey %" PRId64 ",maxKey %" PRId64,
×
5576
               pSDataBlock->info.id.uid, pSDataBlock->info.window.skey, pSDataBlock->info.window.ekey);
5577
      }
5578
    }
5579
    startPos = getNextQualifiedFinalWindow(&pInfo->interval, &nextWin, &pSDataBlock->info, tsCol, prevEndPos);
1,294✔
5580
    if (startPos < 0) {
1,294✔
5581
      break;
38✔
5582
    }
5583
  }
5584

5585
_end:
38✔
5586
  if (code != TSDB_CODE_SUCCESS) {
38!
5587
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
5588
  }
5589
}
38✔
5590

5591
static int32_t addMidRetriveWindow(SArray* wins, SHashObj* pMidPullMap, int32_t numOfChild) {
12✔
5592
  int32_t code = TSDB_CODE_SUCCESS;
12✔
5593
  int32_t lino = 0;
12✔
5594
  int32_t size = taosArrayGetSize(wins);
12✔
5595
  for (int32_t i = 0; i < size; i++) {
18✔
5596
    SWinKey* winKey = taosArrayGet(wins, i);
6✔
5597
    void*    chIds = taosHashGet(pMidPullMap, winKey, sizeof(SWinKey));
6✔
5598
    if (!chIds) {
6!
5599
      code = addPullWindow(pMidPullMap, winKey, numOfChild);
6✔
5600
      qDebug("===stream===prepare mid operator retrive for delete %" PRId64 ", size:%d", winKey->ts, numOfChild);
6!
5601
      QUERY_CHECK_CODE(code, lino, _end);
6!
5602
    }
5603
  }
5604
_end:
12✔
5605
  if (code != TSDB_CODE_SUCCESS) {
12!
UNCOV
5606
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
5607
  }
5608
  return code;
12✔
5609
}
5610

5611
static SSDataBlock* buildMidIntervalResult(SOperatorInfo* pOperator) {
101✔
5612
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
101✔
5613
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
101✔
5614
  uint16_t                     opType = pOperator->operatorType;
101✔
5615

5616
  if (pInfo->recvPullover) {
101✔
5617
    pInfo->recvPullover = false;
6✔
5618
    printDataBlock(pInfo->pMidPulloverRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
6✔
5619
    return pInfo->pMidPulloverRes;
6✔
5620
  }
5621

5622
  qDebug("===stream=== build mid interval result");
95!
5623
  doBuildDeleteResult(pInfo, pInfo->pMidPullDatas, &pInfo->midDelIndex, pInfo->pDelRes);
95✔
5624
  if (pInfo->pDelRes->info.rows != 0) {
95!
5625
    // process the rest of the data
5626
    printDataBlock(pInfo->pDelRes, getStreamOpName(opType), GET_TASKID(pTaskInfo));
×
5627
    return pInfo->pDelRes;
×
5628
  }
5629

5630
  if (pInfo->recvRetrive) {
95✔
5631
    pInfo->recvRetrive = false;
12✔
5632
    printDataBlock(pInfo->pMidRetriveRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
12✔
5633
    return pInfo->pMidRetriveRes;
12✔
5634
  }
5635

5636
  return NULL;
83✔
5637
}
5638

5639
static int32_t doStreamMidIntervalAggNext(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
100✔
5640
  int32_t                      code = TSDB_CODE_SUCCESS;
100✔
5641
  int32_t                      lino = 0;
100✔
5642
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
100✔
5643
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
100✔
5644
  SStorageAPI*                 pAPI = &pOperator->pTaskInfo->storageAPI;
100✔
5645
  SOperatorInfo*               downstream = pOperator->pDownstream[0];
100✔
5646
  SExprSupp*                   pSup = &pOperator->exprSupp;
100✔
5647

5648
  qDebug("stask:%s  %s status: %d", GET_TASKID(pTaskInfo), getStreamOpName(pOperator->operatorType), pOperator->status);
100!
5649

5650
  if (pOperator->status == OP_EXEC_DONE) {
100!
UNCOV
5651
    (*ppRes) = NULL;
×
5652
    return code;
×
5653
  } else if (pOperator->status == OP_RES_TO_RETURN) {
100✔
5654
    SSDataBlock* resBlock = NULL;
32✔
5655
    code = buildIntervalResult(pOperator, &resBlock);
32✔
5656
    QUERY_CHECK_CODE(code, lino, _end);
32!
5657
    if (resBlock != NULL) {
32✔
5658
      (*ppRes) = resBlock;
8✔
5659
      return code;
32✔
5660
    }
5661

5662
    setOperatorCompleted(pOperator);
24✔
5663
    clearFunctionContext(&pOperator->exprSupp);
24✔
5664
    clearStreamIntervalOperator(pInfo);
24✔
5665
    qDebug("stask:%s  ===stream===%s clear", GET_TASKID(pTaskInfo), getStreamOpName(pOperator->operatorType));
24!
5666
    (*ppRes) = NULL;
24✔
5667
    return code;
24✔
5668
  } else {
5669
    SSDataBlock* resBlock = NULL;
68✔
5670
    code = buildIntervalResult(pOperator, &resBlock);
68✔
5671
    QUERY_CHECK_CODE(code, lino, _end);
68!
5672
    if (resBlock != NULL) {
68!
5673
      (*ppRes) = resBlock;
×
5674
      return code;
4✔
5675
    }
5676

5677
    resBlock = buildMidIntervalResult(pOperator);
68✔
5678
    if (resBlock != NULL) {
68✔
5679
      (*ppRes) = resBlock;
4✔
5680
      return code;
4✔
5681
    }
5682

5683
    if (pInfo->clearState) {
64✔
5684
      pInfo->clearState = false;
18✔
5685
      clearFunctionContext(&pOperator->exprSupp);
18✔
5686
      clearStreamIntervalOperator(pInfo);
18✔
5687
    }
5688
  }
5689

5690
  if (!pInfo->pUpdated) {
64✔
5691
    pInfo->pUpdated = taosArrayInit(4096, POINTER_BYTES);
61✔
5692
    QUERY_CHECK_NULL(pInfo->pUpdated, code, lino, _end, terrno);
61!
5693
  }
5694
  if (!pInfo->pUpdatedMap) {
64✔
5695
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
61✔
5696
    pInfo->pUpdatedMap = tSimpleHashInit(4096, hashFn);
61✔
5697
    QUERY_CHECK_NULL(pInfo->pUpdatedMap, code, lino, _end, terrno);
61!
5698
  }
5699

5700
  while (1) {
54✔
5701
    if (isTaskKilled(pTaskInfo)) {
118!
5702
      qInfo("===stream=== %s task is killed, code %s", GET_TASKID(pTaskInfo), tstrerror(pTaskInfo->code));
×
UNCOV
5703
      (*ppRes) = NULL;
×
5704
      return code;
3✔
5705
    }
5706

5707
    SSDataBlock* pBlock = NULL;
118✔
5708
    code = downstream->fpSet.getNextFn(downstream, &pBlock);
118✔
5709
    QUERY_CHECK_CODE(code, lino, _end);
118!
5710

5711
    if (pBlock == NULL) {
118✔
5712
      pOperator->status = OP_RES_TO_RETURN;
43✔
5713
      qDebug("===stream===return data:%s. recv datablock num:%" PRIu64, getStreamOpName(pOperator->operatorType),
43!
5714
             pInfo->numOfDatapack);
5715
      pInfo->numOfDatapack = 0;
43✔
5716
      break;
43✔
5717
    }
5718
    pInfo->numOfDatapack++;
75✔
5719
    printSpecDataBlock(pBlock, getStreamOpName(pOperator->operatorType), "recv", GET_TASKID(pTaskInfo));
75✔
5720
    setStreamOperatorState(&pInfo->basic, pBlock->info.type);
75✔
5721

5722
    if (pBlock->info.type == STREAM_NORMAL || pBlock->info.type == STREAM_PULL_DATA) {
75✔
5723
      pInfo->binfo.pRes->info.type = pBlock->info.type;
10✔
5724
    } else if (pBlock->info.type == STREAM_DELETE_DATA || pBlock->info.type == STREAM_DELETE_RESULT ||
65!
5725
               pBlock->info.type == STREAM_CLEAR) {
63✔
5726
      SArray* delWins = taosArrayInit(8, sizeof(SWinKey));
3✔
5727
      if (!delWins) {
3!
5728
        code = terrno;
×
5729
        QUERY_CHECK_CODE(code, lino, _end);
×
5730
      }
5731
      code =
5732
          doDeleteWindows(pOperator, &pInfo->interval, pBlock, delWins, pInfo->pUpdatedMap, pInfo->pFinalPullDataMap);
3✔
5733
      QUERY_CHECK_CODE(code, lino, _end);
3!
5734

5735
      removeResults(delWins, pInfo->pUpdatedMap);
3✔
5736
      void* tmp = taosArrayAddAll(pInfo->pDelWins, delWins);
3✔
5737
      if (!tmp && taosArrayGetSize(delWins) > 0) {
3!
5738
        code = TSDB_CODE_OUT_OF_MEMORY;
×
UNCOV
5739
        QUERY_CHECK_CODE(code, lino, _end);
×
5740
      }
5741
      taosArrayDestroy(delWins);
3✔
5742

5743
      doBuildDeleteResult(pInfo, pInfo->pDelWins, &pInfo->delIndex, pInfo->pDelRes);
3✔
5744
      if (pInfo->pDelRes->info.rows != 0) {
3!
5745
        // process the rest of the data
5746
        printDataBlock(pInfo->pDelRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
3✔
5747
        if (pBlock->info.type == STREAM_CLEAR) {
3✔
5748
          pInfo->pDelRes->info.type = STREAM_CLEAR;
1✔
5749
        } else {
5750
          pInfo->pDelRes->info.type = STREAM_DELETE_RESULT;
2✔
5751
        }
5752
        (*ppRes) = pInfo->pDelRes;
3✔
5753
        return code;
3✔
5754
      }
5755
      continue;
16✔
5756
    } else if (pBlock->info.type == STREAM_CREATE_CHILD_TABLE) {
62!
5757
      (*ppRes) = pBlock;
×
5758
      return code;
×
5759
    } else if (pBlock->info.type == STREAM_PULL_OVER) {
62✔
5760
      code = processPullOver(pBlock, pInfo->pPullDataMap, pInfo->pFinalPullDataMap, &pInfo->interval, pInfo->pPullWins,
12✔
5761
                             pInfo->numOfChild, pOperator, &pInfo->recvPullover);
5762
      QUERY_CHECK_CODE(code, lino, _end);
12!
5763

5764
      if (pInfo->recvPullover) {
12✔
5765
        code = copyDataBlock(pInfo->pMidPulloverRes, pBlock);
6✔
5766
        QUERY_CHECK_CODE(code, lino, _end);
6!
5767

5768
        pInfo->clearState = true;
6✔
5769
        break;
6✔
5770
      }
5771
      continue;
6✔
5772
    } else if (pBlock->info.type == STREAM_CHECKPOINT) {
50✔
5773
      pAPI->stateStore.streamStateCommit(pInfo->pState);
10✔
5774
      doStreamIntervalSaveCheckpoint(pOperator);
10✔
5775
      code = copyDataBlock(pInfo->pCheckpointRes, pBlock);
10✔
5776
      QUERY_CHECK_CODE(code, lino, _end);
10!
5777

5778
      continue;
10✔
5779
    } else if (pBlock->info.type == STREAM_MID_RETRIEVE) {
40✔
5780
      SArray* delWins = taosArrayInit(8, sizeof(SWinKey));
12✔
5781
      if (!delWins) {
12!
5782
        code = terrno;
×
5783
        QUERY_CHECK_CODE(code, lino, _end);
×
5784
      }
5785
      code = doDeleteWindows(pOperator, &pInfo->interval, pBlock, delWins, pInfo->pUpdatedMap, NULL);
12✔
5786
      QUERY_CHECK_CODE(code, lino, _end);
12!
5787

5788
      code = addMidRetriveWindow(delWins, pInfo->pPullDataMap, pInfo->numOfChild);
12✔
5789
      QUERY_CHECK_CODE(code, lino, _end);
12!
5790

5791
      taosArrayDestroy(delWins);
12✔
5792
      pInfo->recvRetrive = true;
12✔
5793
      code = copyDataBlock(pInfo->pMidRetriveRes, pBlock);
12✔
5794
      QUERY_CHECK_CODE(code, lino, _end);
12!
5795

5796
      pInfo->pMidRetriveRes->info.type = STREAM_MID_RETRIEVE;
12✔
5797
      pInfo->clearState = true;
12✔
5798
      break;
12✔
5799
    } else {
5800
      if (pBlock->info.type != STREAM_INVALID) {
28!
5801
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
5802
        QUERY_CHECK_CODE(code, lino, _end);
×
5803
      }
5804
    }
5805

5806
    if (pInfo->scalarSupp.pExprInfo != NULL) {
38!
5807
      SExprSupp* pExprSup = &pInfo->scalarSupp;
×
5808
      code = projectApplyFunctions(pExprSup->pExprInfo, pBlock, pBlock, pExprSup->pCtx, pExprSup->numOfExprs, NULL);
×
UNCOV
5809
      QUERY_CHECK_CODE(code, lino, _end);
×
5810
    }
5811
    code = setInputDataBlock(pSup, pBlock, TSDB_ORDER_ASC, MAIN_SCAN, true);
38✔
5812
    QUERY_CHECK_CODE(code, lino, _end);
38!
5813
    doStreamMidIntervalAggImpl(pOperator, pBlock, pInfo->pUpdatedMap);
38✔
5814
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.window.ekey);
38✔
5815
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.watermark);
38✔
5816
    pInfo->twAggSup.minTs = TMIN(pInfo->twAggSup.minTs, pBlock->info.window.skey);
38✔
5817
  }
5818

5819
  removeDeleteResults(pInfo->pUpdatedMap, pInfo->pDelWins);
61✔
5820
  pInfo->binfo.pRes->info.watermark = pInfo->twAggSup.maxTs;
61✔
5821

5822
  void*   pIte = NULL;
61✔
5823
  int32_t iter = 0;
61✔
5824
  while ((pIte = tSimpleHashIterate(pInfo->pUpdatedMap, pIte, &iter)) != NULL) {
1,250✔
5825
    void* tmp = taosArrayPush(pInfo->pUpdated, pIte);
1,189✔
5826
    if (!tmp) {
1,189!
5827
      code = terrno;
×
UNCOV
5828
      QUERY_CHECK_CODE(code, lino, _end);
×
5829
    }
5830
  }
5831

5832
  tSimpleHashCleanup(pInfo->pUpdatedMap);
61✔
5833
  pInfo->pUpdatedMap = NULL;
61✔
5834
  taosArraySort(pInfo->pUpdated, winPosCmprImpl);
61✔
5835

5836
  initMultiResInfoFromArrayList(&pInfo->groupResInfo, pInfo->pUpdated);
61✔
5837
  pInfo->pUpdated = NULL;
61✔
5838
  code = blockDataEnsureCapacity(pInfo->binfo.pRes, pOperator->resultInfo.capacity);
61✔
5839
  QUERY_CHECK_CODE(code, lino, _end);
61!
5840

5841
  SSDataBlock* resBlock = NULL;
61✔
5842
  code = buildIntervalResult(pOperator, &resBlock);
61✔
5843
  QUERY_CHECK_CODE(code, lino, _end);
61!
5844
  if (resBlock != NULL) {
61✔
5845
    (*ppRes) = resBlock;
28✔
5846
    return code;
28✔
5847
  }
5848

5849
  resBlock = buildMidIntervalResult(pOperator);
33✔
5850
  if (resBlock != NULL) {
33✔
5851
    (*ppRes) = resBlock;
14✔
5852
    return code;
14✔
5853
  }
5854

5855
  if (pInfo->clearState) {
19!
UNCOV
5856
    pInfo->clearState = false;
×
UNCOV
5857
    clearFunctionContext(&pOperator->exprSupp);
×
UNCOV
5858
    clearStreamIntervalOperator(pInfo);
×
5859
  }
5860

5861
_end:
19✔
5862
  if (code != TSDB_CODE_SUCCESS) {
19!
UNCOV
5863
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
UNCOV
5864
    pTaskInfo->code = code;
×
UNCOV
5865
    T_LONG_JMP(pTaskInfo->env, code);
×
5866
  }
5867
  (*ppRes) = NULL;
19✔
5868
  return code;
19✔
5869
}
5870

UNCOV
5871
static SSDataBlock* doStreamMidIntervalAgg(SOperatorInfo* pOperator) {
×
UNCOV
5872
  SSDataBlock* pRes = NULL;
×
UNCOV
5873
  int32_t      code = doStreamMidIntervalAggNext(pOperator, &pRes);
×
UNCOV
5874
  return pRes;
×
5875
}
5876

5877
void setStreamOperatorCompleted(SOperatorInfo* pOperator) {
42,364✔
5878
  qDebug("stask:%s  %s status: %d. set completed", GET_TASKID(pOperator->pTaskInfo),
42,364✔
5879
         getStreamOpName(pOperator->operatorType), pOperator->status);
5880
  setOperatorCompleted(pOperator);
42,364✔
5881
}
42,366✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc