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

taosdata / TDengine / #4113

17 May 2025 06:43AM UTC coverage: 62.054% (-0.8%) from 62.857%
#4113

push

travis-ci

web-flow
Merge pull request #31115 from taosdata/merge/mainto3.0

merge: from main to 3.0 branch

154737 of 318088 branches covered (48.65%)

Branch coverage included in aggregate %.

175 of 225 new or added lines in 20 files covered. (77.78%)

5853 existing lines in 216 files now uncovered.

239453 of 317147 relevant lines covered (75.5%)

15121865.73 hits per line

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

68.71
/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 "streaminterval.h"
23
#include "streamsession.h"
24
#include "tchecksum.h"
25
#include "tcommon.h"
26
#include "tcompare.h"
27
#include "tdatablock.h"
28
#include "tfill.h"
29
#include "tglobal.h"
30
#include "tlog.h"
31
#include "ttime.h"
32

33
#define IS_FINAL_INTERVAL_OP(op) ((op)->operatorType == QUERY_NODE_PHYSICAL_PLAN_STREAM_FINAL_INTERVAL)
34
#define IS_MID_INTERVAL_OP(op)   ((op)->operatorType == QUERY_NODE_PHYSICAL_PLAN_STREAM_MID_INTERVAL)
35

36
#define IS_FINAL_SESSION_OP(op) ((op)->operatorType == QUERY_NODE_PHYSICAL_PLAN_STREAM_FINAL_SESSION)
37

38
#define DEAULT_DELETE_MARK                 INT64_MAX
39
#define STREAM_INTERVAL_OP_STATE_NAME      "StreamIntervalHistoryState"
40
#define STREAM_SESSION_OP_STATE_NAME       "StreamSessionHistoryState"
41
#define STREAM_STATE_OP_STATE_NAME         "StreamStateHistoryState"
42
#define STREAM_INTERVAL_OP_CHECKPOINT_NAME "StreamIntervalOperator_Checkpoint"
43
#define STREAM_SESSION_OP_CHECKPOINT_NAME  "StreamSessionOperator_Checkpoint"
44
#define STREAM_STATE_OP_CHECKPOINT_NAME    "StreamStateOperator_Checkpoint"
45

46
#define MAX_STREAM_HISTORY_RESULT 20000000
47

48
static int32_t doStreamMidIntervalAggNext(SOperatorInfo* pOperator, SSDataBlock** ppRes);
49

50
int32_t binarySearchCom(void* keyList, int num, void* pKey, int order, __compare_fn_t comparefn) {
1,243✔
51
  int firstPos = 0, lastPos = num - 1, midPos = -1;
1,243✔
52
  int numOfRows = 0;
1,243✔
53

54
  if (num <= 0) return -1;
1,243✔
55
  if (order == TSDB_ORDER_DESC) {
1,015!
56
    // find the first position which is smaller or equal than the key
57
    while (1) {
58
      if (comparefn(pKey, keyList, lastPos) >= 0) return lastPos;
1,109✔
59
      if (comparefn(pKey, keyList, firstPos) == 0) return firstPos;
318✔
60
      if (comparefn(pKey, keyList, firstPos) < 0) return firstPos - 1;
208✔
61

62
      numOfRows = lastPos - firstPos + 1;
161✔
63
      midPos = (numOfRows >> 1) + firstPos;
161✔
64

65
      if (comparefn(pKey, keyList, midPos) < 0) {
161✔
66
        lastPos = midPos - 1;
66✔
67
      } else if (comparefn(pKey, keyList, midPos) > 0) {
95✔
68
        firstPos = midPos + 1;
28✔
69
      } else {
70
        break;
67✔
71
      }
72
    }
73

74
  } else {
75
    // find the first position which is bigger or equal than the key
76
    while (1) {
77
      if (comparefn(pKey, keyList, firstPos) <= 0) return firstPos;
×
78
      if (comparefn(pKey, keyList, lastPos) == 0) return lastPos;
×
79

80
      if (comparefn(pKey, keyList, lastPos) > 0) {
×
81
        lastPos = lastPos + 1;
×
82
        if (lastPos >= num)
×
83
          return -1;
×
84
        else
85
          return lastPos;
×
86
      }
87

88
      numOfRows = lastPos - firstPos + 1;
×
89
      midPos = (numOfRows >> 1) + firstPos;
×
90

91
      if (comparefn(pKey, keyList, midPos) < 0) {
×
92
        lastPos = midPos - 1;
×
93
      } else if (comparefn(pKey, keyList, midPos) > 0) {
×
94
        firstPos = midPos + 1;
×
95
      } else {
96
        break;
×
97
      }
98
    }
99
  }
100

101
  return midPos;
67✔
102
}
103

104
static int32_t comparePullWinKey(void* pKey, void* data, int32_t index) {
176✔
105
  SArray*          res = (SArray*)data;
176✔
106
  SPullWindowInfo* pos = taosArrayGet(res, index);
176✔
107
  SPullWindowInfo* pData = (SPullWindowInfo*)pKey;
176✔
108
  if (pData->groupId > pos->groupId) {
176✔
109
    return 1;
70✔
110
  } else if (pData->groupId < pos->groupId) {
106✔
111
    return -1;
51✔
112
  }
113

114
  if (pData->window.skey > pos->window.ekey) {
55✔
115
    return 1;
43✔
116
  } else if (pData->window.ekey < pos->window.skey) {
12✔
117
    return -1;
6✔
118
  }
119
  return 0;
6✔
120
}
121

122
static int32_t savePullWindow(SPullWindowInfo* pPullInfo, SArray* pPullWins) {
224✔
123
  int32_t size = taosArrayGetSize(pPullWins);
224✔
124
  int32_t index = binarySearchCom(pPullWins, size, pPullInfo, TSDB_ORDER_DESC, comparePullWinKey);
224✔
125
  if (index == -1) {
224✔
126
    index = 0;
173✔
127
  } else {
128
    int32_t code = comparePullWinKey(pPullInfo, pPullWins, index);
51✔
129
    if (code == 0) {
51✔
130
      SPullWindowInfo* pos = taosArrayGet(pPullWins, index);
3✔
131
      pos->window.skey = TMIN(pos->window.skey, pPullInfo->window.skey);
3✔
132
      pos->window.ekey = TMAX(pos->window.ekey, pPullInfo->window.ekey);
3✔
133
      pos->calWin.skey = TMIN(pos->calWin.skey, pPullInfo->calWin.skey);
3✔
134
      pos->calWin.ekey = TMAX(pos->calWin.ekey, pPullInfo->calWin.ekey);
3✔
135
      return TSDB_CODE_SUCCESS;
3✔
136
    } else if (code > 0) {
48!
137
      index++;
48✔
138
    }
139
  }
140
  if (taosArrayInsert(pPullWins, index, pPullInfo) == NULL) {
221!
141
    return terrno;
×
142
  }
143
  return TSDB_CODE_SUCCESS;
221✔
144
}
145

146
int32_t saveResult(SResultWindowInfo winInfo, SSHashObj* pStUpdated) {
10,328✔
147
  if (tSimpleHashGetSize(pStUpdated) > MAX_STREAM_HISTORY_RESULT) {
10,328!
148
    qError("%s failed at line %d since too many history result. ", __func__, __LINE__);
×
149
    return TSDB_CODE_STREAM_INTERNAL_ERROR;
×
150
  }
151
  winInfo.sessionWin.win.ekey = winInfo.sessionWin.win.skey;
10,329✔
152
  return tSimpleHashPut(pStUpdated, &winInfo.sessionWin, sizeof(SSessionKey), &winInfo, sizeof(SResultWindowInfo));
10,329✔
153
}
154

155
int32_t saveWinResult(SWinKey* pKey, SRowBuffPos* pPos, SSHashObj* pUpdatedMap) {
10,322,318✔
156
  if (tSimpleHashGetSize(pUpdatedMap) > MAX_STREAM_HISTORY_RESULT) {
10,322,318!
157
    qError("%s failed at line %d since too many history result. ", __func__, __LINE__);
×
158
    return TSDB_CODE_STREAM_INTERNAL_ERROR;
×
159
  }
160
  return tSimpleHashPut(pUpdatedMap, pKey, sizeof(SWinKey), &pPos, POINTER_BYTES);
10,322,297✔
161
}
162

163
static int32_t saveWinResultInfo(TSKEY ts, uint64_t groupId, SRowBuffPos* pPos, SSHashObj* pUpdatedMap) {
280✔
164
  SWinKey key = {.ts = ts, .groupId = groupId};
280✔
165
  return saveWinResult(&key, pPos, pUpdatedMap);
280✔
166
}
167

168
static void removeResults(SArray* pWins, SSHashObj* pUpdatedMap) {
207✔
169
  int32_t size = taosArrayGetSize(pWins);
207✔
170
  for (int32_t i = 0; i < size; i++) {
456✔
171
    SWinKey* pW = taosArrayGet(pWins, i);
249✔
172
    void*    tmp = tSimpleHashGet(pUpdatedMap, pW, sizeof(SWinKey));
249✔
173
    if (tmp) {
249!
174
      void* value = *(void**)tmp;
×
175
      taosMemoryFree(value);
×
176
      int32_t tmpRes = tSimpleHashRemove(pUpdatedMap, pW, sizeof(SWinKey));
×
177
      qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
×
178
    }
179
  }
180
}
207✔
181

182
int32_t compareWinKey(void* pKey, void* data, int32_t index) {
2,688✔
183
  void* pDataPos = taosArrayGet((SArray*)data, index);
2,688✔
184
  return winKeyCmprImpl(pKey, pDataPos);
2,688✔
185
}
186

187
void removeDeleteResults(SSHashObj* pUpdatedMap, SArray* pDelWins) {
16,017✔
188
  taosArraySort(pDelWins, winKeyCmprImpl);
16,017✔
189
  taosArrayRemoveDuplicate(pDelWins, winKeyCmprImpl, NULL);
16,019✔
190
  int32_t delSize = taosArrayGetSize(pDelWins);
16,019✔
191
  if (tSimpleHashGetSize(pUpdatedMap) == 0 || delSize == 0) {
16,019✔
192
    return;
15,673✔
193
  }
194
  void*   pIte = NULL;
346✔
195
  int32_t iter = 0;
346✔
196
  while ((pIte = tSimpleHashIterate(pUpdatedMap, pIte, &iter)) != NULL) {
1,147✔
197
    SWinKey* pResKey = tSimpleHashGetKey(pIte, NULL);
801✔
198
    int32_t  index = binarySearchCom(pDelWins, delSize, pResKey, TSDB_ORDER_DESC, compareWinKey);
801✔
199
    if (index >= 0 && 0 == compareWinKey(pResKey, pDelWins, index)) {
801✔
200
      taosArrayRemove(pDelWins, index);
600✔
201
      delSize = taosArrayGetSize(pDelWins);
600✔
202
    }
203
  }
204
}
205

206
bool isOverdue(TSKEY ekey, STimeWindowAggSupp* pTwSup) {
30,846,218✔
207
  return pTwSup->maxTs != INT64_MIN && ekey < pTwSup->maxTs - pTwSup->waterMark;
30,846,218✔
208
}
209

210
bool isCloseWindow(STimeWindow* pWin, STimeWindowAggSupp* pTwSup) { return isOverdue(pWin->ekey, pTwSup); }
15,504,219✔
211

212
static void doDeleteWindow(SOperatorInfo* pOperator, TSKEY ts, uint64_t groupId) {
3,147✔
213
  SStorageAPI* pAPI = &pOperator->pTaskInfo->storageAPI;
3,147✔
214

215
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
3,147✔
216
  SWinKey                      key = {.ts = ts, .groupId = groupId};
3,147✔
217
  int32_t                      tmpRes = tSimpleHashRemove(pInfo->aggSup.pResultRowHashTable, &key, sizeof(SWinKey));
3,147✔
218
  qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
3,147!
219
  pAPI->stateStore.streamStateDel(pInfo->pState, &key);
3,147✔
220
}
3,138✔
221

222
int32_t getChildIndex(SSDataBlock* pBlock) { return pBlock->info.childId; }
1,424✔
223

224
static void doDeleteWindowByGroupId(SOperatorInfo* pOperator, SSDataBlock* pBlock) {
×
225
  SStorageAPI*                 pAPI = &pOperator->pTaskInfo->storageAPI;
×
226
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
×
227

228
  SColumnInfoData* pGpIdCol = taosArrayGet(pBlock->pDataBlock, UID_COLUMN_INDEX);
×
229
  uint64_t* pGroupIdData = (uint64_t*)pGpIdCol->pData;
×
230
  for (int32_t i = 0; i < pBlock->info.rows; i++) {
×
231
    uint64_t groupId = pGroupIdData[i];
×
232
    void*   pIte = NULL;
×
233
    int32_t iter = 0;
×
234
    while ((pIte = tSimpleHashIterate(pInfo->aggSup.pResultRowHashTable, pIte, &iter)) != NULL) {
×
235
      size_t keyLen = 0;
×
236
      SWinKey* pKey = tSimpleHashGetKey(pIte, &keyLen);
×
237
      if (pKey->groupId == groupId) {
×
238
        int32_t tmpRes = tSimpleHashIterateRemove(pInfo->aggSup.pResultRowHashTable, pKey, keyLen, &pIte, &iter);
×
239
        qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
×
240
      }
241
    }
242

243
    pAPI->stateStore.streamStateDelByGroupId(pInfo->pState, groupId);
×
244
  }
245
}
×
246

247
static int32_t doDeleteWindows(SOperatorInfo* pOperator, SInterval* pInterval, SSDataBlock* pBlock, SArray* pUpWins,
1,990✔
248
                               SSHashObj* pUpdatedMap, SHashObj* pInvalidWins) {
249
  int32_t                      code = TSDB_CODE_SUCCESS;
1,990✔
250
  int32_t                      lino = 0;
1,990✔
251
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
1,990✔
252
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
1,990✔
253
  SColumnInfoData*             pStartTsCol = taosArrayGet(pBlock->pDataBlock, START_TS_COLUMN_INDEX);
1,990✔
254
  TSKEY*                       startTsCols = (TSKEY*)pStartTsCol->pData;
1,990✔
255
  SColumnInfoData*             pEndTsCol = taosArrayGet(pBlock->pDataBlock, END_TS_COLUMN_INDEX);
1,990✔
256
  TSKEY*                       endTsCols = (TSKEY*)pEndTsCol->pData;
1,990✔
257
  SColumnInfoData*             pCalStTsCol = taosArrayGet(pBlock->pDataBlock, CALCULATE_START_TS_COLUMN_INDEX);
1,990✔
258
  TSKEY*                       calStTsCols = (TSKEY*)pCalStTsCol->pData;
1,990✔
259
  SColumnInfoData*             pCalEnTsCol = taosArrayGet(pBlock->pDataBlock, CALCULATE_END_TS_COLUMN_INDEX);
1,990✔
260
  TSKEY*                       calEnTsCols = (TSKEY*)pCalEnTsCol->pData;
1,990✔
261
  SColumnInfoData*             pGpCol = taosArrayGet(pBlock->pDataBlock, GROUPID_COLUMN_INDEX);
1,990✔
262
  uint64_t*                    pGpDatas = (uint64_t*)pGpCol->pData;
1,990✔
263
  for (int32_t i = 0; i < pBlock->info.rows; i++) {
4,286✔
264
    SResultRowInfo dumyInfo = {0};
2,298✔
265
    dumyInfo.cur.pageId = -1;
2,298✔
266

267
    STimeWindow win = {0};
2,298✔
268
    if (IS_FINAL_INTERVAL_OP(pOperator) || IS_MID_INTERVAL_OP(pOperator)) {
2,298✔
269
      win.skey = startTsCols[i];
261✔
270
      win.ekey = endTsCols[i];
261✔
271
    } else {
272
      win = getActiveTimeWindow(NULL, &dumyInfo, startTsCols[i], pInterval, TSDB_ORDER_ASC);
2,037✔
273
    }
274

275
    do {
276
      if (!inCalSlidingWindow(pInterval, &win, calStTsCols[i], calEnTsCols[i], pBlock->info.type)) {
3,201✔
277
        getNextTimeWindow(pInterval, &win, TSDB_ORDER_ASC);
26✔
278
        continue;
75✔
279
      }
280
      uint64_t winGpId = pGpDatas[i];
3,175✔
281
      SWinKey  winRes = {.ts = win.skey, .groupId = winGpId};
3,175✔
282
      void*    chIds = taosHashGet(pInfo->pPullDataMap, &winRes, sizeof(SWinKey));
3,175✔
283
      if (chIds) {
3,174✔
284
        int32_t childId = getChildIndex(pBlock);
51✔
285
        if (pInvalidWins) {
51✔
286
          qDebug("===stream===save invalid delete window:%" PRId64 ",groupId:%" PRId64 ",chId:%d", winRes.ts,
45✔
287
                 winRes.groupId, childId);
288
          code = taosHashPut(pInvalidWins, &winRes, sizeof(SWinKey), NULL, 0);
45✔
289
          QUERY_CHECK_CODE(code, lino, _end);
45!
290
        }
291

292
        SArray* chArray = *(void**)chIds;
51✔
293
        int32_t index = taosArraySearchIdx(chArray, &childId, compareInt32Val, TD_EQ);
51✔
294
        if (index != -1) {
51✔
295
          qDebug("===stream===try push delete window:%" PRId64 ",groupId:%" PRId64 ",chId:%d ,continue", win.skey,
49✔
296
                 winGpId, childId);
297
          getNextTimeWindow(pInterval, &win, TSDB_ORDER_ASC);
49✔
298
          continue;
49✔
299
        }
300
      }
301
      doDeleteWindow(pOperator, win.skey, winGpId);
3,125✔
302
      if (pUpWins) {
3,118✔
303
        void* tmp = taosArrayPush(pUpWins, &winRes);
2,340✔
304
        if (!tmp) {
2,340!
305
          code = terrno;
×
306
          QUERY_CHECK_CODE(code, lino, _end);
×
307
        }
308
      }
309
      if (pUpdatedMap) {
3,114✔
310
        int32_t tmpRes = tSimpleHashRemove(pUpdatedMap, &winRes, sizeof(SWinKey));
3,113✔
311
        qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
3,123!
312
      }
313
      getNextTimeWindow(pInterval, &win, TSDB_ORDER_ASC);
3,124✔
314
    } while (win.ekey <= endTsCols[i]);
3,198✔
315
  }
316
_end:
1,988✔
317
  if (code != TSDB_CODE_SUCCESS) {
1,988!
318
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
319
  }
320
  return code;
1,988✔
321
}
322

323
static int32_t getAllIntervalWindow(SSHashObj* pHashMap, SSHashObj* resWins) {
805✔
324
  void*   pIte = NULL;
805✔
325
  int32_t iter = 0;
805✔
326
  while ((pIte = tSimpleHashIterate(pHashMap, pIte, &iter)) != NULL) {
1,095✔
327
    SWinKey*     pKey = tSimpleHashGetKey(pIte, NULL);
290✔
328
    uint64_t     groupId = pKey->groupId;
290✔
329
    TSKEY        ts = pKey->ts;
290✔
330
    SRowBuffPos* pPos = *(SRowBuffPos**)pIte;
290✔
331
    if (!pPos->beUpdated) {
290✔
332
      continue;
10✔
333
    }
334
    pPos->beUpdated = false;
280✔
335
    int32_t code = saveWinResultInfo(ts, groupId, pPos, resWins);
280✔
336
    if (code != TSDB_CODE_SUCCESS) {
280!
337
      return code;
×
338
    }
339
  }
340
  return TSDB_CODE_SUCCESS;
805✔
341
}
342

343
static int32_t closeStreamIntervalWindow(SSHashObj* pHashMap, STimeWindowAggSupp* pTwSup, SInterval* pInterval,
13,989✔
344
                                         SHashObj* pPullDataMap, SSHashObj* closeWins, SArray* pDelWins,
345
                                         SOperatorInfo* pOperator) {
346
  qDebug("===stream===close interval window");
13,989✔
347
  int32_t                      code = TSDB_CODE_SUCCESS;
13,989✔
348
  int32_t                      lino = 0;
13,989✔
349
  void*                        pIte = NULL;
13,989✔
350
  int32_t                      iter = 0;
13,989✔
351
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
13,989✔
352
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
13,989✔
353
  int32_t                      delSize = taosArrayGetSize(pDelWins);
13,989✔
354
  while ((pIte = tSimpleHashIterate(pHashMap, pIte, &iter)) != NULL) {
19,393✔
355
    void*    key = tSimpleHashGetKey(pIte, NULL);
5,405!
356
    SWinKey* pWinKey = (SWinKey*)key;
5,405✔
357
    if (delSize > 0) {
5,405✔
358
      int32_t index = binarySearchCom(pDelWins, delSize, pWinKey, TSDB_ORDER_DESC, compareWinKey);
218✔
359
      if (index >= 0 && 0 == compareWinKey(pWinKey, pDelWins, index)) {
218✔
360
        taosArrayRemove(pDelWins, index);
88✔
361
        delSize = taosArrayGetSize(pDelWins);
88✔
362
      }
363
    }
364

365
    void*       chIds = taosHashGet(pPullDataMap, pWinKey, sizeof(SWinKey));
5,405✔
366
    STimeWindow win = {
10,810✔
367
        .skey = pWinKey->ts,
5,405✔
368
        .ekey = taosTimeAdd(win.skey, pInterval->interval, pInterval->intervalUnit, pInterval->precision, NULL) - 1,
5,405✔
369
    };
370
    if (isCloseWindow(&win, pTwSup)) {
5,405✔
371
      if (chIds && pPullDataMap) {
2,159!
372
        SArray* chAy = *(SArray**)chIds;
1✔
373
        int32_t size = taosArrayGetSize(chAy);
1✔
374
        qDebug("===stream===window %" PRId64 " wait child size:%d", pWinKey->ts, size);
1!
375
        for (int32_t i = 0; i < size; i++) {
2✔
376
          qDebug("===stream===window %" PRId64 " wait child id:%d", pWinKey->ts, *(int32_t*)taosArrayGet(chAy, i));
1!
377
        }
378
        continue;
1✔
379
      } else if (pPullDataMap) {
2,158✔
380
        qDebug("===stream===close window %" PRId64, pWinKey->ts);
92✔
381
      }
382

383
      if (pTwSup->calTrigger == STREAM_TRIGGER_WINDOW_CLOSE) {
2,158!
384
        code = saveWinResult(pWinKey, *(SRowBuffPos**)pIte, closeWins);
2,158✔
385
        QUERY_CHECK_CODE(code, lino, _end);
2,158!
386
      }
387
      int32_t tmpRes = tSimpleHashIterateRemove(pHashMap, pWinKey, sizeof(SWinKey), &pIte, &iter);
2,158✔
388
      qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
2,158!
389
    }
390
  }
391

392
_end:
13,990✔
393
  if (code != TSDB_CODE_SUCCESS) {
13,990!
394
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
395
  }
396
  return code;
13,990✔
397
}
398

399
STimeWindow getFinalTimeWindow(int64_t ts, SInterval* pInterval) {
220,530✔
400
  STimeWindow w = {.skey = ts, .ekey = INT64_MAX};
220,530✔
401
  w.ekey = taosTimeAdd(w.skey, pInterval->interval, pInterval->intervalUnit, pInterval->precision, NULL) - 1;
220,530✔
402
  return w;
220,530✔
403
}
404

405
static void doBuildDeleteResult(SExecTaskInfo* pTaskInfo, SArray* pWins, int32_t* index,
77,206✔
406
                                SSDataBlock* pBlock) {
407
  doBuildDeleteResultImpl(&pTaskInfo->storageAPI.stateStore, pTaskInfo->streamInfo.pState, pWins, index, pBlock);
77,206✔
408
}
77,202✔
409

410
void doBuildDeleteResultImpl(SStateStore* pAPI, SStreamState* pState, SArray* pWins, int32_t* index,
79,406✔
411
                             SSDataBlock* pBlock) {
412
  int32_t code = TSDB_CODE_SUCCESS;
79,406✔
413
  int32_t lino = 0;
79,406✔
414
  blockDataCleanup(pBlock);
79,406✔
415
  int32_t size = taosArrayGetSize(pWins);
79,403✔
416
  if (*index == size) {
79,403✔
417
    *index = 0;
78,767✔
418
    taosArrayClear(pWins);
78,767✔
419
    goto _end;
78,766✔
420
  }
421
  code = blockDataEnsureCapacity(pBlock, size - *index);
636✔
422
  QUERY_CHECK_CODE(code, lino, _end);
636!
423

424
  uint64_t uid = 0;
636✔
425
  for (int32_t i = *index; i < size; i++) {
2,135✔
426
    SWinKey* pWin = taosArrayGet(pWins, i);
1,499✔
427
    void*    tbname = NULL;
1,499✔
428
    int32_t  winCode = TSDB_CODE_SUCCESS;
1,499✔
429
    code = pAPI->streamStateGetParName(pState, pWin->groupId, &tbname, false, &winCode);
1,499✔
430
    QUERY_CHECK_CODE(code, lino, _end);
1,499!
431

432
    if (winCode != TSDB_CODE_SUCCESS) {
1,499✔
433
      code = appendDataToSpecialBlock(pBlock, &pWin->ts, &pWin->ts, &uid, &pWin->groupId, NULL);
1,089✔
434
      QUERY_CHECK_CODE(code, lino, _end);
1,089!
435
    } else {
436
      QUERY_CHECK_CONDITION((tbname), code, lino, _end, TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR);
410!
437
      char parTbName[VARSTR_HEADER_SIZE + TSDB_TABLE_NAME_LEN];
438
      STR_WITH_MAXSIZE_TO_VARSTR(parTbName, tbname, sizeof(parTbName));
410✔
439
      code = appendDataToSpecialBlock(pBlock, &pWin->ts, &pWin->ts, &uid, &pWin->groupId, parTbName);
410✔
440
      QUERY_CHECK_CODE(code, lino, _end);
410!
441
    }
442
    pAPI->streamStateFreeVal(tbname);
1,499✔
443
    (*index)++;
1,499✔
444
  }
445

446
_end:
636✔
447
  if (code != TSDB_CODE_SUCCESS) {
79,402!
448
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
449
  }
450
}
79,402✔
451

452
void destroyFlusedPos(void* pRes) {
803,725✔
453
  SRowBuffPos* pPos = (SRowBuffPos*)pRes;
803,725✔
454
  if (pPos->needFree && !pPos->pRowBuff) {
803,725!
455
    taosMemoryFreeClear(pPos->pKey);
×
456
    taosMemoryFree(pPos);
×
457
  }
458
}
803,725✔
459

460
void destroyFlusedppPos(void* ppRes) {
×
461
  void* pRes = *(void**)ppRes;
×
462
  destroyFlusedPos(pRes);
×
463
}
×
464

465
void clearGroupResInfo(SGroupResInfo* pGroupResInfo) {
2,970✔
466
  int32_t size = taosArrayGetSize(pGroupResInfo->pRows);
2,970✔
467
  if (pGroupResInfo->index >= 0 && pGroupResInfo->index < size) {
2,970!
468
    for (int32_t i = pGroupResInfo->index; i < size; i++) {
803,727✔
469
      void* pPos = taosArrayGetP(pGroupResInfo->pRows, i);
803,725✔
470
      destroyFlusedPos(pPos);
803,725✔
471
    }
472
  }
473

474
  pGroupResInfo->freeItem = false;
2,970✔
475
  taosArrayDestroy(pGroupResInfo->pRows);
2,970✔
476
  pGroupResInfo->pRows = NULL;
2,970✔
477
  pGroupResInfo->index = 0;
2,970✔
478
  pGroupResInfo->delIndex = 0;
2,970✔
479
}
2,970✔
480

481
void destroyStreamFinalIntervalOperatorInfo(void* param) {
2,891✔
482
  if (param == NULL) {
2,891!
483
    return;
×
484
  }
485
  SStreamIntervalOperatorInfo* pInfo = (SStreamIntervalOperatorInfo*)param;
2,891✔
486
  cleanupBasicInfo(&pInfo->binfo);
2,891✔
487
  if (pInfo->pOperator) {
2,891!
488
    cleanupResultInfo(pInfo->pOperator->pTaskInfo, &pInfo->pOperator->exprSupp, &pInfo->groupResInfo, &pInfo->aggSup,
2,891✔
489
                      false);
490
    pInfo->pOperator = NULL;
2,891✔
491
  }
492

493
  destroyStreamBasicInfo(&pInfo->basic);
2,891✔
494
  cleanupAggSup(&pInfo->aggSup);
2,891✔
495
  clearGroupResInfo(&pInfo->groupResInfo);
2,891✔
496
  taosArrayDestroyP(pInfo->pUpdated, destroyFlusedPos);
2,891✔
497
  pInfo->pUpdated = NULL;
2,891✔
498

499
  // it should be empty.
500
  void* pIte = NULL;
2,891✔
501
  while ((pIte = taosHashIterate(pInfo->pPullDataMap, pIte)) != NULL) {
2,891!
502
    taosArrayDestroy(*(void**)pIte);
×
503
  }
504
  taosHashCleanup(pInfo->pPullDataMap);
2,891✔
505
  taosHashCleanup(pInfo->pFinalPullDataMap);
2,891✔
506
  taosArrayDestroy(pInfo->pPullWins);
2,891✔
507
  blockDataDestroy(pInfo->pPullDataRes);
2,891✔
508
  taosArrayDestroy(pInfo->pDelWins);
2,891✔
509
  blockDataDestroy(pInfo->pDelRes);
2,891✔
510
  blockDataDestroy(pInfo->pMidRetriveRes);
2,891✔
511
  blockDataDestroy(pInfo->pMidPulloverRes);
2,891✔
512
  if (pInfo->pUpdatedMap != NULL) {
2,891!
513
    // free flushed pos
514
    tSimpleHashSetFreeFp(pInfo->pUpdatedMap, destroyFlusedppPos);
×
515
    tSimpleHashCleanup(pInfo->pUpdatedMap);
×
516
    pInfo->pUpdatedMap = NULL;
×
517
  }
518

519
  if (pInfo->stateStore.streamFileStateDestroy != NULL) {
2,891!
520
    pInfo->stateStore.streamFileStateDestroy(pInfo->pState->pFileState);
2,891✔
521
  }
522
  taosArrayDestroy(pInfo->pMidPullDatas);
2,891✔
523

524
  if (pInfo->pState != NULL && pInfo->pState->dump == 1) {
2,891!
525
    taosMemoryFreeClear(pInfo->pState->pTdbState->pOwner);
865!
526
    taosMemoryFreeClear(pInfo->pState->pTdbState);
865!
527
  }
528
  taosMemoryFreeClear(pInfo->pState);
2,891!
529

530
  nodesDestroyNode((SNode*)pInfo->pPhyNode);
2,891✔
531
  colDataDestroy(&pInfo->twAggSup.timeWindowData);
2,891✔
532
  cleanupExprSupp(&pInfo->scalarSupp);
2,891✔
533
  tSimpleHashCleanup(pInfo->pDeletedMap);
2,891✔
534

535
  blockDataDestroy(pInfo->pCheckpointRes);
2,891✔
536

537
  taosMemoryFreeClear(param);
2,891!
538
}
539

540
#ifdef BUILD_NO_CALL
541
static bool allInvertible(SqlFunctionCtx* pFCtx, int32_t numOfCols) {
542
  for (int32_t i = 0; i < numOfCols; i++) {
543
    if (fmIsUserDefinedFunc(pFCtx[i].functionId) || !fmIsInvertible(pFCtx[i].functionId)) {
544
      return false;
545
    }
546
  }
547
  return true;
548
}
549
#endif
550

551
void reloadFromDownStream(SOperatorInfo* downstream, SStreamIntervalOperatorInfo* pInfo) {
787✔
552
  SStateStore* pAPI = &downstream->pTaskInfo->storageAPI.stateStore;
787✔
553

554
  if (downstream->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_SCAN) {
787✔
555
    reloadFromDownStream(downstream->pDownstream[0], pInfo);
64✔
556
    return;
64✔
557
  }
558

559
  SStreamScanInfo* pScanInfo = downstream->info;
723✔
560
  pInfo->pUpdateInfo = pScanInfo->pUpdateInfo;
723✔
561
}
562

563
bool hasSrcPrimaryKeyCol(SSteamOpBasicInfo* pInfo) { return pInfo->primaryPkIndex != -1; }
11,056,974✔
564

565
int32_t initIntervalDownStream(SOperatorInfo* downstream, uint16_t type, SStreamIntervalOperatorInfo* pInfo,
2,940✔
566
                               struct SSteamOpBasicInfo* pBasic) {
567
  int32_t        code = TSDB_CODE_SUCCESS;
2,940✔
568
  int32_t        lino = 0;
2,940✔
569
  SStateStore*   pAPI = &downstream->pTaskInfo->storageAPI.stateStore;
2,940✔
570
  SExecTaskInfo* pTaskInfo = downstream->pTaskInfo;
2,940✔
571

572
  if (downstream->operatorType == QUERY_NODE_PHYSICAL_PLAN_STREAM_PARTITION) {
2,940✔
573
    SStreamPartitionOperatorInfo* pScanInfo = downstream->info;
257✔
574
    pBasic->primaryPkIndex = pScanInfo->basic.primaryPkIndex;
257✔
575
  }
576

577
  if (downstream->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_SCAN) {
2,940✔
578
    return initIntervalDownStream(downstream->pDownstream[0], type, pInfo, pBasic);
257✔
579
  }
580

581
  SStreamScanInfo* pScanInfo = downstream->info;
2,683✔
582
  pScanInfo->windowSup.parentType = type;
2,683✔
583
  pScanInfo->windowSup.pIntervalAggSup = &pInfo->aggSup;
2,683✔
584
  if (!pScanInfo->pUpdateInfo) {
2,683✔
585
    code = pAPI->updateInfoInitP(&pInfo->interval, pInfo->twAggSup.waterMark, pScanInfo->igCheckUpdate,
2,422✔
586
                                 pScanInfo->pkColType, pScanInfo->pkColLen, &pScanInfo->pUpdateInfo);
2,422✔
587
    QUERY_CHECK_CODE(code, lino, _end);
2,422!
588
  }
589

590
  pScanInfo->interval = pInfo->interval;
2,683✔
591
  pScanInfo->twAggSup = pInfo->twAggSup;
2,683✔
592
  pScanInfo->pState = pInfo->pState;
2,683✔
593
  pInfo->pUpdateInfo = pScanInfo->pUpdateInfo;
2,683✔
594
  if (!hasSrcPrimaryKeyCol(pBasic)) {
2,683✔
595
    pBasic->primaryPkIndex = pScanInfo->basic.primaryPkIndex;
2,679✔
596
  }
597

598
_end:
4✔
599
  if (code != TSDB_CODE_SUCCESS) {
2,683!
600
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
601
  }
602
  return code;
2,683✔
603
}
604

605
int32_t compactFunctions(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx, int32_t numOfOutput,
45✔
606
                         SExecTaskInfo* pTaskInfo, SColumnInfoData* pTimeWindowData) {
607
  int32_t code = TSDB_CODE_SUCCESS;
45✔
608
  int32_t lino = 0;
45✔
609
  for (int32_t k = 0; k < numOfOutput; ++k) {
263✔
610
    if (fmIsWindowPseudoColumnFunc(pDestCtx[k].functionId)) {
220✔
611
      if (!pTimeWindowData) {
49!
612
        continue;
×
613
      }
614

615
      SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(&pDestCtx[k]);
49✔
616
      char*                p = GET_ROWCELL_INTERBUF(pEntryInfo);
49✔
617
      SColumnInfoData      idata = {0};
49✔
618
      idata.info.type = TSDB_DATA_TYPE_BIGINT;
49✔
619
      idata.info.bytes = tDataTypes[TSDB_DATA_TYPE_BIGINT].bytes;
49✔
620
      idata.pData = p;
49✔
621

622
      SScalarParam out = {.columnData = &idata};
49✔
623
      SScalarParam tw = {.numOfRows = 5, .columnData = pTimeWindowData};
49✔
624
      code = pDestCtx[k].sfp.process(&tw, 1, &out);
49✔
625
      QUERY_CHECK_CODE(code, lino, _end);
49!
626

627
      pEntryInfo->numOfRes = 1;
49✔
628
    } else if (functionNeedToExecute(&pDestCtx[k]) && pDestCtx[k].fpSet.combine != NULL) {
171!
629
      code = pDestCtx[k].fpSet.combine(&pDestCtx[k], &pSourceCtx[k]);
169✔
630
      QUERY_CHECK_CODE(code, lino, _end);
169!
631
    } else if (pDestCtx[k].fpSet.combine == NULL) {
2!
632
      char* funName = fmGetFuncName(pDestCtx[k].functionId);
2✔
633
      qError("%s error, combine funcion for %s is not implemented", GET_TASKID(pTaskInfo), funName);
2!
634
      taosMemoryFreeClear(funName);
2!
635
      code = TSDB_CODE_FAILED;
2✔
636
      QUERY_CHECK_CODE(code, lino, _end);
2!
637
    }
638
  }
639

640
_end:
43✔
641
  if (code != TSDB_CODE_SUCCESS) {
45✔
642
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
2!
643
  }
644
  return code;
45✔
645
}
646

647
bool hasIntervalWindow(void* pState, SWinKey* pKey, SStateStore* pStore) {
24✔
648
  return pStore->streamStateCheck(pState, pKey, false, NULL);
24✔
649
}
650

651
int32_t setIntervalOutputBuf(void* pState, STimeWindow* win, SRowBuffPos** pResult, int64_t groupId,
10,327,601✔
652
                             SqlFunctionCtx* pCtx, int32_t numOfOutput, int32_t* rowEntryInfoOffset,
653
                             SAggSupporter* pAggSup, SStateStore* pStore, int32_t* pWinCode) {
654
  int32_t code = TSDB_CODE_SUCCESS;
10,327,601✔
655
  int32_t lino = 0;
10,327,601✔
656
  SWinKey key = {.ts = win->skey, .groupId = groupId};
10,327,601✔
657
  char*   value = NULL;
10,327,601✔
658
  int32_t size = pAggSup->resultRowSize;
10,327,601✔
659

660
  code = pStore->streamStateAddIfNotExist(pState, &key, (void**)&value, &size, pWinCode);
10,327,601✔
661
  QUERY_CHECK_CODE(code, lino, _end);
10,328,494!
662

663
  *pResult = (SRowBuffPos*)value;
10,328,494✔
664
  SResultRow* res = (SResultRow*)((*pResult)->pRowBuff);
10,328,494✔
665

666
  // set time window for current result
667
  res->win = (*win);
10,328,494✔
668
  code = setResultRowInitCtx(res, pCtx, numOfOutput, rowEntryInfoOffset);
10,328,494✔
669
  QUERY_CHECK_CODE(code, lino, _end);
10,326,424!
670

671
_end:
10,326,424✔
672
  if (code != TSDB_CODE_SUCCESS) {
10,326,424!
673
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
674
  }
675
  return code;
10,326,695✔
676
}
677

678
bool isDeletedStreamWindow(STimeWindow* pWin, uint64_t groupId, void* pState, STimeWindowAggSupp* pTwSup,
5,259,142✔
679
                           SStateStore* pStore) {
680
  if (pTwSup->maxTs != INT64_MIN && pWin->ekey < pTwSup->maxTs - pTwSup->deleteMark) {
5,259,142✔
681
    SWinKey key = {.ts = pWin->skey, .groupId = groupId};
24✔
682
    if (!hasIntervalWindow(pState, &key, pStore)) {
24✔
683
      return true;
14✔
684
    }
685
    return false;
10✔
686
  }
687
  return false;
5,259,118✔
688
}
689

690
int32_t getNexWindowPos(SInterval* pInterval, SDataBlockInfo* pBlockInfo, TSKEY* tsCols, int32_t startPos, TSKEY eKey,
45✔
691
                        STimeWindow* pNextWin) {
692
  int32_t forwardRows =
693
      getNumOfRowsInTimeWindow(pBlockInfo, tsCols, startPos, eKey, binarySearchForKey, NULL, TSDB_ORDER_ASC);
45✔
694
  int32_t prevEndPos = forwardRows - 1 + startPos;
45✔
695
  return getNextQualifiedWindow(pInterval, pNextWin, pBlockInfo, tsCols, prevEndPos, TSDB_ORDER_ASC);
45✔
696
}
697

698
int32_t addPullWindow(SHashObj* pMap, SWinKey* pWinRes, int32_t size) {
230✔
699
  int32_t code = TSDB_CODE_SUCCESS;
230✔
700
  int32_t lino = 0;
230✔
701
  SArray* childIds = taosArrayInit(8, sizeof(int32_t));
230✔
702
  QUERY_CHECK_NULL(childIds, code, lino, _end, terrno);
230!
703
  for (int32_t i = 0; i < size; i++) {
994✔
704
    void* tmp = taosArrayPush(childIds, &i);
764✔
705
    if (!tmp) {
764!
706
      code = terrno;
×
707
      QUERY_CHECK_CODE(code, lino, _end);
×
708
    }
709
  }
710
  code = taosHashPut(pMap, pWinRes, sizeof(SWinKey), &childIds, sizeof(void*));
230✔
711
  QUERY_CHECK_CODE(code, lino, _end);
230!
712
_end:
230✔
713
  if (code != TSDB_CODE_SUCCESS) {
230!
714
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
715
  }
716
  return code;
230✔
717
}
718

719
static void clearStreamIntervalOperator(SStreamIntervalOperatorInfo* pInfo) {
1,893✔
720
  tSimpleHashClear(pInfo->aggSup.pResultRowHashTable);
1,893✔
721
  clearDiskbasedBuf(pInfo->aggSup.pResultBuf);
1,893✔
722
  initResultRowInfo(&pInfo->binfo.resultRowInfo);
1,893✔
723
  pInfo->aggSup.currentPageId = -1;
1,893✔
724
  pInfo->stateStore.streamStateClear(pInfo->pState);
1,893✔
725
}
1,893✔
726

727
static void clearSpecialDataBlock(SSDataBlock* pBlock) {
2,941✔
728
  if (pBlock->info.rows <= 0) {
2,941✔
729
    return;
2,781✔
730
  }
731
  blockDataCleanup(pBlock);
160✔
732
}
733

734
void doBuildPullDataBlock(SArray* array, int32_t* pIndex, SSDataBlock* pBlock) {
2,941✔
735
  int32_t code = TSDB_CODE_SUCCESS;
2,941✔
736
  int32_t lino = 0;
2,941✔
737
  clearSpecialDataBlock(pBlock);
2,941✔
738
  int32_t size = taosArrayGetSize(array);
2,941✔
739
  if (size - (*pIndex) == 0) {
2,941✔
740
    goto _end;
2,781✔
741
  }
742
  code = blockDataEnsureCapacity(pBlock, size - (*pIndex));
160✔
743
  QUERY_CHECK_CODE(code, lino, _end);
160!
744

745
  SColumnInfoData* pStartTs = (SColumnInfoData*)taosArrayGet(pBlock->pDataBlock, START_TS_COLUMN_INDEX);
160✔
746
  SColumnInfoData* pEndTs = (SColumnInfoData*)taosArrayGet(pBlock->pDataBlock, END_TS_COLUMN_INDEX);
160✔
747
  SColumnInfoData* pGroupId = (SColumnInfoData*)taosArrayGet(pBlock->pDataBlock, GROUPID_COLUMN_INDEX);
160✔
748
  SColumnInfoData* pCalStartTs = (SColumnInfoData*)taosArrayGet(pBlock->pDataBlock, CALCULATE_START_TS_COLUMN_INDEX);
160✔
749
  SColumnInfoData* pCalEndTs = (SColumnInfoData*)taosArrayGet(pBlock->pDataBlock, CALCULATE_END_TS_COLUMN_INDEX);
160✔
750
  SColumnInfoData* pTbName = (SColumnInfoData*)taosArrayGet(pBlock->pDataBlock, TABLE_NAME_COLUMN_INDEX);
160✔
751
  SColumnInfoData* pPrimaryKey = NULL;
160✔
752
  if (taosArrayGetSize(pBlock->pDataBlock) > PRIMARY_KEY_COLUMN_INDEX) {
160!
753
    pPrimaryKey = (SColumnInfoData*)taosArrayGet(pBlock->pDataBlock, PRIMARY_KEY_COLUMN_INDEX);
×
754
  }
755
  for (; (*pIndex) < size; (*pIndex)++) {
381✔
756
    SPullWindowInfo* pWin = taosArrayGet(array, (*pIndex));
221✔
757
    code = colDataSetVal(pStartTs, pBlock->info.rows, (const char*)&pWin->window.skey, false);
221✔
758
    QUERY_CHECK_CODE(code, lino, _end);
221!
759

760
    code = colDataSetVal(pEndTs, pBlock->info.rows, (const char*)&pWin->window.ekey, false);
221✔
761
    QUERY_CHECK_CODE(code, lino, _end);
221!
762

763
    code = colDataSetVal(pGroupId, pBlock->info.rows, (const char*)&pWin->groupId, false);
221✔
764
    QUERY_CHECK_CODE(code, lino, _end);
221!
765

766
    code = colDataSetVal(pCalStartTs, pBlock->info.rows, (const char*)&pWin->calWin.skey, false);
221✔
767
    QUERY_CHECK_CODE(code, lino, _end);
221!
768

769
    code = colDataSetVal(pCalEndTs, pBlock->info.rows, (const char*)&pWin->calWin.ekey, false);
221✔
770
    QUERY_CHECK_CODE(code, lino, _end);
221!
771

772
    colDataSetNULL(pTbName, pBlock->info.rows);
221!
773
    if (pPrimaryKey != NULL) {
221!
774
      colDataSetNULL(pPrimaryKey, pBlock->info.rows);
×
775
    }
776

777
    pBlock->info.rows++;
221✔
778
  }
779
  if ((*pIndex) == size) {
160!
780
    *pIndex = 0;
160✔
781
    taosArrayClear(array);
160✔
782
  }
783
  code = blockDataUpdateTsWindow(pBlock, 0);
160✔
784
  QUERY_CHECK_CODE(code, lino, _end);
160!
785

786
_end:
160✔
787
  if (code != TSDB_CODE_SUCCESS) {
2,941!
788
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
789
  }
790
}
2,941✔
791

792
static int32_t processPullOver(SSDataBlock* pBlock, SHashObj* pMap, SHashObj* pFinalMap, SInterval* pInterval,
532✔
793
                               SArray* pPullWins, int32_t numOfCh, SOperatorInfo* pOperator, bool* pBeOver) {
794
  int32_t                      code = TSDB_CODE_SUCCESS;
532✔
795
  int32_t                      lino = 0;
532✔
796
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
532✔
797
  SColumnInfoData*             pStartCol = taosArrayGet(pBlock->pDataBlock, CALCULATE_START_TS_COLUMN_INDEX);
532✔
798
  TSKEY*                       tsData = (TSKEY*)pStartCol->pData;
532✔
799
  SColumnInfoData*             pEndCol = taosArrayGet(pBlock->pDataBlock, CALCULATE_END_TS_COLUMN_INDEX);
532✔
800
  TSKEY*                       tsEndData = (TSKEY*)pEndCol->pData;
532✔
801
  SColumnInfoData*             pGroupCol = taosArrayGet(pBlock->pDataBlock, GROUPID_COLUMN_INDEX);
532✔
802
  uint64_t*                    groupIdData = (uint64_t*)pGroupCol->pData;
532✔
803
  int32_t                      chId = getChildIndex(pBlock);
532✔
804
  bool                         res = false;
532✔
805
  for (int32_t i = 0; i < pBlock->info.rows; i++) {
1,278✔
806
    TSKEY winTs = tsData[i];
746✔
807
    while (winTs <= tsEndData[i]) {
1,510✔
808
      SWinKey winRes = {.ts = winTs, .groupId = groupIdData[i]};
764✔
809
      void*   chIds = taosHashGet(pMap, &winRes, sizeof(SWinKey));
764✔
810
      if (chIds) {
764!
811
        SArray* chArray = *(SArray**)chIds;
764✔
812
        int32_t index = taosArraySearchIdx(chArray, &chId, compareInt32Val, TD_EQ);
764✔
813
        if (index != -1) {
764!
814
          qDebug("===stream===retrive window %" PRId64 " delete child id %d", winRes.ts, chId);
764✔
815
          taosArrayRemove(chArray, index);
764✔
816
          if (taosArrayGetSize(chArray) == 0) {
764✔
817
            // pull data is over
818
            taosArrayDestroy(chArray);
230✔
819
            int32_t tmpRes = taosHashRemove(pMap, &winRes, sizeof(SWinKey));
230✔
820
            qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
230!
821
            res = true;
230✔
822
            qDebug("===stream===retrive pull data over.window %" PRId64, winRes.ts);
230✔
823

824
            void* pFinalCh = taosHashGet(pFinalMap, &winRes, sizeof(SWinKey));
230✔
825
            if (pFinalCh) {
230✔
826
              int32_t tmpRes = taosHashRemove(pFinalMap, &winRes, sizeof(SWinKey));
22✔
827
              qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
22!
828
              doDeleteWindow(pOperator, winRes.ts, winRes.groupId);
22✔
829
              STimeWindow     nextWin = getFinalTimeWindow(winRes.ts, pInterval);
22✔
830
              SPullWindowInfo pull = {.window = nextWin,
22✔
831
                                      .groupId = winRes.groupId,
22✔
832
                                      .calWin.skey = nextWin.skey,
22✔
833
                                      .calWin.ekey = nextWin.skey};
22✔
834
              // add pull data request
835
              qDebug("===stream===prepare final retrive for delete window:%" PRId64 ",groupId:%" PRId64 ", size:%d",
22✔
836
                     winRes.ts, winRes.groupId, numOfCh);
837
              if (IS_MID_INTERVAL_OP(pOperator)) {
22!
838
                SStreamIntervalOperatorInfo* pInfo = (SStreamIntervalOperatorInfo*)pOperator->info;
×
839

840
                void* tmp = taosArrayPush(pInfo->pMidPullDatas, &winRes);
×
841
                if (!tmp) {
×
842
                  code = terrno;
×
843
                  QUERY_CHECK_CODE(code, lino, _end);
×
844
                }
845
              } else if (savePullWindow(&pull, pPullWins) == TSDB_CODE_SUCCESS) {
22!
846
                void* tmp = taosArrayPush(pInfo->pDelWins, &winRes);
22✔
847
                if (!tmp) {
22!
848
                  code = terrno;
×
849
                  QUERY_CHECK_CODE(code, lino, _end);
×
850
                }
851

852
                code = addPullWindow(pMap, &winRes, numOfCh);
22✔
853
                QUERY_CHECK_CODE(code, lino, _end);
22!
854

855
                if (pInfo->destHasPrimaryKey) {
22!
856
                  code = tSimpleHashPut(pInfo->pDeletedMap, &winRes, sizeof(SWinKey), NULL, 0);
×
857
                  QUERY_CHECK_CODE(code, lino, _end);
×
858
                }
859
                qDebug("===stream===prepare final retrive for delete %" PRId64 ", size:%d", winRes.ts, numOfCh);
22✔
860
              }
861
            }
862
          }
863
        }
864
      }
865
      winTs = taosTimeAdd(winTs, pInterval->sliding, pInterval->slidingUnit, pInterval->precision, NULL);
764✔
866
    }
867
  }
868
  if (pBeOver) {
532✔
869
    *pBeOver = res;
12✔
870
  }
871

872
_end:
520✔
873
  if (code != TSDB_CODE_SUCCESS) {
532!
874
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
875
  }
876
  return code;
532✔
877
}
878

879
static int32_t addRetriveWindow(SArray* wins, SStreamIntervalOperatorInfo* pInfo, int32_t childId) {
204✔
880
  int32_t code = TSDB_CODE_SUCCESS;
204✔
881
  int32_t lino = 0;
204✔
882
  int32_t size = taosArrayGetSize(wins);
204✔
883
  for (int32_t i = 0; i < size; i++) {
407✔
884
    SWinKey*    winKey = taosArrayGet(wins, i);
203✔
885
    STimeWindow nextWin = getFinalTimeWindow(winKey->ts, &pInfo->interval);
203✔
886
    void*       chIds = taosHashGet(pInfo->pPullDataMap, winKey, sizeof(SWinKey));
203✔
887
    if (!chIds) {
203✔
888
      SPullWindowInfo pull = {
201✔
889
          .window = nextWin, .groupId = winKey->groupId, .calWin.skey = nextWin.skey, .calWin.ekey = nextWin.skey};
201✔
890
      // add pull data request
891
      if (savePullWindow(&pull, pInfo->pPullWins) == TSDB_CODE_SUCCESS) {
201!
892
        code = addPullWindow(pInfo->pPullDataMap, winKey, pInfo->numOfChild);
201✔
893
        QUERY_CHECK_CODE(code, lino, _end);
201!
894

895
        if (pInfo->destHasPrimaryKey) {
201!
896
          code = tSimpleHashPut(pInfo->pDeletedMap, winKey, sizeof(SWinKey), NULL, 0);
×
897
          QUERY_CHECK_CODE(code, lino, _end);
×
898
        }
899
        qDebug("===stream===prepare retrive for delete %" PRId64 ", size:%d", winKey->ts, pInfo->numOfChild);
201✔
900
      }
901
    } else {
902
      SArray* chArray = *(void**)chIds;
2✔
903
      int32_t index = taosArraySearchIdx(chArray, &childId, compareInt32Val, TD_EQ);
2✔
904
      qDebug("===stream===check final retrive %" PRId64 ",chid:%d", winKey->ts, index);
2!
905
      if (index == -1) {
2!
906
        qDebug("===stream===add final retrive %" PRId64, winKey->ts);
2!
907
        code = taosHashPut(pInfo->pFinalPullDataMap, winKey, sizeof(SWinKey), NULL, 0);
2✔
908
        QUERY_CHECK_CODE(code, lino, _end);
2!
909
      }
910
    }
911
  }
912

913
_end:
204✔
914
  if (code != TSDB_CODE_SUCCESS) {
204!
915
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
916
  }
917
  return code;
204✔
918
}
919

920
static void clearFunctionContext(SExprSupp* pSup) {
2,387✔
921
  for (int32_t i = 0; i < pSup->numOfExprs; i++) {
24,576✔
922
    pSup->pCtx[i].saveHandle.currentPage = -1;
22,189✔
923
  }
924
}
2,387✔
925

926
int32_t getOutputBuf(void* pState, SRowBuffPos* pPos, SResultRow** pResult, SStateStore* pStore) {
9,346,468✔
927
  return pStore->streamStateGetByPos(pState, pPos, (void**)pResult);
9,346,468✔
928
}
929

930
void buildDataBlockFromGroupRes(SOperatorInfo* pOperator, void* pState, SSDataBlock* pBlock, SExprSupp* pSup,
53,047✔
931
                                SGroupResInfo* pGroupResInfo, SArray* pSessionKeys) {
932
  int32_t         code = TSDB_CODE_SUCCESS;
53,047✔
933
  int32_t         lino = 0;
53,047✔
934
  SExecTaskInfo*  pTaskInfo = pOperator->pTaskInfo;
53,047✔
935
  SStorageAPI*    pAPI = &pOperator->pTaskInfo->storageAPI;
53,047✔
936
  SExprInfo*      pExprInfo = pSup->pExprInfo;
53,047✔
937
  int32_t         numOfExprs = pSup->numOfExprs;
53,047✔
938
  int32_t*        rowEntryOffset = pSup->rowEntryInfoOffset;
53,047✔
939
  SqlFunctionCtx* pCtx = pSup->pCtx;
53,047✔
940

941
  int32_t numOfRows = getNumOfTotalRes(pGroupResInfo);
53,047✔
942

943
  for (int32_t i = pGroupResInfo->index; i < numOfRows; i += 1) {
9,352,431✔
944
    SRowBuffPos* pPos = *(SRowBuffPos**)taosArrayGet(pGroupResInfo->pRows, i);
9,346,687✔
945
    SResultRow*  pRow = NULL;
9,346,654✔
946
    code = getOutputBuf(pState, pPos, &pRow, &pAPI->stateStore);
9,346,654✔
947
    QUERY_CHECK_CODE(code, lino, _end);
9,346,266!
948
    uint64_t groupId = ((SWinKey*)pPos->pKey)->groupId;
9,346,266✔
949
    doUpdateNumOfRows(pCtx, pRow, numOfExprs, rowEntryOffset);
9,346,266✔
950
    // no results, continue to check the next one
951
    if (pRow->numOfRows == 0) {
9,345,977!
952
      pGroupResInfo->index += 1;
×
953
      continue;
×
954
    }
955
    if (pBlock->info.id.groupId == 0) {
9,345,977✔
956
      pBlock->info.id.groupId = groupId;
477,053✔
957
      void*   tbname = NULL;
477,053✔
958
      int32_t winCode = TSDB_CODE_SUCCESS;
477,053✔
959
      code = pAPI->stateStore.streamStateGetParName(pTaskInfo->streamInfo.pState, pBlock->info.id.groupId, &tbname,
477,053✔
960
                                                    false, &winCode);
961
      QUERY_CHECK_CODE(code, lino, _end);
477,227!
962
      if (winCode != TSDB_CODE_SUCCESS) {
477,227✔
963
        pBlock->info.parTbName[0] = 0;
473,750✔
964
      } else {
965
        memcpy(pBlock->info.parTbName, tbname, TSDB_TABLE_NAME_LEN);
3,477✔
966
      }
967
      qDebug("%s partName:%s, groupId:%"PRIu64, __FUNCTION__, (char*)tbname, groupId);
477,227✔
968

969
      pAPI->stateStore.streamStateFreeVal(tbname);
477,227✔
970
    } else {
971
      // current value belongs to different group, it can't be packed into one datablock
972
      if (pBlock->info.id.groupId != groupId) {
8,868,924✔
973
        break;
44,839✔
974
      }
975
    }
976

977
    if (pBlock->info.rows + pRow->numOfRows > pBlock->info.capacity) {
9,302,337✔
978
      break;
1,194✔
979
    }
980
    pGroupResInfo->index += 1;
9,301,143✔
981

982
    for (int32_t j = 0; j < numOfExprs; ++j) {
71,611,928✔
983
      int32_t slotId = pExprInfo[j].base.resSchema.slotId;
62,312,544✔
984

985
      pCtx[j].resultInfo = getResultEntryInfo(pRow, j, rowEntryOffset);
62,312,544✔
986

987
      if (pCtx[j].fpSet.finalize) {
62,311,172✔
988
        int32_t tmpRes = pCtx[j].fpSet.finalize(&pCtx[j], pBlock);
41,404,614✔
989
        if (TAOS_FAILED(tmpRes)) {
41,405,083!
990
          qError("%s build result data block error, code %s", GET_TASKID(pTaskInfo), tstrerror(tmpRes));
×
UNCOV
991
          QUERY_CHECK_CODE(code, lino, _end);
×
992
        }
993
      } else if (strcmp(pCtx[j].pExpr->pExpr->_function.functionName, "_select_value") == 0) {
20,906,558✔
994
        // do nothing, todo refactor
995
      } else {
996
        // expand the result into multiple rows. E.g., _wstart, top(k, 20)
997
        // the _wstart needs to copy to 20 following rows, since the results of top-k expands to 20 different rows.
998
        SColumnInfoData* pColInfoData = taosArrayGet(pBlock->pDataBlock, slotId);
20,888,088✔
999
        char*            in = GET_ROWCELL_INTERBUF(pCtx[j].resultInfo);
20,887,956✔
1000
        for (int32_t k = 0; k < pRow->numOfRows; ++k) {
41,776,344✔
1001
          code = colDataSetVal(pColInfoData, pBlock->info.rows + k, in, pCtx[j].resultInfo->isNullRes);
20,888,088✔
1002
          QUERY_CHECK_CODE(code, lino, _end);
20,888,388!
1003
        }
1004
      }
1005
    }
1006

1007
    if (pSessionKeys) {
9,299,384!
1008
      SSessionKey key = {.groupId = groupId, .win = pRow->win};
×
1009
      for (int32_t j = 0; j < pRow->numOfRows; ++j) {
×
1010
        const void* px = taosArrayPush(pSessionKeys, &key);
×
1011
        QUERY_CHECK_NULL(px, code, lino, _end, terrno);
×
1012
      }
1013
    }
1014

1015
    pBlock->info.rows += pRow->numOfRows;
9,299,384✔
1016
  }
1017

1018
  pBlock->info.dataLoad = 1;
50,583✔
1019
  code = blockDataUpdateTsWindow(pBlock, 0);
50,583✔
1020
  QUERY_CHECK_CODE(code, lino, _end);
53,045!
1021

1022
_end:
53,045✔
1023
  if (code != TSDB_CODE_SUCCESS) {
53,045!
1024
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
1025
  }
1026
}
53,045✔
1027

1028
void doBuildStreamIntervalResult(SOperatorInfo* pOperator, void* pState, SSDataBlock* pBlock,
78,666✔
1029
                                 SGroupResInfo* pGroupResInfo, SArray* pSessionKeys) {
1030
  SExecTaskInfo* pTaskInfo = pOperator->pTaskInfo;
78,666✔
1031
  // set output datablock version
1032
  pBlock->info.version = pTaskInfo->version;
78,666✔
1033

1034
  blockDataCleanup(pBlock);
78,666✔
1035
  taosArrayClear(pSessionKeys);
78,667✔
1036
  if (!hasRemainResults(pGroupResInfo)) {
78,668✔
1037
    return;
25,625✔
1038
  }
1039

1040
  // clear the existed group id
1041
  pBlock->info.id.groupId = 0;
53,047✔
1042
  buildDataBlockFromGroupRes(pOperator, pState, pBlock, &pOperator->exprSupp, pGroupResInfo, pSessionKeys);
53,047✔
1043
}
1044

1045
int32_t getNextQualifiedFinalWindow(SInterval* pInterval, STimeWindow* pNext, SDataBlockInfo* pDataBlockInfo,
220,305✔
1046
                                    TSKEY* primaryKeys, int32_t prevPosition) {
1047
  int32_t startPos = prevPosition + 1;
220,305✔
1048
  if (startPos == pDataBlockInfo->rows) {
220,305✔
1049
    startPos = -1;
1,851✔
1050
  } else {
1051
    *pNext = getFinalTimeWindow(primaryKeys[startPos], pInterval);
218,454✔
1052
  }
1053
  return startPos;
220,305✔
1054
}
1055

1056
static int32_t doStreamIntervalAggImpl(SOperatorInfo* pOperator, SSDataBlock* pSDataBlock, uint64_t groupId,
716,287✔
1057
                                       SSHashObj* pUpdatedMap, SSHashObj* pDeletedMap) {
1058
  int32_t                      code = TSDB_CODE_SUCCESS;
716,287✔
1059
  int32_t                      lino = 0;
716,287✔
1060
  SStreamIntervalOperatorInfo* pInfo = (SStreamIntervalOperatorInfo*)pOperator->info;
716,287✔
1061
  pInfo->dataVersion = TMAX(pInfo->dataVersion, pSDataBlock->info.version);
716,287✔
1062

1063
  SResultRowInfo* pResultRowInfo = &(pInfo->binfo.resultRowInfo);
716,287✔
1064
  SExecTaskInfo*  pTaskInfo = pOperator->pTaskInfo;
716,287✔
1065
  SExprSupp*      pSup = &pOperator->exprSupp;
716,287✔
1066
  int32_t         numOfOutput = pSup->numOfExprs;
716,287✔
1067
  int32_t         step = 1;
716,287✔
1068
  TSKEY*          tsCols = NULL;
716,287✔
1069
  SRowBuffPos*    pResPos = NULL;
716,287✔
1070
  SResultRow*     pResult = NULL;
716,287✔
1071
  int32_t         forwardRows = 0;
716,287✔
1072
  int32_t         endRowId = pSDataBlock->info.rows - 1;
716,287✔
1073

1074
  SColumnInfoData* pColDataInfo = taosArrayGet(pSDataBlock->pDataBlock, pInfo->primaryTsIndex);
716,287✔
1075
  tsCols = (int64_t*)pColDataInfo->pData;
716,290✔
1076

1077
  void*            pPkVal = NULL;
716,290✔
1078
  int32_t          pkLen = 0;
716,290✔
1079
  SColumnInfoData* pPkColDataInfo = NULL;
716,290✔
1080
  if (hasSrcPrimaryKeyCol(&pInfo->basic)) {
716,290✔
1081
    pPkColDataInfo = taosArrayGet(pSDataBlock->pDataBlock, pInfo->basic.primaryPkIndex);
151,944✔
1082
  }
1083

1084
  if (pSDataBlock->info.window.skey != tsCols[0] || pSDataBlock->info.window.ekey != tsCols[endRowId]) {
716,290!
1085
    qError("table uid %" PRIu64 " data block timestamp range may not be calculated! minKey %" PRId64 ",maxKey %" PRId64,
×
1086
           pSDataBlock->info.id.uid, pSDataBlock->info.window.skey, pSDataBlock->info.window.ekey);
1087
    code = blockDataUpdateTsWindow(pSDataBlock, pInfo->primaryTsIndex);
×
1088
    QUERY_CHECK_CODE(code, lino, _end);
×
1089

1090
    // timestamp of the data is incorrect
1091
    if (pSDataBlock->info.window.skey <= 0 || pSDataBlock->info.window.ekey <= 0) {
×
1092
      qError("table uid %" PRIu64 " data block timestamp is out of range! minKey %" PRId64 ",maxKey %" PRId64,
×
1093
             pSDataBlock->info.id.uid, pSDataBlock->info.window.skey, pSDataBlock->info.window.ekey);
1094
    }
1095
  }
1096

1097
  int32_t     startPos = 0;
716,292✔
1098
  TSKEY       ts = getStartTsKey(&pSDataBlock->info.window, tsCols);
716,292✔
1099
  STimeWindow nextWin = {0};
716,288✔
1100
  if (IS_FINAL_INTERVAL_OP(pOperator)) {
716,288✔
1101
    nextWin = getFinalTimeWindow(ts, &pInfo->interval);
1,811✔
1102
  } else {
1103
    nextWin = getActiveTimeWindow(pInfo->aggSup.pResultBuf, pResultRowInfo, ts, &pInfo->interval, TSDB_ORDER_ASC);
714,477✔
1104
  }
1105
  while (1) {
9,610,700✔
1106
    bool isClosed = isCloseWindow(&nextWin, &pInfo->twAggSup);
10,326,980✔
1107
    if (hasSrcPrimaryKeyCol(&pInfo->basic) && !IS_FINAL_INTERVAL_OP(pOperator) && pInfo->ignoreExpiredData &&
10,326,871!
1108
        pSDataBlock->info.type != STREAM_PULL_DATA) {
×
1109
      pPkVal = colDataGetData(pPkColDataInfo, startPos);
×
1110
      pkLen = colDataGetRowLength(pPkColDataInfo, startPos);
×
1111
    }
1112

1113
    if ((!IS_FINAL_INTERVAL_OP(pOperator) && pInfo->ignoreExpiredData && pSDataBlock->info.type != STREAM_PULL_DATA &&
10,327,526✔
1114
         checkExpiredData(&pInfo->stateStore, pInfo->pUpdateInfo, &pInfo->twAggSup, pSDataBlock->info.id.uid,
672✔
1115
                          nextWin.ekey, pPkVal, pkLen)) ||
10,326,672✔
1116
        !inSlidingWindow(&pInfo->interval, &nextWin, &pSDataBlock->info)) {
10,326,828✔
1117
      startPos = getNexWindowPos(&pInfo->interval, &pSDataBlock->info, tsCols, startPos, nextWin.ekey, &nextWin);
35✔
1118
      if (startPos < 0) {
45✔
1119
        break;
716,289✔
1120
      }
1121
      qDebug("===stream===ignore expired data, window end ts:%" PRId64 ", maxts - wartermak:%" PRId64, nextWin.ekey,
19!
1122
             pInfo->twAggSup.maxTs - pInfo->twAggSup.waterMark);
1123
      continue;
57✔
1124
    }
1125

1126
    if (IS_FINAL_INTERVAL_OP(pOperator) && pInfo->numOfChild > 0) {
10,326,663!
1127
      bool    ignore = true;
218,993✔
1128
      SWinKey winRes = {
218,993✔
1129
          .ts = nextWin.skey,
218,993✔
1130
          .groupId = groupId,
1131
      };
1132
      void* chIds = taosHashGet(pInfo->pPullDataMap, &winRes, sizeof(SWinKey));
218,993✔
1133
      if (isDeletedStreamWindow(&nextWin, groupId, pInfo->pState, &pInfo->twAggSup, &pInfo->stateStore) && isClosed &&
218,993!
1134
          !chIds) {
1✔
1135
        SPullWindowInfo pull = {
1✔
1136
            .window = nextWin, .groupId = groupId, .calWin.skey = nextWin.skey, .calWin.ekey = nextWin.skey};
1✔
1137
        // add pull data request
1138
        if (savePullWindow(&pull, pInfo->pPullWins) == TSDB_CODE_SUCCESS) {
1!
1139
          code = addPullWindow(pInfo->pPullDataMap, &winRes, pInfo->numOfChild);
1✔
1140
          QUERY_CHECK_CODE(code, lino, _end);
1!
1141

1142
          if (pInfo->destHasPrimaryKey) {
1!
1143
            code = tSimpleHashPut(pInfo->pDeletedMap, &winRes, sizeof(SWinKey), NULL, 0);
×
1144
            QUERY_CHECK_CODE(code, lino, _end);
×
1145
          }
1146
        }
1147
      } else {
1148
        int32_t index = -1;
218,992✔
1149
        SArray* chArray = NULL;
218,992✔
1150
        int32_t chId = 0;
218,992✔
1151
        if (chIds) {
218,992✔
1152
          chArray = *(void**)chIds;
352✔
1153
          chId = getChildIndex(pSDataBlock);
352✔
1154
          index = taosArraySearchIdx(chArray, &chId, compareInt32Val, TD_EQ);
352✔
1155
        }
1156
        if (index == -1 || pSDataBlock->info.type == STREAM_PULL_DATA) {
218,992✔
1157
          ignore = false;
218,863✔
1158
        }
1159
      }
1160

1161
      if (ignore) {
218,993✔
1162
        startPos = getNextQualifiedFinalWindow(&pInfo->interval, &nextWin, &pSDataBlock->info, tsCols, startPos);
130✔
1163
        if (startPos < 0) {
130✔
1164
          break;
92✔
1165
        }
1166
        continue;
38✔
1167
      }
1168
    }
1169

1170
    int32_t winCode = TSDB_CODE_SUCCESS;
10,326,533✔
1171
    code = setIntervalOutputBuf(pInfo->pState, &nextWin, &pResPos, groupId, pSup->pCtx, numOfOutput,
10,326,533✔
1172
                                pSup->rowEntryInfoOffset, &pInfo->aggSup, &pInfo->stateStore, &winCode);
1173
    QUERY_CHECK_CODE(code, lino, _end);
10,325,380!
1174

1175
    if (winCode != TSDB_CODE_SUCCESS && IS_NORMAL_INTERVAL_OP(pOperator) &&
10,325,380✔
1176
        BIT_FLAG_TEST_MASK(pTaskInfo->streamInfo.eventTypes, SNOTIFY_EVENT_WINDOW_OPEN)) {
9,762,020!
1177
      SSessionKey key = {.win = nextWin, .groupId = groupId};
×
1178
      code = addIntervalAggNotifyEvent(SNOTIFY_EVENT_WINDOW_OPEN, &key, &pInfo->basic.notifyEventSup,
×
1179
                                       pTaskInfo->streamInfo.pNotifyEventStat);
1180
      QUERY_CHECK_CODE(code, lino, _end);
×
1181
    }
1182

1183
    pResult = (SResultRow*)pResPos->pRowBuff;
10,325,380✔
1184

1185
    if (IS_FINAL_INTERVAL_OP(pOperator)) {
10,325,380✔
1186
      forwardRows = 1;
218,863✔
1187
    } else {
1188
      forwardRows = getNumOfRowsInTimeWindow(&pSDataBlock->info, tsCols, startPos, nextWin.ekey, binarySearchForKey,
10,106,517✔
1189
                                             NULL, TSDB_ORDER_ASC);
1190
    }
1191

1192
    SWinKey key = {
10,327,598✔
1193
        .ts = pResult->win.skey,
10,327,598✔
1194
        .groupId = groupId,
1195
    };
1196

1197
    if (pInfo->destHasPrimaryKey && winCode == TSDB_CODE_SUCCESS && IS_NORMAL_INTERVAL_OP(pOperator)) {
10,327,598!
1198
      code = tSimpleHashPut(pDeletedMap, &key, sizeof(SWinKey), NULL, 0);
6✔
1199
      QUERY_CHECK_CODE(code, lino, _end);
6!
1200
    }
1201

1202
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_AT_ONCE && pUpdatedMap) {
10,327,598!
1203
      code = saveWinResult(&key, pResPos, pUpdatedMap);
10,318,257✔
1204
      QUERY_CHECK_CODE(code, lino, _end);
10,318,663!
1205
    }
1206

1207
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_WINDOW_CLOSE) {
10,328,004✔
1208
      pResPos->beUpdated = true;
8,508✔
1209
      code = tSimpleHashPut(pInfo->aggSup.pResultRowHashTable, &key, sizeof(SWinKey), &pResPos, POINTER_BYTES);
8,508✔
1210
      QUERY_CHECK_CODE(code, lino, _end);
8,510!
1211
    }
1212

1213
    updateTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &nextWin, 1);
10,328,006✔
1214
    code = applyAggFunctionOnPartialTuples(pTaskInfo, pSup->pCtx, &pInfo->twAggSup.timeWindowData, startPos,
10,327,105✔
1215
                                           forwardRows, pSDataBlock->info.rows, numOfOutput);
10,327,105✔
1216
    QUERY_CHECK_CODE(code, lino, _end);
10,327,554!
1217
    key.ts = nextWin.skey;
10,327,554✔
1218

1219
    if (pInfo->delKey.ts > key.ts) {
10,327,554✔
1220
      pInfo->delKey = key;
1,549✔
1221
    }
1222
    int32_t prevEndPos = (forwardRows - 1) * step + startPos;
10,327,554✔
1223
    if (IS_FINAL_INTERVAL_OP(pOperator)) {
10,327,554✔
1224
      startPos = getNextQualifiedFinalWindow(&pInfo->interval, &nextWin, &pSDataBlock->info, tsCols, prevEndPos);
218,863✔
1225
    } else {
1226
      startPos =
1227
          getNextQualifiedWindow(&pInfo->interval, &nextWin, &pSDataBlock->info, tsCols, prevEndPos, TSDB_ORDER_ASC);
10,108,691✔
1228
    }
1229
    if (startPos < 0) {
10,326,814✔
1230
      break;
716,171✔
1231
    }
1232
  }
1233
_end:
716,289✔
1234
  if (code != TSDB_CODE_SUCCESS) {
716,289!
1235
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
1236
  }
1237
  return code;
716,288✔
1238
}
1239

1240
int winPosCmprImpl(const void* pKey1, const void* pKey2) {
148,849,586✔
1241
  SRowBuffPos* pos1 = *(SRowBuffPos**)pKey1;
148,849,586✔
1242
  SRowBuffPos* pos2 = *(SRowBuffPos**)pKey2;
148,849,586✔
1243
  SWinKey*     pWin1 = (SWinKey*)pos1->pKey;
148,849,586✔
1244
  SWinKey*     pWin2 = (SWinKey*)pos2->pKey;
148,849,586✔
1245

1246
  if (pWin1->groupId > pWin2->groupId) {
148,849,586✔
1247
    return 1;
28,427,591✔
1248
  } else if (pWin1->groupId < pWin2->groupId) {
120,421,995✔
1249
    return -1;
26,986,957✔
1250
  }
1251

1252
  if (pWin1->ts > pWin2->ts) {
93,435,038✔
1253
    return 1;
47,063,865✔
1254
  } else if (pWin1->ts < pWin2->ts) {
46,371,173!
1255
    return -1;
46,436,271✔
1256
  }
1257

1258
  return 0;
×
1259
}
1260

1261
static void resetUnCloseWinInfo(SSHashObj* winMap) {
226✔
1262
  void*   pIte = NULL;
226✔
1263
  int32_t iter = 0;
226✔
1264
  while ((pIte = tSimpleHashIterate(winMap, pIte, &iter)) != NULL) {
514✔
1265
    SRowBuffPos* pPos = *(SRowBuffPos**)pIte;
288✔
1266
    pPos->beUsed = true;
288✔
1267
  }
1268
}
226✔
1269

1270
int32_t encodeSWinKey(void** buf, SWinKey* key) {
58✔
1271
  int32_t tlen = 0;
58✔
1272
  tlen += taosEncodeFixedI64(buf, key->ts);
58✔
1273
  tlen += taosEncodeFixedU64(buf, key->groupId);
58✔
1274
  tlen += taosEncodeFixedI32(buf, key->numInGroup);
58✔
1275
  return tlen;
58✔
1276
}
1277

1278
void* decodeSWinKey(void* buf, SWinKey* key) {
3✔
1279
  buf = taosDecodeFixedI64(buf, &key->ts);
3!
1280
  buf = taosDecodeFixedU64(buf, &key->groupId);
3!
1281
  buf = taosDecodeFixedI32(buf, &key->numInGroup);
3!
1282
  return buf;
3✔
1283
}
1284

1285
int32_t encodeSTimeWindowAggSupp(void** buf, STimeWindowAggSupp* pTwAggSup) {
189✔
1286
  int32_t tlen = 0;
189✔
1287
  tlen += taosEncodeFixedI64(buf, pTwAggSup->minTs);
189✔
1288
  tlen += taosEncodeFixedI64(buf, pTwAggSup->maxTs);
189✔
1289
  return tlen;
189✔
1290
}
1291

1292
void* decodeSTimeWindowAggSupp(void* buf, STimeWindowAggSupp* pTwAggSup) {
12✔
1293
  buf = taosDecodeFixedI64(buf, &pTwAggSup->minTs);
12!
1294
  buf = taosDecodeFixedI64(buf, &pTwAggSup->maxTs);
12!
1295
  return buf;
12✔
1296
}
1297

UNCOV
1298
int32_t encodeSTimeWindow(void** buf, STimeWindow* pWin) {
×
UNCOV
1299
  int32_t tlen = 0;
×
UNCOV
1300
  tlen += taosEncodeFixedI64(buf, pWin->skey);
×
UNCOV
1301
  tlen += taosEncodeFixedI64(buf, pWin->ekey);
×
UNCOV
1302
  return tlen;
×
1303
}
1304

1305
void* decodeSTimeWindow(void* buf, STimeWindow* pWin) {
×
1306
  buf = taosDecodeFixedI64(buf, &pWin->skey);
×
1307
  buf = taosDecodeFixedI64(buf, &pWin->ekey);
×
1308
  return buf;
×
1309
}
1310

1311
int32_t encodeSPullWindowInfo(void** buf, SPullWindowInfo* pPullInfo) {
×
1312
  int32_t tlen = 0;
×
1313
  tlen += encodeSTimeWindow(buf, &pPullInfo->calWin);
×
1314
  tlen += taosEncodeFixedU64(buf, pPullInfo->groupId);
×
1315
  tlen += encodeSTimeWindow(buf, &pPullInfo->window);
×
1316
  return tlen;
×
1317
}
1318

1319
void* decodeSPullWindowInfo(void* buf, SPullWindowInfo* pPullInfo) {
×
1320
  buf = decodeSTimeWindow(buf, &pPullInfo->calWin);
×
1321
  buf = taosDecodeFixedU64(buf, &pPullInfo->groupId);
×
1322
  buf = decodeSTimeWindow(buf, &pPullInfo->window);
×
1323
  return buf;
×
1324
}
1325

1326
int32_t encodeSPullWindowInfoArray(void** buf, SArray* pPullInfos) {
76✔
1327
  int32_t tlen = 0;
76✔
1328
  int32_t size = taosArrayGetSize(pPullInfos);
76✔
1329
  tlen += taosEncodeFixedI32(buf, size);
76✔
1330
  for (int32_t i = 0; i < size; i++) {
76!
1331
    void* pItem = taosArrayGet(pPullInfos, i);
×
1332
    tlen += encodeSPullWindowInfo(buf, pItem);
×
1333
  }
1334
  return tlen;
76✔
1335
}
1336

1337
int32_t decodeSPullWindowInfoArray(void* buf, SArray* pPullInfos, void** ppBuf) {
4✔
1338
  int32_t code = TSDB_CODE_SUCCESS;
4✔
1339
  int32_t lino = 0;
4✔
1340
  int32_t size = 0;
4!
1341
  buf = taosDecodeFixedI32(buf, &size);
4✔
1342
  for (int32_t i = 0; i < size; i++) {
4!
1343
    SPullWindowInfo item = {0};
×
1344
    buf = decodeSPullWindowInfo(buf, &item);
×
1345
    void* tmp = taosArrayPush(pPullInfos, &item);
×
1346
    if (!tmp) {
×
1347
      code = terrno;
×
1348
      QUERY_CHECK_CODE(code, lino, _end);
×
1349
    }
1350
  }
1351
  (*ppBuf) = buf;
4✔
1352

1353
_end:
4✔
1354
  if (code != TSDB_CODE_SUCCESS) {
4!
1355
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
1356
  }
1357
  return code;
4✔
1358
}
1359

1360
int32_t doStreamIntervalEncodeOpState(void** buf, int32_t len, SOperatorInfo* pOperator) {
76✔
1361
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
76✔
1362
  if (!pInfo) {
76!
1363
    return 0;
×
1364
  }
1365

1366
  void* pData = (buf == NULL) ? NULL : *buf;
76✔
1367

1368
  // 1.pResultRowHashTable
1369
  int32_t tlen = 0;
76✔
1370
  int32_t mapSize = tSimpleHashGetSize(pInfo->aggSup.pResultRowHashTable);
76✔
1371
  tlen += taosEncodeFixedI32(buf, mapSize);
76✔
1372
  void*   pIte = NULL;
76✔
1373
  size_t  keyLen = 0;
76✔
1374
  int32_t iter = 0;
76✔
1375
  while ((pIte = tSimpleHashIterate(pInfo->aggSup.pResultRowHashTable, pIte, &iter)) != NULL) {
134✔
1376
    void* key = tSimpleHashGetKey(pIte, &keyLen);
58✔
1377
    tlen += encodeSWinKey(buf, key);
58✔
1378
  }
1379

1380
  // 2.twAggSup
1381
  tlen += encodeSTimeWindowAggSupp(buf, &pInfo->twAggSup);
76✔
1382

1383
  // 3.pPullDataMap
1384
  int32_t size = taosHashGetSize(pInfo->pPullDataMap);
76✔
1385
  tlen += taosEncodeFixedI32(buf, size);
76✔
1386
  pIte = NULL;
76✔
1387
  keyLen = 0;
76✔
1388
  while ((pIte = taosHashIterate(pInfo->pPullDataMap, pIte)) != NULL) {
76!
1389
    void* key = taosHashGetKey(pIte, &keyLen);
×
1390
    tlen += encodeSWinKey(buf, key);
×
1391
    SArray* pArray = *(SArray**)pIte;
×
1392
    int32_t chSize = taosArrayGetSize(pArray);
×
1393
    tlen += taosEncodeFixedI32(buf, chSize);
×
1394
    for (int32_t i = 0; i < chSize; i++) {
×
1395
      void* pChItem = taosArrayGet(pArray, i);
×
1396
      tlen += taosEncodeFixedI32(buf, *(int32_t*)pChItem);
×
1397
    }
1398
  }
1399

1400
  // 4.pPullWins
1401
  tlen += encodeSPullWindowInfoArray(buf, pInfo->pPullWins);
76✔
1402

1403
  // 5.dataVersion
1404
  tlen += taosEncodeFixedI64(buf, pInfo->dataVersion);
76✔
1405

1406
  // 6.basicInfo
1407
  tlen += encodeStreamBasicInfo(buf, &pInfo->basic);
76✔
1408

1409
  // 7.checksum
1410
  if (buf) {
76✔
1411
    uint32_t cksum = taosCalcChecksum(0, pData, len - sizeof(uint32_t));
76!
1412
    tlen += taosEncodeFixedU32(buf, cksum);
38✔
1413
  } else {
1414
    tlen += sizeof(uint32_t);
38✔
1415
  }
1416

1417
  return tlen;
76✔
1418
}
1419

1420
void doStreamIntervalDecodeOpState(void* buf, int32_t len, SOperatorInfo* pOperator) {
4✔
1421
  int32_t                      code = TSDB_CODE_SUCCESS;
4✔
1422
  int32_t                      lino = 0;
4✔
1423
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
4✔
1424
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
4✔
1425
  void*                        pDataEnd = POINTER_SHIFT(buf, len);
4✔
1426
  if (!pInfo) {
4!
1427
    code = TSDB_CODE_FAILED;
×
1428
    QUERY_CHECK_CODE(code, lino, _end);
×
1429
  }
1430

1431
  // 7.checksum
1432
  int32_t dataLen = len - sizeof(uint32_t);
4✔
1433
  void*   pCksum = POINTER_SHIFT(buf, dataLen);
4✔
1434
  if (taosCheckChecksum(buf, dataLen, *(uint32_t*)pCksum) != TSDB_CODE_SUCCESS) {
8!
1435
    code = TSDB_CODE_FAILED;
×
1436
    QUERY_CHECK_CODE(code, lino, _end);
×
1437
  }
1438
  pDataEnd = pCksum;
4✔
1439

1440
  // 1.pResultRowHashTable
1441
  int32_t mapSize = 0;
4✔
1442
  buf = taosDecodeFixedI32(buf, &mapSize);
4!
1443
  for (int32_t i = 0; i < mapSize; i++) {
7✔
1444
    SWinKey key = {0};
3✔
1445
    buf = decodeSWinKey(buf, &key);
3✔
1446
    SRowBuffPos* pPos = NULL;
3✔
1447
    int32_t      resSize = pInfo->aggSup.resultRowSize;
3✔
1448
    int32_t      winCode = TSDB_CODE_SUCCESS;
3✔
1449
    code = pInfo->stateStore.streamStateAddIfNotExist(pInfo->pState, &key, (void**)&pPos, &resSize, &winCode);
3✔
1450
    QUERY_CHECK_CODE(code, lino, _end);
3!
1451
    QUERY_CHECK_CONDITION((winCode == TSDB_CODE_SUCCESS), code, lino, _end, TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR);
3!
1452

1453
    code = tSimpleHashPut(pInfo->aggSup.pResultRowHashTable, &key, sizeof(SWinKey), &pPos, POINTER_BYTES);
3✔
1454
    QUERY_CHECK_CODE(code, lino, _end);
3!
1455
  }
1456

1457
  // 2.twAggSup
1458
  buf = decodeSTimeWindowAggSupp(buf, &pInfo->twAggSup);
4✔
1459

1460
  // 3.pPullDataMap
1461
  int32_t size = 0;
4✔
1462
  buf = taosDecodeFixedI32(buf, &size);
4!
1463
  for (int32_t i = 0; i < size; i++) {
4!
1464
    SWinKey key = {0};
×
1465
    SArray* pArray = taosArrayInit(0, sizeof(int32_t));
×
1466
    if (!pArray) {
×
1467
      code = terrno;
×
1468
      QUERY_CHECK_CODE(code, lino, _end);
×
1469
    }
1470

1471
    buf = decodeSWinKey(buf, &key);
×
1472
    int32_t chSize = 0;
×
1473
    buf = taosDecodeFixedI32(buf, &chSize);
×
1474
    for (int32_t i = 0; i < chSize; i++) {
×
1475
      int32_t chId = 0;
×
1476
      buf = taosDecodeFixedI32(buf, &chId);
×
1477
      void* tmp = taosArrayPush(pArray, &chId);
×
1478
      if (!tmp) {
×
1479
        code = terrno;
×
1480
        QUERY_CHECK_CODE(code, lino, _end);
×
1481
      }
1482
    }
1483
    code = taosHashPut(pInfo->pPullDataMap, &key, sizeof(SWinKey), &pArray, POINTER_BYTES);
×
1484
    QUERY_CHECK_CODE(code, lino, _end);
×
1485
  }
1486

1487
  // 4.pPullWins
1488
  code = decodeSPullWindowInfoArray(buf, pInfo->pPullWins, &buf);
4✔
1489
  QUERY_CHECK_CODE(code, lino, _end);
4!
1490

1491
  // 5.dataVersion
1492
  buf = taosDecodeFixedI64(buf, &pInfo->dataVersion);
4!
1493

1494
  // 6.basicInfo
1495
  if (buf < pDataEnd) {
4!
1496
    code = decodeStreamBasicInfo(&buf, &pInfo->basic);
4✔
1497
    QUERY_CHECK_CODE(code, lino, _end);
4!
1498
  }
1499

1500
_end:
4✔
1501
  if (code != TSDB_CODE_SUCCESS) {
4!
1502
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
1503
  }
1504
}
4✔
1505

1506
void doStreamIntervalSaveCheckpoint(SOperatorInfo* pOperator) {
790✔
1507
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
790✔
1508
  if (needSaveStreamOperatorInfo(&pInfo->basic)) {
790✔
1509
    int32_t len = doStreamIntervalEncodeOpState(NULL, 0, pOperator);
38✔
1510
    void*   buf = taosMemoryCalloc(1, len);
38!
1511
    if (!buf) {
38!
1512
      qError("%s failed at line %d since %s", __func__, __LINE__, tstrerror(terrno));
×
1513
      return;
×
1514
    }
1515
    void* pBuf = buf;
38✔
1516
    len = doStreamIntervalEncodeOpState(&pBuf, len, pOperator);
38✔
1517
    pInfo->stateStore.streamStateSaveInfo(pInfo->pState, STREAM_INTERVAL_OP_CHECKPOINT_NAME,
38✔
1518
                                          strlen(STREAM_INTERVAL_OP_CHECKPOINT_NAME), buf, len);
1519
    taosMemoryFree(buf);
38!
1520
    saveStreamOperatorStateComplete(&pInfo->basic);
38✔
1521
  }
1522
}
1523

1524
int32_t copyIntervalDeleteKey(SSHashObj* pMap, SArray* pWins) {
63✔
1525
  int32_t code = TSDB_CODE_SUCCESS;
63✔
1526
  int32_t lino = 0;
63✔
1527
  void*   pIte = NULL;
63✔
1528
  int32_t iter = 0;
63✔
1529
  while ((pIte = tSimpleHashIterate(pMap, pIte, &iter)) != NULL) {
84✔
1530
    void* pKey = tSimpleHashGetKey(pIte, NULL);
21✔
1531
    void* tmp = taosArrayPush(pWins, pKey);
21✔
1532
    if (!tmp) {
21!
1533
      code = terrno;
×
1534
      QUERY_CHECK_CODE(code, lino, _end);
×
1535
    }
1536
  }
1537
  tSimpleHashClear(pMap);
63✔
1538

1539
_end:
63✔
1540
  if (code != TSDB_CODE_SUCCESS) {
63!
1541
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
1542
  }
1543
  return code;
63✔
1544
}
1545

1546
static int32_t buildIntervalResult(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
77,065✔
1547
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
77,065✔
1548
  int32_t                      code = TSDB_CODE_SUCCESS;
77,065✔
1549
  int32_t                      lino = 0;
77,065✔
1550
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
77,065✔
1551
  uint16_t                     opType = pOperator->operatorType;
77,065✔
1552
  SStreamNotifyEventSupp*      pNotifySup = &pInfo->basic.notifyEventSup;
77,065✔
1553
  STaskNotifyEventStat*        pNotifyEventStat = pTaskInfo->streamInfo.pNotifyEventStat;
77,065✔
1554
  bool                         addNotifyEvent = false;
77,065✔
1555

1556
  // check if query task is closed or not
1557
  if (isTaskKilled(pTaskInfo)) {
77,065✔
1558
    (*ppRes) = NULL;
2✔
1559
    return code;
2✔
1560
  }
1561

1562
  addNotifyEvent = IS_NORMAL_INTERVAL_OP(pOperator) &&
142,061✔
1563
                   BIT_FLAG_TEST_MASK(pTaskInfo->streamInfo.eventTypes, SNOTIFY_EVENT_WINDOW_CLOSE);
64,997!
1564
  if (IS_FINAL_INTERVAL_OP(pOperator)) {
77,064✔
1565
    doBuildPullDataBlock(pInfo->pPullWins, &pInfo->pullIndex, pInfo->pPullDataRes);
2,941✔
1566
    if (pInfo->pPullDataRes->info.rows != 0) {
2,941✔
1567
      // process the rest of the data
1568
      printDataBlock(pInfo->pPullDataRes, getStreamOpName(opType), GET_TASKID(pTaskInfo));
160✔
1569
      (*ppRes) = pInfo->pPullDataRes;
160✔
1570
      return code;
160✔
1571
    }
1572
  }
1573

1574
  doBuildDeleteResult(pTaskInfo, pInfo->pDelWins, &pInfo->delIndex, pInfo->pDelRes);
76,904✔
1575
  if (pInfo->pDelRes->info.rows != 0) {
76,899✔
1576
    // process the rest of the data
1577
    printDataBlock(pInfo->pDelRes, getStreamOpName(opType), GET_TASKID(pTaskInfo));
429✔
1578
    if (addNotifyEvent) {
429!
1579
      code = addAggDeleteNotifyEvent(pInfo->pDelRes, pNotifySup, pNotifyEventStat);
×
1580
      QUERY_CHECK_CODE(code, lino, _end);
×
1581
    }
1582
    (*ppRes) = pInfo->pDelRes;
429✔
1583
    return code;
429✔
1584
  }
1585

1586
  doBuildStreamIntervalResult(pOperator, pInfo->pState, pInfo->binfo.pRes, &pInfo->groupResInfo,
76,470!
1587
                              addNotifyEvent ? pNotifySup->pSessionKeys : NULL);
1588
  if (pInfo->binfo.pRes->info.rows != 0) {
76,471✔
1589
    printDataBlock(pInfo->binfo.pRes, getStreamOpName(opType), GET_TASKID(pTaskInfo));
52,836✔
1590
    if (addNotifyEvent) {
52,836!
1591
      code = addAggResultNotifyEvent(pInfo->binfo.pRes, pNotifySup->pSessionKeys,
×
1592
                                     pTaskInfo->streamInfo.notifyResultSchema, pNotifySup, pNotifyEventStat);
×
1593
      QUERY_CHECK_CODE(code, lino, _end);
×
1594
    }
1595
    (*ppRes) = pInfo->binfo.pRes;
52,836✔
1596
    return code;
52,836✔
1597
  }
1598

1599
  code = buildNotifyEventBlock(pTaskInfo, pNotifySup, pNotifyEventStat);
23,635✔
1600
  QUERY_CHECK_CODE(code, lino, _end);
23,632!
1601
  if (pNotifySup->pEventBlock && pNotifySup->pEventBlock->info.rows > 0) {
23,632!
1602
    printDataBlock(pNotifySup->pEventBlock, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
1603
    (*ppRes) = pNotifySup->pEventBlock;
×
1604
    return code;
×
1605
  }
1606

1607
  code = removeOutdatedNotifyEvents(&pInfo->twAggSup, pNotifySup, pNotifyEventStat);
23,632✔
1608
  QUERY_CHECK_CODE(code, lino, _end);
23,630!
1609

1610
_end:
23,630✔
1611
  if (code != TSDB_CODE_SUCCESS) {
23,630!
1612
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
1613
  }
1614
  (*ppRes) = NULL;
23,630✔
1615
  return code;
23,630✔
1616
}
1617

1618
int32_t copyUpdateResult(SSHashObj** ppWinUpdated, SArray* pUpdated, __compar_fn_t compar) {
17,934✔
1619
  int32_t code = TSDB_CODE_SUCCESS;
17,934✔
1620
  int32_t lino = 0;
17,934✔
1621
  void*   pIte = NULL;
17,934✔
1622
  int32_t iter = 0;
17,934✔
1623
  while ((pIte = tSimpleHashIterate(*ppWinUpdated, pIte, &iter)) != NULL) {
463,006✔
1624
    void* tmp = taosArrayPush(pUpdated, pIte);
445,072✔
1625
    if (!tmp) {
445,072!
1626
      code = terrno;
×
1627
      QUERY_CHECK_CODE(code, lino, _end);
×
1628
    }
1629
  }
1630
  taosArraySort(pUpdated, compar);
17,932✔
1631
  tSimpleHashCleanup(*ppWinUpdated);
17,937✔
1632
  *ppWinUpdated = NULL;
17,940✔
1633

1634
_end:
17,940✔
1635
  if (code != TSDB_CODE_SUCCESS) {
17,940!
1636
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
1637
  }
1638
  return code;
17,941✔
1639
}
1640

1641
static int32_t doStreamFinalIntervalAggNext(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
11,584✔
1642
  int32_t                      code = TSDB_CODE_SUCCESS;
11,584✔
1643
  int32_t                      lino = 0;
11,584✔
1644
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
11,584✔
1645
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
11,584✔
1646
  SStorageAPI*                 pAPI = &pOperator->pTaskInfo->storageAPI;
11,584✔
1647

1648
  SOperatorInfo* downstream = pOperator->pDownstream[0];
11,584✔
1649
  SExprSupp*     pSup = &pOperator->exprSupp;
11,584✔
1650

1651
  qDebug("stask:%s  %s status: %d", GET_TASKID(pTaskInfo), getStreamOpName(pOperator->operatorType), pOperator->status);
11,584✔
1652

1653
  if (pOperator->status == OP_EXEC_DONE) {
11,585!
1654
    (*ppRes) = NULL;
×
1655
    return code;
×
1656
  } else if (pOperator->status == OP_RES_TO_RETURN) {
11,585✔
1657
    SSDataBlock* resBlock = NULL;
4,085✔
1658
    code = buildIntervalResult(pOperator, &resBlock);
4,085✔
1659
    QUERY_CHECK_CODE(code, lino, _end);
4,085!
1660
    if (resBlock != NULL) {
4,085✔
1661
      (*ppRes) = resBlock;
1,074✔
1662
      return code;
4,085✔
1663
    }
1664

1665
    if (pInfo->recvGetAll) {
3,011✔
1666
      pInfo->recvGetAll = false;
83✔
1667
      resetUnCloseWinInfo(pInfo->aggSup.pResultRowHashTable);
83✔
1668
    }
1669

1670
    if (pInfo->reCkBlock) {
3,011!
1671
      pInfo->reCkBlock = false;
×
1672
      printDataBlock(pInfo->pCheckpointRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
1673
      (*ppRes) = pInfo->pCheckpointRes;
×
1674
      return code;
×
1675
    }
1676

1677
    setStreamOperatorCompleted(pOperator);
3,011✔
1678
    if (!IS_FINAL_INTERVAL_OP(pOperator)) {
3,011✔
1679
      clearFunctionContext(&pOperator->exprSupp);
1,850✔
1680
      // semi interval operator clear disk buffer
1681
      clearStreamIntervalOperator(pInfo);
1,850✔
1682
      qDebug("===stream===clear semi operator");
1,850✔
1683
    }
1684
    (*ppRes) = NULL;
3,011✔
1685
    return code;
3,011✔
1686
  } else {
1687
    if (!IS_FINAL_INTERVAL_OP(pOperator)) {
7,500✔
1688
      SSDataBlock* resBlock = NULL;
5,243✔
1689
      code = buildIntervalResult(pOperator, &resBlock);
5,243✔
1690
      QUERY_CHECK_CODE(code, lino, _end);
5,239!
1691
      if (resBlock != NULL) {
5,239!
1692
        (*ppRes) = resBlock;
×
1693
        return code;
×
1694
      }
1695

1696
      if (pInfo->recvRetrive) {
5,239!
1697
        pInfo->recvRetrive = false;
×
1698
        printDataBlock(pInfo->pMidRetriveRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
1699
        (*ppRes) = pInfo->pMidRetriveRes;
×
1700
        return code;
×
1701
      }
1702
    }
1703
  }
1704

1705
  if (!pInfo->pUpdated) {
7,496✔
1706
    pInfo->pUpdated = taosArrayInit(4096, POINTER_BYTES);
5,510✔
1707
    QUERY_CHECK_NULL(pInfo->pUpdated, code, lino, _end, terrno);
5,514!
1708
  }
1709
  if (!pInfo->pUpdatedMap) {
7,500✔
1710
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
5,514✔
1711
    pInfo->pUpdatedMap = tSimpleHashInit(4096, hashFn);
5,513✔
1712
    QUERY_CHECK_NULL(pInfo->pUpdatedMap, code, lino, _end, terrno);
5,514!
1713
  }
1714

1715
  while (1) {
21,311✔
1716
    if (isTaskKilled(pTaskInfo)) {
28,811!
1717
      qInfo("===stream=== %s task is killed, code %s", GET_TASKID(pTaskInfo), tstrerror(pTaskInfo->code));
×
1718
      (*ppRes) = NULL;
×
1719
      return code;
1,986✔
1720
    }
1721

1722
    SSDataBlock* pBlock = NULL;
28,811✔
1723
    code = downstream->fpSet.getNextFn(downstream, &pBlock);
28,811✔
1724
    QUERY_CHECK_CODE(code, lino, _end);
28,811!
1725

1726
    if (pBlock == NULL) {
28,811✔
1727
      pOperator->status = OP_RES_TO_RETURN;
4,987✔
1728
      qDebug("===stream===return data:%s. recv datablock num:%" PRIu64, getStreamOpName(pOperator->operatorType),
4,987✔
1729
             pInfo->numOfDatapack);
1730
      pInfo->numOfDatapack = 0;
4,988✔
1731
      break;
4,988✔
1732
    }
1733

1734
    pInfo->numOfDatapack++;
23,824✔
1735
    printSpecDataBlock(pBlock, getStreamOpName(pOperator->operatorType), "recv", GET_TASKID(pTaskInfo));
23,824✔
1736
    setStreamOperatorState(&pInfo->basic, pBlock->info.type);
23,822✔
1737

1738
    if (pBlock->info.type == STREAM_NORMAL || pBlock->info.type == STREAM_PULL_DATA) {
23,822✔
1739
      pInfo->binfo.pRes->info.type = pBlock->info.type;
19,041✔
1740
    } else if (pBlock->info.type == STREAM_DELETE_DATA || pBlock->info.type == STREAM_DELETE_RESULT ||
4,781✔
1741
               pBlock->info.type == STREAM_CLEAR) {
4,549✔
1742
      SArray* delWins = taosArrayInit(8, sizeof(SWinKey));
408✔
1743
      QUERY_CHECK_NULL(delWins, code, lino, _end, terrno);
408!
1744
      SHashObj* finalMap = IS_FINAL_INTERVAL_OP(pOperator) ? pInfo->pFinalPullDataMap : NULL;
408✔
1745
      code = doDeleteWindows(pOperator, &pInfo->interval, pBlock, delWins, pInfo->pUpdatedMap, finalMap);
408✔
1746
      QUERY_CHECK_CODE(code, lino, _end);
408!
1747

1748
      if (IS_FINAL_INTERVAL_OP(pOperator)) {
408✔
1749
        int32_t chId = getChildIndex(pBlock);
204✔
1750
        code = addRetriveWindow(delWins, pInfo, chId);
204✔
1751
        QUERY_CHECK_CODE(code, lino, _end);
204!
1752

1753
        if (pBlock->info.type != STREAM_CLEAR) {
204✔
1754
          void* tmp = taosArrayAddAll(pInfo->pDelWins, delWins);
116✔
1755
          if (!tmp && taosArrayGetSize(delWins) > 0) {
116!
1756
            code = TSDB_CODE_OUT_OF_MEMORY;
×
1757
            QUERY_CHECK_CODE(code, lino, _end);
×
1758
          }
1759
        }
1760
        taosArrayDestroy(delWins);
204✔
1761
        continue;
1,524✔
1762
      }
1763
      removeResults(delWins, pInfo->pUpdatedMap);
204✔
1764
      void* tmp = taosArrayAddAll(pInfo->pDelWins, delWins);
204✔
1765
      if (!tmp && taosArrayGetSize(delWins) > 0) {
204!
1766
        code = TSDB_CODE_OUT_OF_MEMORY;
×
1767
        QUERY_CHECK_CODE(code, lino, _end);
×
1768
      }
1769
      taosArrayDestroy(delWins);
204✔
1770

1771
      doBuildDeleteResult(pTaskInfo, pInfo->pDelWins, &pInfo->delIndex, pInfo->pDelRes);
204✔
1772
      if (pInfo->pDelRes->info.rows != 0) {
204!
1773
        // process the rest of the data
1774
        printDataBlock(pInfo->pDelRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
204✔
1775
        if (pBlock->info.type == STREAM_CLEAR) {
204✔
1776
          pInfo->pDelRes->info.type = STREAM_CLEAR;
88✔
1777
        } else {
1778
          pInfo->pDelRes->info.type = STREAM_DELETE_RESULT;
116✔
1779
        }
1780
        (*ppRes) = pInfo->pDelRes;
204✔
1781
        return code;
204✔
1782
      }
1783

1784
      break;
×
1785
    } else if (pBlock->info.type == STREAM_GET_ALL && IS_FINAL_INTERVAL_OP(pOperator)) {
4,373!
1786
      pInfo->recvGetAll = true;
83✔
1787
      code = getAllIntervalWindow(pInfo->aggSup.pResultRowHashTable, pInfo->pUpdatedMap);
83✔
1788
      QUERY_CHECK_CODE(code, lino, _end);
83!
1789
      continue;
83✔
1790
    } else if (pBlock->info.type == STREAM_RETRIEVE) {
4,290✔
1791
      if (!IS_FINAL_INTERVAL_OP(pOperator)) {
526!
1792
        pInfo->recvRetrive = true;
526✔
1793
        code = copyDataBlock(pInfo->pMidRetriveRes, pBlock);
526✔
1794
        QUERY_CHECK_CODE(code, lino, _end);
526!
1795

1796
        pInfo->pMidRetriveRes->info.type = STREAM_MID_RETRIEVE;
526✔
1797
        code = doDeleteWindows(pOperator, &pInfo->interval, pBlock, NULL, pInfo->pUpdatedMap, NULL);
526✔
1798
        QUERY_CHECK_CODE(code, lino, _end);
524!
1799
        break;
524✔
1800
      }
1801
      continue;
×
1802
    } else if (pBlock->info.type == STREAM_PULL_OVER && IS_FINAL_INTERVAL_OP(pOperator)) {
3,764!
1803
      code = processPullOver(pBlock, pInfo->pPullDataMap, pInfo->pFinalPullDataMap, &pInfo->interval, pInfo->pPullWins,
520✔
1804
                             pInfo->numOfChild, pOperator, NULL);
1805
      QUERY_CHECK_CODE(code, lino, _end);
520!
1806
      continue;
520✔
1807
    } else if (pBlock->info.type == STREAM_CREATE_CHILD_TABLE) {
3,244✔
1808
      (*ppRes) = pBlock;
1,782✔
1809
      return code;
1,782✔
1810
    } else if (pBlock->info.type == STREAM_CHECKPOINT) {
1,462✔
1811
      pAPI->stateStore.streamStateCommit(pInfo->pState);
191✔
1812
      doStreamIntervalSaveCheckpoint(pOperator);
191✔
1813
      code = copyDataBlock(pInfo->pCheckpointRes, pBlock);
191✔
1814
      QUERY_CHECK_CODE(code, lino, _end);
191!
1815

1816
      continue;
191✔
1817
    } else if (IS_FINAL_INTERVAL_OP(pOperator) && pBlock->info.type == STREAM_MID_RETRIEVE) {
1,271✔
1818
      continue;
526✔
1819
    } else {
1820
      if (pBlock->info.type != STREAM_INVALID) {
745!
1821
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
1822
        QUERY_CHECK_CODE(code, lino, _end);
×
1823
      }
1824
    }
1825

1826
    if (pInfo->scalarSupp.pExprInfo != NULL) {
19,786!
1827
      SExprSupp* pExprSup = &pInfo->scalarSupp;
×
1828
      code = projectApplyFunctions(pExprSup->pExprInfo, pBlock, pBlock, pExprSup->pCtx, pExprSup->numOfExprs, NULL);
×
1829
      QUERY_CHECK_CODE(code, lino, _end);
×
1830
    }
1831
    code = setInputDataBlock(pSup, pBlock, TSDB_ORDER_ASC, MAIN_SCAN, true);
19,786✔
1832
    QUERY_CHECK_CODE(code, lino, _end);
19,787!
1833

1834
    code = doStreamIntervalAggImpl(pOperator, pBlock, pBlock->info.id.groupId, pInfo->pUpdatedMap, pInfo->pDeletedMap);
19,787✔
1835
    if (code == TSDB_CODE_STREAM_INTERNAL_ERROR) {
19,787!
1836
      code = TSDB_CODE_SUCCESS;
×
1837
      pOperator->status = OP_RES_TO_RETURN;
×
1838
      break;
×
1839
    }
1840
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.window.ekey);
19,787✔
1841
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.watermark);
19,787✔
1842
    pInfo->twAggSup.minTs = TMIN(pInfo->twAggSup.minTs, pBlock->info.window.skey);
19,787✔
1843
  }
1844

1845
  if (IS_FINAL_INTERVAL_OP(pOperator) && !pInfo->destHasPrimaryKey) {
5,512✔
1846
    removeDeleteResults(pInfo->pUpdatedMap, pInfo->pDelWins);
1,363✔
1847
  }
1848
  if (IS_FINAL_INTERVAL_OP(pOperator)) {
5,512✔
1849
    code = closeStreamIntervalWindow(pInfo->aggSup.pResultRowHashTable, &pInfo->twAggSup, &pInfo->interval,
1,365✔
1850
                                     pInfo->pPullDataMap, pInfo->pUpdatedMap, pInfo->pDelWins, pOperator);
1851
    QUERY_CHECK_CODE(code, lino, _end);
1,365!
1852

1853
    if (pInfo->destHasPrimaryKey) {
1,365✔
1854
      code = copyIntervalDeleteKey(pInfo->pDeletedMap, pInfo->pDelWins);
2✔
1855
      QUERY_CHECK_CODE(code, lino, _end);
2!
1856
    }
1857
  }
1858
  pInfo->binfo.pRes->info.watermark = pInfo->twAggSup.maxTs;
5,512✔
1859

1860
  code = copyUpdateResult(&pInfo->pUpdatedMap, pInfo->pUpdated, winPosCmprImpl);
5,512✔
1861
  QUERY_CHECK_CODE(code, lino, _end);
5,514!
1862

1863
  initMultiResInfoFromArrayList(&pInfo->groupResInfo, pInfo->pUpdated);
5,514✔
1864
  pInfo->pUpdated = NULL;
5,514✔
1865
  code = blockDataEnsureCapacity(pInfo->binfo.pRes, pOperator->resultInfo.capacity);
5,514✔
1866
  QUERY_CHECK_CODE(code, lino, _end);
5,514!
1867

1868
  SSDataBlock* resBlock = NULL;
5,514✔
1869
  code = buildIntervalResult(pOperator, &resBlock);
5,514✔
1870
  QUERY_CHECK_CODE(code, lino, _end);
5,514!
1871
  if (resBlock != NULL) {
5,514✔
1872
    (*ppRes) = resBlock;
3,011✔
1873
    return code;
3,011✔
1874
  }
1875

1876
  if (pInfo->recvRetrive) {
2,503✔
1877
    pInfo->recvRetrive = false;
526✔
1878
    printDataBlock(pInfo->pMidRetriveRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
526✔
1879
    (*ppRes) = pInfo->pMidRetriveRes;
526✔
1880
    return code;
526✔
1881
  }
1882

1883
_end:
1,977✔
1884
  if (code != TSDB_CODE_SUCCESS) {
1,977!
1885
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
1886
    pTaskInfo->code = code;
×
1887
    T_LONG_JMP(pTaskInfo->env, code);
×
1888
  }
1889
  setStreamOperatorCompleted(pOperator);
1,977✔
1890
  (*ppRes) = NULL;
1,977✔
1891
  return code;
1,977✔
1892
}
1893

1894
int64_t getDeleteMark(SWindowPhysiNode* pWinPhyNode, int64_t interval) {
4,740✔
1895
  if (pWinPhyNode->deleteMark <= 0) {
4,740✔
1896
    return DEAULT_DELETE_MARK;
3,872✔
1897
  }
1898
  int64_t deleteMark = TMAX(pWinPhyNode->deleteMark, pWinPhyNode->watermark);
868✔
1899
  deleteMark = TMAX(deleteMark, interval);
868✔
1900
  return deleteMark;
868✔
1901
}
1902

1903
int64_t getDeleteMarkFromOption(SStreamNodeOption* pOption) {
242✔
1904
  if (pOption->deleteMark <= 0) {
242!
1905
    return DEAULT_DELETE_MARK;
242✔
1906
  }
1907
  int64_t deleteMark = TMAX(pOption->deleteMark, pOption->watermark);
×
1908
  return deleteMark;
×
1909
}
1910

1911
TSKEY compareTs(void* pKey) {
28,736,924✔
1912
  SWinKey* pWinKey = (SWinKey*)pKey;
28,736,924✔
1913
  return pWinKey->ts;
28,736,924✔
1914
}
1915

1916
static int32_t getSelectivityBufSize(SqlFunctionCtx* pCtx) {
56,967✔
1917
  if (pCtx->subsidiaries.rowLen == 0) {
56,967!
1918
    int32_t rowLen = 0;
56,969✔
1919
    for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
57,276✔
1920
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
307✔
1921
      rowLen += pc->pExpr->base.resSchema.bytes;
307✔
1922
    }
1923

1924
    return rowLen + pCtx->subsidiaries.num * sizeof(bool);
56,969✔
1925
  } else {
1926
    return pCtx->subsidiaries.rowLen;
×
1927
  }
1928
}
1929

1930
static int32_t getMaxFunResSize(SExprSupp* pSup, int32_t numOfCols) {
4,985✔
1931
  int32_t size = 0;
4,985✔
1932
  for (int32_t i = 0; i < numOfCols; ++i) {
61,953✔
1933
    int32_t resSize = getSelectivityBufSize(pSup->pCtx + i);
56,968✔
1934
    size = TMAX(size, resSize);
56,968✔
1935
  }
1936
  return size;
4,985✔
1937
}
1938

1939
static void streamIntervalReleaseState(SOperatorInfo* pOperator) {
723✔
1940
  if (pOperator->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_SEMI_INTERVAL &&
723✔
1941
      pOperator->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_MID_INTERVAL) {
589✔
1942
    SStreamIntervalOperatorInfo* pInfo = pOperator->info;
579✔
1943
    int32_t                      resSize = sizeof(TSKEY);
579✔
1944
    pInfo->stateStore.streamStateSaveInfo(pInfo->pState, STREAM_INTERVAL_OP_STATE_NAME,
579✔
1945
                                          strlen(STREAM_INTERVAL_OP_STATE_NAME), &pInfo->twAggSup.maxTs, resSize);
579✔
1946
  }
1947
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
723✔
1948
  SStorageAPI*                 pAPI = &pOperator->pTaskInfo->storageAPI;
723✔
1949
  pAPI->stateStore.streamStateCommit(pInfo->pState);
723✔
1950
  SOperatorInfo* downstream = pOperator->pDownstream[0];
723✔
1951
  if (downstream->fpSet.releaseStreamStateFn) {
723!
1952
    downstream->fpSet.releaseStreamStateFn(downstream);
723✔
1953
  }
1954
}
723✔
1955

1956
void streamIntervalReloadState(SOperatorInfo* pOperator) {
723✔
1957
  int32_t                      code = TSDB_CODE_SUCCESS;
723✔
1958
  int32_t                      lino = 0;
723✔
1959
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
723✔
1960
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
723✔
1961
  if (pOperator->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_SEMI_INTERVAL &&
723✔
1962
      pOperator->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_MID_INTERVAL) {
589✔
1963
    int32_t size = 0;
579✔
1964
    void*   pBuf = NULL;
579✔
1965
    code = pInfo->stateStore.streamStateGetInfo(pInfo->pState, STREAM_INTERVAL_OP_STATE_NAME,
579✔
1966
                                                strlen(STREAM_INTERVAL_OP_STATE_NAME), &pBuf, &size);
1967
    QUERY_CHECK_CODE(code, lino, _end);
579!
1968

1969
    TSKEY ts = *(TSKEY*)pBuf;
579✔
1970
    taosMemoryFree(pBuf);
579!
1971
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, ts);
579✔
1972
    pInfo->stateStore.streamStateReloadInfo(pInfo->pState, ts);
579✔
1973
  }
1974
  SOperatorInfo* downstream = pOperator->pDownstream[0];
723✔
1975
  if (downstream->fpSet.reloadStreamStateFn) {
723!
1976
    downstream->fpSet.reloadStreamStateFn(downstream);
723✔
1977
  }
1978
  reloadFromDownStream(downstream, pInfo);
723✔
1979

1980
_end:
723✔
1981
  if (code != TSDB_CODE_SUCCESS) {
723!
1982
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
1983
  }
1984
}
723✔
1985

1986
int32_t createStreamFinalIntervalOperatorInfo(SOperatorInfo* downstream, SPhysiNode* pPhyNode, SExecTaskInfo* pTaskInfo,
865✔
1987
                                              int32_t numOfChild, SReadHandle* pHandle, SOperatorInfo** pOptrInfo) {
1988
  QRY_PARAM_CHECK(pOptrInfo);
865!
1989

1990
  int32_t                      code = TSDB_CODE_SUCCESS;
865✔
1991
  int32_t                      lino = 0;
865✔
1992
  SIntervalPhysiNode*          pIntervalPhyNode = (SIntervalPhysiNode*)pPhyNode;
865✔
1993
  SStreamIntervalOperatorInfo* pInfo = taosMemoryCalloc(1, sizeof(SStreamIntervalOperatorInfo));
865!
1994
  SOperatorInfo*               pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo));
865!
1995
  if (pInfo == NULL || pOperator == NULL) {
865!
1996
    code = terrno;
×
1997
    QUERY_CHECK_CODE(code, lino, _error);
×
1998
  }
1999

2000
  pOperator->exprSupp.hasWindowOrGroup = true;
865✔
2001
  pOperator->pTaskInfo = pTaskInfo;
865✔
2002
  SStorageAPI* pAPI = &pTaskInfo->storageAPI;
865✔
2003

2004
  pInfo->interval = (SInterval){.interval = pIntervalPhyNode->interval,
865✔
2005
                                .sliding = pIntervalPhyNode->sliding,
865✔
2006
                                .intervalUnit = pIntervalPhyNode->intervalUnit,
865✔
2007
                                .slidingUnit = pIntervalPhyNode->slidingUnit,
865✔
2008
                                .offset = pIntervalPhyNode->offset,
865✔
2009
                                .precision = ((SColumnNode*)pIntervalPhyNode->window.pTspk)->node.resType.precision,
865✔
2010
                                .timeRange = pIntervalPhyNode->timeRange};
865✔
2011
  calcIntervalAutoOffset(&pInfo->interval);
865✔
2012
  pInfo->twAggSup = (STimeWindowAggSupp){
865✔
2013
      .waterMark = pIntervalPhyNode->window.watermark,
865✔
2014
      .calTrigger = pIntervalPhyNode->window.triggerType,
865✔
2015
      .maxTs = INT64_MIN,
2016
      .minTs = INT64_MAX,
2017
      .deleteMark = getDeleteMark(&pIntervalPhyNode->window, pIntervalPhyNode->interval),
865✔
2018
      .deleteMarkSaved = 0,
2019
      .calTriggerSaved = 0,
2020
  };
2021
  pInfo->primaryTsIndex = ((SColumnNode*)pIntervalPhyNode->window.pTspk)->slotId;
865✔
2022
  size_t keyBufSize = sizeof(int64_t) + sizeof(int64_t) + POINTER_BYTES;
865✔
2023
  initResultSizeInfo(&pOperator->resultInfo, 4096);
865✔
2024
  if (pIntervalPhyNode->window.pExprs != NULL) {
865!
2025
    int32_t    numOfScalar = 0;
×
2026
    SExprInfo* pScalarExprInfo = NULL;
×
2027

2028
    code = createExprInfo(pIntervalPhyNode->window.pExprs, NULL, &pScalarExprInfo, &numOfScalar);
×
2029
    QUERY_CHECK_CODE(code, lino, _error);
×
2030

2031
    code = initExprSupp(&pInfo->scalarSupp, pScalarExprInfo, numOfScalar, &pTaskInfo->storageAPI.functionStore);
×
2032
    QUERY_CHECK_CODE(code, lino, _error);
×
2033
  }
2034

2035
  SSDataBlock* pResBlock = createDataBlockFromDescNode(pPhyNode->pOutputDataBlockDesc);
865✔
2036
  QUERY_CHECK_NULL(pResBlock, code, lino, _error, terrno);
865!
2037
  initBasicInfo(&pInfo->binfo, pResBlock);
865✔
2038

2039
  pInfo->pState = taosMemoryCalloc(1, sizeof(SStreamState));
865!
2040
  QUERY_CHECK_NULL(pInfo->pState, code, lino, _error, terrno);
865!
2041
  qInfo("open state %p", pInfo->pState);
865!
2042
  pAPI->stateStore.streamStateCopyBackend(pTaskInfo->streamInfo.pState, pInfo->pState);
865✔
2043
  //*(pInfo->pState) = *(pTaskInfo->streamInfo.pState);
2044

2045
  qInfo("copy state %p to %p", pTaskInfo->streamInfo.pState, pInfo->pState);
865!
2046

2047
  pAPI->stateStore.streamStateSetNumber(pInfo->pState, -1, pInfo->primaryTsIndex);
865✔
2048

2049
  int32_t    numOfCols = 0;
865✔
2050
  SExprInfo* pExprInfo = NULL;
865✔
2051
  code = createExprInfo(pIntervalPhyNode->window.pFuncs, NULL, &pExprInfo, &numOfCols);
865✔
2052
  QUERY_CHECK_CODE(code, lino, _error);
865!
2053

2054
  code = initAggSup(&pOperator->exprSupp, &pInfo->aggSup, pExprInfo, numOfCols, keyBufSize, pTaskInfo->id.str,
865✔
2055
                    pInfo->pState, &pTaskInfo->storageAPI.functionStore);
865✔
2056
  QUERY_CHECK_CODE(code, lino, _error);
865!
2057

2058
  code = initExecTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &pTaskInfo->window);
865✔
2059
  QUERY_CHECK_CODE(code, lino, _error);
864!
2060
  initResultRowInfo(&pInfo->binfo.resultRowInfo);
864✔
2061

2062
  pInfo->numOfChild = numOfChild;
864✔
2063
  pInfo->pPhyNode = NULL;
864✔
2064
  code = nodesCloneNode((SNode*)pPhyNode, (SNode**)&pInfo->pPhyNode);
864✔
2065
  if (TSDB_CODE_SUCCESS != code) {
865!
2066
    goto _error;
×
2067
  }
2068

2069
  pInfo->pPullWins = taosArrayInit(8, sizeof(SPullWindowInfo));
865✔
2070
  QUERY_CHECK_NULL(pInfo->pPullWins, code, lino, _error, terrno);
865!
2071
  pInfo->pullIndex = 0;
865✔
2072
  _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
865✔
2073
  pInfo->pPullDataMap = taosHashInit(64, hashFn, true, HASH_NO_LOCK);
865✔
2074
  pInfo->pFinalPullDataMap = taosHashInit(64, hashFn, true, HASH_NO_LOCK);
865✔
2075

2076
  code = createSpecialDataBlock(STREAM_RETRIEVE, &pInfo->pPullDataRes);
865✔
2077
  QUERY_CHECK_CODE(code, lino, _error);
865!
2078

2079
  pInfo->ignoreExpiredData = pIntervalPhyNode->window.igExpired;
865✔
2080
  pInfo->ignoreExpiredDataSaved = false;
865✔
2081
  code = createSpecialDataBlock(STREAM_DELETE_RESULT, &pInfo->pDelRes);
865✔
2082
  QUERY_CHECK_CODE(code, lino, _error);
865!
2083

2084
  pInfo->delIndex = 0;
865✔
2085
  pInfo->pDelWins = taosArrayInit(4, sizeof(SWinKey));
865✔
2086
  QUERY_CHECK_NULL(pInfo->pDelWins, code, lino, _error, terrno);
865!
2087
  pInfo->delKey.ts = INT64_MAX;
865✔
2088
  pInfo->delKey.groupId = 0;
865✔
2089
  pInfo->numOfDatapack = 0;
865✔
2090
  pInfo->pUpdated = NULL;
865✔
2091
  pInfo->pUpdatedMap = NULL;
865✔
2092
  pInfo->stateStore = pTaskInfo->storageAPI.stateStore;
865✔
2093
  int32_t funResSize = getMaxFunResSize(&pOperator->exprSupp, numOfCols);
865✔
2094
  pInfo->pState->pFileState = NULL;
865✔
2095

2096
  // used for backward compatibility of function's result info
2097
  pInfo->pState->pResultRowStore.resultRowGet = getResultRowFromBuf;
865✔
2098
  pInfo->pState->pResultRowStore.resultRowPut = putResultRowToBuf;
865✔
2099
  pInfo->pState->pExprSupp = &pOperator->exprSupp;
865✔
2100

2101
  code =
2102
      pAPI->stateStore.streamFileStateInit(tsStreamBufferSize, sizeof(SWinKey), pInfo->aggSup.resultRowSize, funResSize,
865✔
2103
                                           compareTs, pInfo->pState, pInfo->twAggSup.deleteMark, GET_TASKID(pTaskInfo),
865✔
2104
                                           pHandle->checkpointId, STREAM_STATE_BUFF_HASH, &pInfo->pState->pFileState);
865✔
2105
  QUERY_CHECK_CODE(code, lino, _error);
865!
2106

2107
  pInfo->dataVersion = 0;
865✔
2108
  pInfo->recvGetAll = false;
865✔
2109
  pInfo->recvPullover = false;
865✔
2110
  pInfo->recvRetrive = false;
865✔
2111

2112
  code = createSpecialDataBlock(STREAM_CHECKPOINT, &pInfo->pCheckpointRes);
865✔
2113
  QUERY_CHECK_CODE(code, lino, _error);
865!
2114
  code = createSpecialDataBlock(STREAM_MID_RETRIEVE, &pInfo->pMidRetriveRes);
865✔
2115
  QUERY_CHECK_CODE(code, lino, _error);
865!
2116
  code = createSpecialDataBlock(STREAM_MID_RETRIEVE, &pInfo->pMidPulloverRes);
865✔
2117
  QUERY_CHECK_CODE(code, lino, _error);
865!
2118

2119
  pInfo->clearState = false;
865✔
2120
  pInfo->pMidPullDatas = taosArrayInit(4, sizeof(SWinKey));
865✔
2121
  QUERY_CHECK_NULL(pInfo->pMidPullDatas, code, lino, _error, terrno);
865!
2122
  pInfo->pDeletedMap = tSimpleHashInit(4096, hashFn);
865✔
2123
  QUERY_CHECK_NULL(pInfo->pDeletedMap, code, lino, _error, terrno);
865!
2124
  pInfo->destHasPrimaryKey = pIntervalPhyNode->window.destHasPrimaryKey;
865✔
2125
  pInfo->pOperator = pOperator;
865✔
2126

2127
  pOperator->operatorType = pPhyNode->type;
865✔
2128
  if (!IS_FINAL_INTERVAL_OP(pOperator) || numOfChild == 0) {
865!
2129
    pInfo->twAggSup.calTrigger = STREAM_TRIGGER_AT_ONCE;
657✔
2130
  }
2131
  pOperator->name = getStreamOpName(pOperator->operatorType);
865✔
2132
  pOperator->blocking = true;
865✔
2133
  pOperator->status = OP_NOT_OPENED;
865✔
2134
  pOperator->info = pInfo;
865✔
2135

2136
  if (pPhyNode->type == QUERY_NODE_PHYSICAL_PLAN_STREAM_MID_INTERVAL) {
865✔
2137
    pOperator->fpSet =
2138
        createOperatorFpSet(NULL, doStreamMidIntervalAggNext, NULL, destroyStreamFinalIntervalOperatorInfo,
22✔
2139
                            optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
2140
  } else {
2141
    pOperator->fpSet =
2142
        createOperatorFpSet(NULL, doStreamFinalIntervalAggNext, NULL, destroyStreamFinalIntervalOperatorInfo,
843✔
2143
                            optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
2144
  }
2145
  setOperatorStreamStateFn(pOperator, streamIntervalReleaseState, streamIntervalReloadState);
865✔
2146

2147
  code = initStreamBasicInfo(&pInfo->basic, pOperator);
865✔
2148
  QUERY_CHECK_CODE(code, lino, _error);
865!
2149

2150
  if (pPhyNode->type == QUERY_NODE_PHYSICAL_PLAN_STREAM_SEMI_INTERVAL ||
865✔
2151
      pPhyNode->type == QUERY_NODE_PHYSICAL_PLAN_STREAM_MID_INTERVAL) {
230✔
2152
    pInfo->basic.primaryPkIndex = -1;
657✔
2153
    code = initIntervalDownStream(downstream, pPhyNode->type, pInfo, &pInfo->basic);
657✔
2154
    QUERY_CHECK_CODE(code, lino, _error);
657!
2155
  }
2156
  code = appendDownstream(pOperator, &downstream, 1);
865✔
2157
  QUERY_CHECK_CODE(code, lino, _error);
865!
2158

2159
  // for stream
2160
  void*   buff = NULL;
865✔
2161
  int32_t len = 0;
865✔
2162
  int32_t res = pAPI->stateStore.streamStateGetInfo(pInfo->pState, STREAM_INTERVAL_OP_CHECKPOINT_NAME,
865✔
2163
                                                    strlen(STREAM_INTERVAL_OP_CHECKPOINT_NAME), &buff, &len);
2164
  if (res == TSDB_CODE_SUCCESS) {
864!
2165
    doStreamIntervalDecodeOpState(buff, len, pOperator);
×
2166
    taosMemoryFree(buff);
×
2167
  }
2168

2169
  *pOptrInfo = pOperator;
864✔
2170
  return TSDB_CODE_SUCCESS;
864✔
2171

2172
_error:
×
2173
  if (pInfo != NULL) destroyStreamFinalIntervalOperatorInfo(pInfo);
×
2174
  destroyOperatorAndDownstreams(pOperator, &downstream, 1);
×
2175
  pTaskInfo->code = code;
×
2176
  return code;
×
2177
}
2178

2179
void destroyStreamAggSupporter(SStreamAggSupporter* pSup) {
2,096✔
2180
  tSimpleHashCleanup(pSup->pResultRows);
2,096✔
2181
  destroyDiskbasedBuf(pSup->pResultBuf);
2,096✔
2182
  blockDataDestroy(pSup->pScanBlock);
2,096✔
2183
  if (pSup->stateStore.streamFileStateDestroy != NULL) {
2,096!
2184
    pSup->stateStore.streamFileStateDestroy(pSup->pState->pFileState);
2,096✔
2185
    pSup->pState->pFileState = NULL;
2,096✔
2186
  }
2187
  taosMemoryFreeClear(pSup->pState);
2,096!
2188
  taosMemoryFreeClear(pSup->pDummyCtx);
2,096!
2189
}
2,096✔
2190

2191
void destroyResultWinInfo(void* pRes) {
×
2192
  SResultWindowInfo* pWinRes = (SResultWindowInfo*)pRes;
×
2193
  destroyFlusedPos(pWinRes->pStatePos);
×
2194
}
×
2195

2196
void clearSessionGroupResInfo(SGroupResInfo* pGroupResInfo) {
1,775✔
2197
  int32_t size = taosArrayGetSize(pGroupResInfo->pRows);
1,775✔
2198
  if (pGroupResInfo->index >= 0 && pGroupResInfo->index < size) {
1,775!
2199
    for (int32_t i = pGroupResInfo->index; i < size; i++) {
×
2200
      SResultWindowInfo* pRes = (SResultWindowInfo*) taosArrayGet(pGroupResInfo->pRows, i);
×
2201
      destroyFlusedPos(pRes->pStatePos);
×
2202
      pRes->pStatePos = NULL;
×
2203
    }
2204
  }
2205

2206
  pGroupResInfo->freeItem = false;
1,775✔
2207
  taosArrayDestroy(pGroupResInfo->pRows);
1,775✔
2208
  pGroupResInfo->pRows = NULL;
1,775✔
2209
  pGroupResInfo->index = 0;
1,775✔
2210
}
1,775✔
2211

2212
void destroyStreamSessionAggOperatorInfo(void* param) {
897✔
2213
  if (param == NULL) {
897!
2214
    return;
×
2215
  }
2216
  SStreamSessionAggOperatorInfo* pInfo = (SStreamSessionAggOperatorInfo*)param;
897✔
2217
  cleanupBasicInfo(&pInfo->binfo);
897✔
2218
  if (pInfo->pOperator) {
897!
2219
    cleanupResultInfoInStream(pInfo->pOperator->pTaskInfo, pInfo->streamAggSup.pState, &pInfo->pOperator->exprSupp,
897✔
2220
                              &pInfo->groupResInfo);
2221
    pInfo->pOperator = NULL;
897✔
2222
  }
2223

2224
  destroyStreamBasicInfo(&pInfo->basic);
897✔
2225
  cleanupExprSupp(&pInfo->scalarSupp);
897✔
2226
  clearSessionGroupResInfo(&pInfo->groupResInfo);
897✔
2227
  taosArrayDestroyEx(pInfo->pUpdated, destroyResultWinInfo);
897✔
2228
  pInfo->pUpdated = NULL;
897✔
2229
  destroyStreamAggSupporter(&pInfo->streamAggSup);
897✔
2230

2231
  if (pInfo->pChildren != NULL) {
897✔
2232
    int32_t size = taosArrayGetSize(pInfo->pChildren);
37✔
2233
    for (int32_t i = 0; i < size; i++) {
158✔
2234
      SOperatorInfo* pChild = taosArrayGetP(pInfo->pChildren, i);
121✔
2235
      destroyOperator(pChild);
121✔
2236
    }
2237
    taosArrayDestroy(pInfo->pChildren);
37✔
2238
  }
2239

2240
  colDataDestroy(&pInfo->twAggSup.timeWindowData);
897✔
2241
  blockDataDestroy(pInfo->pDelRes);
897✔
2242
  blockDataDestroy(pInfo->pWinBlock);
897✔
2243
  tSimpleHashCleanup(pInfo->pStUpdated);
897✔
2244
  tSimpleHashCleanup(pInfo->pStDeleted);
897✔
2245
  cleanupGroupResInfo(&pInfo->groupResInfo);
897✔
2246

2247
  taosArrayDestroy(pInfo->historyWins);
897✔
2248
  blockDataDestroy(pInfo->pCheckpointRes);
897✔
2249
  tSimpleHashCleanup(pInfo->pPkDeleted);
897✔
2250
  destroyNonBlockAggSupptor(&pInfo->nbSup);
897✔
2251

2252
  taosMemoryFreeClear(param);
897!
2253
}
2254

2255
int32_t initBasicInfoEx(SOptrBasicInfo* pBasicInfo, SExprSupp* pSup, SExprInfo* pExprInfo, int32_t numOfCols,
1,774✔
2256
                        SSDataBlock* pResultBlock, SFunctionStateStore* pStore) {
2257
  initBasicInfo(pBasicInfo, pResultBlock);
1,774✔
2258
  int32_t code = initExprSupp(pSup, pExprInfo, numOfCols, pStore);
1,775✔
2259
  if (code != TSDB_CODE_SUCCESS) {
1,774!
2260
    return code;
×
2261
  }
2262

2263
  for (int32_t i = 0; i < numOfCols; ++i) {
28,458✔
2264
    pSup->pCtx[i].saveHandle.pBuf = NULL;
26,684✔
2265
  }
2266

2267
  return TSDB_CODE_SUCCESS;
1,774✔
2268
}
2269

2270
void initDummyFunction(SqlFunctionCtx* pDummy, SqlFunctionCtx* pCtx, int32_t nums) {
2,095✔
2271
  for (int i = 0; i < nums; i++) {
30,193✔
2272
    pDummy[i].functionId = pCtx[i].functionId;
28,098✔
2273
    pDummy[i].isNotNullFunc = pCtx[i].isNotNullFunc;
28,098✔
2274
    pDummy[i].isPseudoFunc = pCtx[i].isPseudoFunc;
28,098✔
2275
    pDummy[i].fpSet.init = pCtx[i].fpSet.init;
28,098✔
2276
  }
2277
}
2,095✔
2278

2279
int32_t initDownStream(SOperatorInfo* downstream, SStreamAggSupporter* pAggSup, uint16_t type, int32_t tsColIndex,
2,290✔
2280
                       STimeWindowAggSupp* pTwSup, struct SSteamOpBasicInfo* pBasic, int64_t recalculateInterval) {
2281
  SExecTaskInfo* pTaskInfo = downstream->pTaskInfo;
2,290✔
2282
  int32_t        code = TSDB_CODE_SUCCESS;
2,290✔
2283
  int32_t        lino = 0;
2,290✔
2284
  if (downstream->operatorType == QUERY_NODE_PHYSICAL_PLAN_STREAM_PARTITION) {
2,290✔
2285
    SStreamPartitionOperatorInfo* pScanInfo = downstream->info;
636✔
2286
    pScanInfo->tsColIndex = tsColIndex;
636✔
2287
    pBasic->primaryPkIndex = pScanInfo->basic.primaryPkIndex;
636✔
2288
  }
2289

2290
  if (downstream->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_SCAN) {
2,290✔
2291
    code = initDownStream(downstream->pDownstream[0], pAggSup, type, tsColIndex, pTwSup, pBasic, recalculateInterval);
636✔
2292
    return code;
636✔
2293
  }
2294
  SStreamScanInfo* pScanInfo = downstream->info;
1,654✔
2295
  pScanInfo->windowSup = (SWindowSupporter){.pStreamAggSup = pAggSup, .gap = pAggSup->gap, .parentType = type};
1,654✔
2296
  pScanInfo->pState = pAggSup->pState;
1,654✔
2297
  if (!pScanInfo->pUpdateInfo) {
1,654✔
2298
    code = pAggSup->stateStore.updateInfoInit(60000, TSDB_TIME_PRECISION_MILLI, pTwSup->waterMark,
1,018✔
2299
                                              pScanInfo->igCheckUpdate, pScanInfo->pkColType, pScanInfo->pkColLen,
1,018✔
2300
                                              &pScanInfo->pUpdateInfo);
1,018✔
2301
    QUERY_CHECK_CODE(code, lino, _end);
1,018!
2302
  }
2303
  pScanInfo->twAggSup = *pTwSup;
1,654✔
2304
  pAggSup->pUpdateInfo = pScanInfo->pUpdateInfo;
1,654✔
2305
  if (!hasSrcPrimaryKeyCol(pBasic)) {
1,654✔
2306
    pBasic->primaryPkIndex = pScanInfo->basic.primaryPkIndex;
1,650✔
2307
  }
2308

2309
  pBasic->pTsDataState = pScanInfo->basic.pTsDataState;
1,654✔
2310

2311
  if (type == QUERY_NODE_PHYSICAL_PLAN_STREAM_CONTINUE_SEMI_SESSION) {
1,654!
2312
    pScanInfo->scanAllTables = true;
×
2313
  }
2314
  pScanInfo->recalculateInterval = recalculateInterval;
1,654✔
2315
  pScanInfo->windowSup.parentType = type;
1,654✔
2316
  pScanInfo->recParam.gap = pAggSup->gap;
1,654✔
2317

2318
_end:
1,654✔
2319
  if (code != TSDB_CODE_SUCCESS) {
1,654!
2320
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
2321
  }
2322
  return code;
1,654✔
2323
}
2324

2325
static TSKEY sesionTs(void* pKey) {
4,570✔
2326
  SSessionKey* pWinKey = (SSessionKey*)pKey;
4,570✔
2327
  return pWinKey->win.skey;
4,570✔
2328
}
2329

2330
int32_t initStreamAggSupporter(SStreamAggSupporter* pSup, SExprSupp* pExpSup, int32_t numOfOutput, int64_t gap,
2,094✔
2331
                               SStreamState* pState, int32_t keySize, int16_t keyType, SStateStore* pStore,
2332
                               SReadHandle* pHandle, STimeWindowAggSupp* pTwAggSup, const char* taskIdStr,
2333
                               SStorageAPI* pApi, int32_t tsIndex, int8_t stateType, int32_t ratio) {
2334
  pSup->resultRowSize = (keySize + getResultRowSize(pExpSup->pCtx, numOfOutput)) * ratio;
2,094✔
2335
  int32_t lino = 0;
2,096✔
2336
  int32_t code = createSpecialDataBlock(STREAM_CLEAR, &pSup->pScanBlock);
2,096✔
2337
  QUERY_CHECK_CODE(code, lino, _end);
2,095!
2338

2339
  pSup->gap = gap;
2,095✔
2340
  pSup->stateKeySize = keySize;
2,095✔
2341
  pSup->stateKeyType = keyType;
2,095✔
2342
  pSup->pDummyCtx = (SqlFunctionCtx*)taosMemoryCalloc(numOfOutput, sizeof(SqlFunctionCtx));
2,095!
2343
  QUERY_CHECK_NULL(pSup->pDummyCtx, code, lino, _end, terrno);
2,096!
2344

2345
  pSup->stateStore = *pStore;
2,096✔
2346
  pSup->pSessionAPI = pApi;
2,096✔
2347

2348
  initDummyFunction(pSup->pDummyCtx, pExpSup->pCtx, numOfOutput);
2,096✔
2349
  pSup->pState = taosMemoryCalloc(1, sizeof(SStreamState));
2,096!
2350
  QUERY_CHECK_NULL(pSup->pState, code, lino, _end, terrno);
2,096!
2351

2352
  *(pSup->pState) = *pState;
2,096✔
2353
  pSup->stateStore.streamStateSetNumber(pSup->pState, -1, tsIndex);
2,096✔
2354
  int32_t funResSize = getMaxFunResSize(pExpSup, numOfOutput);
2,095✔
2355
  if (stateType != STREAM_STATE_BUFF_HASH_SORT) {
2,096✔
2356
    // used for backward compatibility of function's result info
2357
    pSup->pState->pResultRowStore.resultRowGet = getResultRowFromBuf;
1,854✔
2358
    pSup->pState->pResultRowStore.resultRowPut = putResultRowToBuf;
1,854✔
2359
    pSup->pState->pExprSupp = pExpSup;
1,854✔
2360
  }
2361

2362
  if (stateType == STREAM_STATE_BUFF_SORT) {
2,096✔
2363
    pSup->pState->pFileState = NULL;
1,775✔
2364
    code = pSup->stateStore.streamFileStateInit(tsStreamBufferSize, sizeof(SSessionKey), pSup->resultRowSize,
1,775✔
2365
                                                funResSize, sesionTs, pSup->pState, pTwAggSup->deleteMark, taskIdStr,
1,775✔
2366
                                                pHandle->checkpointId, stateType, &pSup->pState->pFileState);
1,775✔
2367
  } else if (stateType == STREAM_STATE_BUFF_HASH_SORT || stateType == STREAM_STATE_BUFF_HASH_SEARCH) {
321!
2368
    pSup->pState->pFileState = NULL;
321✔
2369
    code = pSup->stateStore.streamFileStateInit(tsStreamBufferSize, sizeof(SWinKey), pSup->resultRowSize, funResSize,
321✔
2370
                                                compareTs, pSup->pState, pTwAggSup->deleteMark, taskIdStr,
321✔
2371
                                                pHandle->checkpointId, stateType, &pSup->pState->pFileState);
321✔
2372
  }
2373
  QUERY_CHECK_CODE(code, lino, _end);
2,095!
2374

2375
  _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
2,095✔
2376
  pSup->pResultRows = tSimpleHashInit(32, hashFn);
2,095✔
2377
  QUERY_CHECK_NULL(pSup->pResultRows, code, lino, _end, terrno);
2,095!
2378

2379
  for (int32_t i = 0; i < numOfOutput; ++i) {
30,154✔
2380
    pExpSup->pCtx[i].saveHandle.pState = pSup->pState;
28,059✔
2381
  }
2382

2383
  pSup->pCur = NULL;
2,095✔
2384

2385
_end:
2,095✔
2386
  if (code != TSDB_CODE_SUCCESS) {
2,095!
2387
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
2388
  }
2389
  return code;
2,094✔
2390
}
2391

2392
bool isInTimeWindow(STimeWindow* pWin, TSKEY ts, int64_t gap) {
5,487✔
2393
  if (ts + gap >= pWin->skey && ts - gap <= pWin->ekey) {
5,487✔
2394
    return true;
4,052✔
2395
  }
2396
  return false;
1,435✔
2397
}
2398

2399
bool isInWindow(SResultWindowInfo* pWinInfo, TSKEY ts, int64_t gap) {
4,627✔
2400
  return isInTimeWindow(&pWinInfo->sessionWin.win, ts, gap);
4,627✔
2401
}
2402

2403
void getCurSessionWindow(SStreamAggSupporter* pAggSup, TSKEY startTs, TSKEY endTs, uint64_t groupId,
4,362✔
2404
                         SSessionKey* pKey) {
2405
  pKey->win.skey = startTs;
4,362✔
2406
  pKey->win.ekey = endTs;
4,362✔
2407
  pKey->groupId = groupId;
4,362✔
2408
  int32_t code = pAggSup->stateStore.streamStateSessionGetKeyByRange(pAggSup->pState, pKey, pKey);
4,362✔
2409
  if (code != TSDB_CODE_SUCCESS) {
4,365✔
2410
    SET_SESSION_WIN_KEY_INVALID(pKey);
1,269✔
2411
  }
2412
}
4,365✔
2413

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

2416
bool inWinRange(STimeWindow* range, STimeWindow* cur) {
52,348✔
2417
  if (cur->skey >= range->skey && cur->ekey <= range->ekey) {
52,348!
2418
    return true;
52,365✔
2419
  }
2420
  return false;
×
2421
}
2422

2423
void clearOutputBuf(void* pState, SRowBuffPos* pPos, SStateStore* pAPI) { pAPI->streamStateClearBuff(pState, pPos); }
×
2424

2425
int32_t setSessionOutputBuf(SStreamAggSupporter* pAggSup, TSKEY startTs, TSKEY endTs, uint64_t groupId,
3,189✔
2426
                            SResultWindowInfo* pCurWin, int32_t* pWinCode) {
2427
  int32_t code = TSDB_CODE_SUCCESS;
3,189✔
2428
  int32_t lino = 0;
3,189✔
2429
  pCurWin->sessionWin.groupId = groupId;
3,189✔
2430
  pCurWin->sessionWin.win.skey = startTs;
3,189✔
2431
  pCurWin->sessionWin.win.ekey = endTs;
3,189✔
2432
  int32_t size = pAggSup->resultRowSize;
3,189✔
2433
  code = pAggSup->stateStore.streamStateSessionAddIfNotExist(pAggSup->pState, &pCurWin->sessionWin, pAggSup->gap,
3,189✔
2434
                                                             (void**)&pCurWin->pStatePos, &size, pWinCode);
3,189✔
2435
  QUERY_CHECK_CODE(code, lino, _end);
3,190!
2436

2437
  if (*pWinCode == TSDB_CODE_SUCCESS && !inWinRange(&pAggSup->winRange, &pCurWin->sessionWin.win)) {
3,190!
2438
    *pWinCode = TSDB_CODE_FAILED;
×
2439
    clearOutputBuf(pAggSup->pState, pCurWin->pStatePos, &pAggSup->pSessionAPI->stateStore);
×
2440
  }
2441

2442
  if (*pWinCode == TSDB_CODE_SUCCESS) {
3,190✔
2443
    pCurWin->isOutput = true;
937✔
2444
    if (pCurWin->pStatePos->needFree) {
937✔
2445
      pAggSup->stateStore.streamStateSessionDel(pAggSup->pState, &pCurWin->sessionWin);
133✔
2446
    }
2447
  } else {
2448
    pCurWin->sessionWin.win.skey = startTs;
2,253✔
2449
    pCurWin->sessionWin.win.ekey = endTs;
2,253✔
2450
  }
2451
  qDebug("===stream===set session window buff .start:%" PRId64 ",end:%" PRId64 ",groupid:%" PRIu64,
3,188✔
2452
         pCurWin->sessionWin.win.skey, pCurWin->sessionWin.win.ekey, pCurWin->sessionWin.groupId);
2453
_end:
1,724✔
2454
  if (code != TSDB_CODE_SUCCESS) {
3,189!
2455
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
2456
  }
2457
  return code;
3,189✔
2458
}
2459

2460
void getSessionWinBuf(SStreamAggSupporter* pAggSup, SStreamStateCur* pCur, SResultWindowInfo* pWinInfo,
209✔
2461
                      int32_t* pWinCode) {
2462
  int32_t size = 0;
209✔
2463
  (*pWinCode) = pAggSup->stateStore.streamStateSessionGetKVByCur(pCur, &pWinInfo->sessionWin,
418✔
2464
                                                                 (void**)&pWinInfo->pStatePos, &size);
209✔
2465
  if ((*pWinCode) != TSDB_CODE_SUCCESS) {
209✔
2466
    return;
181✔
2467
  }
2468

2469
  pAggSup->stateStore.streamStateCurNext(pAggSup->pState, pCur);
28✔
2470
}
2471

2472
int32_t saveDeleteInfo(SArray* pWins, SSessionKey key) {
1,154✔
2473
  int32_t code = TSDB_CODE_SUCCESS;
1,154✔
2474
  int32_t lino = 0;
1,154✔
2475
  void*   res = taosArrayPush(pWins, &key);
1,154✔
2476
  if (!res) {
1,154!
2477
    code = terrno;
×
2478
    QUERY_CHECK_CODE(code, lino, _end);
×
2479
  }
2480

2481
_end:
1,154✔
2482
  if (code != TSDB_CODE_SUCCESS) {
1,154!
2483
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
2484
  }
2485
  return code;
1,153✔
2486
}
2487

2488
int32_t saveDeleteRes(SSHashObj* pStDelete, SSessionKey key) {
81✔
2489
  key.win.ekey = key.win.skey;
81✔
2490
  return tSimpleHashPut(pStDelete, &key, sizeof(SSessionKey), NULL, 0);
81✔
2491
}
2492

2493
void releaseOutputBuf(void* pState, SRowBuffPos* pPos, SStateStore* pAPI) {
13,572✔
2494
  pAPI->streamStateReleaseBuf(pState, pPos, false);
13,572✔
2495
}
13,571✔
2496

2497
void removeSessionResult(SStreamAggSupporter* pAggSup, SSHashObj* pHashMap, SSHashObj* pResMap, SSessionKey* pKey) {
88✔
2498
  int32_t     code = TSDB_CODE_SUCCESS;
88✔
2499
  int32_t     lino = 0;
88✔
2500
  SSessionKey key = {0};
88✔
2501
  getSessionHashKey(pKey, &key);
88✔
2502
  void* pVal = tSimpleHashGet(pHashMap, &key, sizeof(SSessionKey));
88✔
2503
  if (pVal) {
88✔
2504
    releaseOutputBuf(pAggSup->pState, *(void**)pVal, &pAggSup->pSessionAPI->stateStore);
4✔
2505
    int32_t tmpRes = tSimpleHashRemove(pHashMap, &key, sizeof(SSessionKey));
4✔
2506
    qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
4!
2507
  }
2508
  int32_t tmpRes = tSimpleHashRemove(pResMap, &key, sizeof(SSessionKey));
88✔
2509
  qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
88✔
2510
}
88✔
2511

2512
void getSessionHashKey(const SSessionKey* pKey, SSessionKey* pHashKey) {
12,788✔
2513
  *pHashKey = *pKey;
12,788✔
2514
  pHashKey->win.ekey = pKey->win.skey;
12,788✔
2515
}
12,788✔
2516

2517
void removeSessionDeleteResults(SSHashObj* pHashMap, SArray* pWins) {
10,346✔
2518
  if (tSimpleHashGetSize(pHashMap) == 0) {
10,346✔
2519
    return;
9,344✔
2520
  }
2521
  int32_t size = taosArrayGetSize(pWins);
1,005✔
2522
  for (int32_t i = 0; i < size; i++) {
2,189✔
2523
    SResultWindowInfo* pWin = taosArrayGet(pWins, i);
1,184✔
2524
    if (!pWin) continue;
1,184!
2525
    SSessionKey key = {0};
1,184✔
2526
    getSessionHashKey(&pWin->sessionWin, &key);
1,184✔
2527
    int32_t tmpRes = tSimpleHashRemove(pHashMap, &key, sizeof(SSessionKey));
1,184✔
2528
    qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
1,184✔
2529
  }
2530
}
2531

2532
void removeSessionResults(SStreamAggSupporter* pAggSup, SSHashObj* pHashMap, SArray* pWins) {
1,083✔
2533
  if (tSimpleHashGetSize(pHashMap) == 0) {
1,083✔
2534
    return;
835✔
2535
  }
2536
  int32_t size = taosArrayGetSize(pWins);
250✔
2537
  for (int32_t i = 0; i < size; i++) {
533✔
2538
    SSessionKey* pWin = taosArrayGet(pWins, i);
282✔
2539
    if (!pWin) continue;
282!
2540
    SSessionKey key = {0};
282✔
2541
    getSessionHashKey(pWin, &key);
282✔
2542
    void* pVal = tSimpleHashGet(pHashMap, &key, sizeof(SSessionKey));
283✔
2543
    if (pVal) {
283✔
2544
      releaseOutputBuf(pAggSup->pState, *(void**)pVal, &pAggSup->pSessionAPI->stateStore);
178✔
2545
      int32_t tmpRes = tSimpleHashRemove(pHashMap, &key, sizeof(SSessionKey));
177✔
2546
      qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
178!
2547
    }
2548
  }
2549
}
2550

2551
int32_t updateSessionWindowInfo(SStreamAggSupporter* pAggSup, SResultWindowInfo* pWinInfo, TSKEY* pStartTs,
3,165✔
2552
                                TSKEY* pEndTs, uint64_t groupId, int32_t rows, int32_t start, int64_t gap,
2553
                                SSHashObj* pResultRows, SSHashObj* pStUpdated, SSHashObj* pStDeleted,
2554
                                int32_t* pWinRos) {
2555
  int32_t code = TSDB_CODE_SUCCESS;
3,165✔
2556
  int32_t lino = 0;
3,165✔
2557
  for (int32_t i = start; i < rows; ++i) {
7,164✔
2558
    if (!isInWindow(pWinInfo, pStartTs[i], gap) && (!pEndTs || !isInWindow(pWinInfo, pEndTs[i], gap))) {
4,094!
2559
      (*pWinRos) = i - start;
96✔
2560
      goto _end;
96✔
2561
    }
2562
    if (pWinInfo->sessionWin.win.skey > pStartTs[i]) {
3,999✔
2563
      if (pStDeleted && pWinInfo->isOutput) {
26!
2564
        code = saveDeleteRes(pStDeleted, pWinInfo->sessionWin);
21✔
2565
        QUERY_CHECK_CODE(code, lino, _end);
21!
2566
      }
2567

2568
      removeSessionResult(pAggSup, pStUpdated, pResultRows, &pWinInfo->sessionWin);
26✔
2569
      pWinInfo->sessionWin.win.skey = pStartTs[i];
26✔
2570
    }
2571
    pWinInfo->sessionWin.win.ekey = TMAX(pWinInfo->sessionWin.win.ekey, pStartTs[i]);
3,999✔
2572
    if (pEndTs) {
3,999!
2573
      pWinInfo->sessionWin.win.ekey = TMAX(pWinInfo->sessionWin.win.ekey, pEndTs[i]);
4,000✔
2574
    }
2575
    memcpy(pWinInfo->pStatePos->pKey, &pWinInfo->sessionWin, sizeof(SSessionKey));
3,999✔
2576
  }
2577
  (*pWinRos) = rows - start;
3,070✔
2578

2579
_end:
3,166✔
2580
  if (code != TSDB_CODE_SUCCESS) {
3,166!
2581
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
2582
  }
2583
  return code;
3,166✔
2584
}
2585

2586
static int32_t initSessionOutputBuf(SResultWindowInfo* pWinInfo, SResultRow** pResult, SqlFunctionCtx* pCtx,
12,353✔
2587
                                    int32_t numOfOutput, int32_t* rowEntryInfoOffset) {
2588
  *pResult = (SResultRow*)pWinInfo->pStatePos->pRowBuff;
12,353✔
2589
  // set time window for current result
2590
  (*pResult)->win = pWinInfo->sessionWin.win;
12,353✔
2591
  return setResultRowInitCtx(*pResult, pCtx, numOfOutput, rowEntryInfoOffset);
12,353✔
2592
}
2593

2594
int32_t doOneWindowAggImpl(SColumnInfoData* pTimeWindowData, SResultWindowInfo* pCurWin, SResultRow** pResult,
12,264✔
2595
                           int32_t startIndex, int32_t winRows, int32_t rows, int32_t numOutput,
2596
                           SOperatorInfo* pOperator, int64_t winDelta) {
2597
  int32_t        code = TSDB_CODE_SUCCESS;
12,264✔
2598
  int32_t        lino = 0;
12,264✔
2599
  SExprSupp*     pSup = &pOperator->exprSupp;
12,264✔
2600
  SExecTaskInfo* pTaskInfo = pOperator->pTaskInfo;
12,264✔
2601
  code = initSessionOutputBuf(pCurWin, pResult, pSup->pCtx, numOutput, pSup->rowEntryInfoOffset);
12,264✔
2602
  QUERY_CHECK_CODE(code, lino, _end);
12,269!
2603

2604
  updateTimeWindowInfo(pTimeWindowData, &pCurWin->sessionWin.win, winDelta);
12,269✔
2605
  code = applyAggFunctionOnPartialTuples(pTaskInfo, pSup->pCtx, pTimeWindowData, startIndex, winRows, rows, numOutput);
12,269✔
2606

2607
_end:
12,271✔
2608
  if (code != TSDB_CODE_SUCCESS) {
12,271!
2609
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
2610
  }
2611
  return code;
12,271✔
2612
}
2613

2614
void doDeleteSessionWindow(SStreamAggSupporter* pAggSup, SSessionKey* pKey) {
1,242✔
2615
  pAggSup->stateStore.streamStateSessionDel(pAggSup->pState, pKey);
1,242✔
2616
  SSessionKey hashKey = {0};
1,233✔
2617
  getSessionHashKey(pKey, &hashKey);
1,233✔
2618
  int32_t tmpRes = tSimpleHashRemove(pAggSup->pResultRows, &hashKey, sizeof(SSessionKey));
1,233✔
2619
  qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
1,239✔
2620
}
1,239✔
2621

2622
void setSessionWinOutputInfo(SSHashObj* pStUpdated, SResultWindowInfo* pWinInfo) {
15,830✔
2623
  void* pVal = tSimpleHashGet(pStUpdated, &pWinInfo->sessionWin, sizeof(SSessionKey));
15,830✔
2624
  if (pVal) {
15,832✔
2625
    SResultWindowInfo* pWin = pVal;
789✔
2626
    pWinInfo->isOutput = pWin->isOutput;
789✔
2627
  }
2628
}
15,832✔
2629

2630
void getNextSessionWinInfo(SStreamAggSupporter* pAggSup, SSHashObj* pStUpdated, SResultWindowInfo* pCurWin,
3,479✔
2631
                           SResultWindowInfo* pNextWin) {
2632
  SStreamStateCur* pCur = pAggSup->stateStore.streamStateSessionSeekKeyNext(pAggSup->pState, &pCurWin->sessionWin);
3,479✔
2633
  pNextWin->isOutput = true;
3,481✔
2634
  setSessionWinOutputInfo(pStUpdated, pNextWin);
3,481✔
2635
  int32_t size = 0;
3,481✔
2636
  pNextWin->sessionWin = pCurWin->sessionWin;
3,481✔
2637
  int32_t code = pAggSup->stateStore.streamStateSessionGetKVByCur(pCur, &pNextWin->sessionWin,
3,481✔
2638
                                                                  (void**)&pNextWin->pStatePos, &size);
3,481✔
2639
  if (code != TSDB_CODE_SUCCESS) {
3,481✔
2640
    SET_SESSION_WIN_INVALID(*pNextWin);
3,043✔
2641
  }
2642
  pAggSup->stateStore.streamStateFreeCur(pCur);
3,481✔
2643
}
3,481✔
2644

2645
int32_t compactTimeWindow(SExprSupp* pSup, SStreamAggSupporter* pAggSup, STimeWindowAggSupp* pTwAggSup,
24✔
2646
                          SExecTaskInfo* pTaskInfo, SResultWindowInfo* pCurWin, SResultWindowInfo* pNextWin,
2647
                          SSHashObj* pStUpdated, SSHashObj* pStDeleted, bool addGap) {
2648
  int32_t     code = TSDB_CODE_SUCCESS;
24✔
2649
  int32_t     lino = 0;
24✔
2650
  SResultRow* pCurResult = NULL;
24✔
2651
  int32_t     numOfOutput = pSup->numOfExprs;
24✔
2652
  code = initSessionOutputBuf(pCurWin, &pCurResult, pSup->pCtx, numOfOutput, pSup->rowEntryInfoOffset);
24✔
2653
  QUERY_CHECK_CODE(code, lino, _end);
24!
2654

2655
  SResultRow* pWinResult = NULL;
24✔
2656
  code = initSessionOutputBuf(pNextWin, &pWinResult, pAggSup->pDummyCtx, numOfOutput, pSup->rowEntryInfoOffset);
24✔
2657
  QUERY_CHECK_CODE(code, lino, _end);
24!
2658

2659
  pCurWin->sessionWin.win.ekey = TMAX(pCurWin->sessionWin.win.ekey, pNextWin->sessionWin.win.ekey);
24✔
2660
  memcpy(pCurWin->pStatePos->pKey, &pCurWin->sessionWin, sizeof(SSessionKey));
24✔
2661

2662
  int64_t winDelta = 0;
24✔
2663
  if (addGap) {
24✔
2664
    winDelta = pAggSup->gap;
20✔
2665
  }
2666
  updateTimeWindowInfo(&pTwAggSup->timeWindowData, &pCurWin->sessionWin.win, winDelta);
24✔
2667
  code = compactFunctions(pSup->pCtx, pAggSup->pDummyCtx, numOfOutput, pTaskInfo, &pTwAggSup->timeWindowData);
24✔
2668
  QUERY_CHECK_CODE(code, lino, _end);
24✔
2669

2670
  int32_t tmpRes = tSimpleHashRemove(pStUpdated, &pNextWin->sessionWin, sizeof(SSessionKey));
22✔
2671
  qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
22✔
2672

2673
  if (pNextWin->isOutput && pStDeleted) {
22!
2674
    qDebug("===stream=== save delete window info %" PRId64 ", %" PRIu64, pNextWin->sessionWin.win.skey,
21!
2675
           pNextWin->sessionWin.groupId);
2676
    code = saveDeleteRes(pStDeleted, pNextWin->sessionWin);
21✔
2677
    QUERY_CHECK_CODE(code, lino, _end);
21!
2678
  }
2679
  removeSessionResult(pAggSup, pStUpdated, pAggSup->pResultRows, &pNextWin->sessionWin);
22✔
2680
  doDeleteSessionWindow(pAggSup, &pNextWin->sessionWin);
22✔
2681
  releaseOutputBuf(pAggSup->pState, pNextWin->pStatePos, &pAggSup->pSessionAPI->stateStore);
22✔
2682

2683
_end:
24✔
2684
  if (code != TSDB_CODE_SUCCESS) {
24✔
2685
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
2!
2686
  }
2687
  return code;
24✔
2688
}
2689

2690
int32_t compactSessionWindow(SOperatorInfo* pOperator, SResultWindowInfo* pCurWin, SSHashObj* pStUpdated,
3,349✔
2691
                             SSHashObj* pStDeleted, bool addGap, int32_t* pWinNum, bool* pIsEnd) {
2692
  int32_t                        code = TSDB_CODE_SUCCESS;
3,349✔
2693
  int32_t                        lino = 0;
3,349✔
2694
  SExprSupp*                     pSup = &pOperator->exprSupp;
3,349✔
2695
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
3,349✔
2696
  SStorageAPI*                   pAPI = &pOperator->pTaskInfo->storageAPI;
3,349✔
2697
  int32_t                        winNum = 0;
3,349✔
2698
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
3,349✔
2699
  SResultRow*                    pCurResult = NULL;
3,349✔
2700
  int32_t                        numOfOutput = pOperator->exprSupp.numOfExprs;
3,349✔
2701
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
3,349✔
2702

2703
  if (pIsEnd != NULL) {
3,349!
2704
    (*pIsEnd) = false;
×
2705
  }
2706
  // Just look for the window behind StartIndex
2707
  while (1) {
18✔
2708
    SResultWindowInfo winInfo = {0};
3,367✔
2709
    getNextSessionWinInfo(pAggSup, pStUpdated, pCurWin, &winInfo);
3,367✔
2710
    if (!IS_VALID_SESSION_WIN(winInfo)) {
3,368✔
2711
      if (pIsEnd != NULL) {
2,934!
2712
        (*pIsEnd) = true;
×
2713
      }
2714
      releaseOutputBuf(pAggSup->pState, winInfo.pStatePos, &pAggSup->pSessionAPI->stateStore);
2,934✔
2715
      break;
2,932✔
2716
    }
2717
    if (!isInWindow(pCurWin, winInfo.sessionWin.win.skey, pAggSup->gap) ||
434✔
2718
        !inWinRange(&pAggSup->winRange, &winInfo.sessionWin.win)) {
20!
2719
      releaseOutputBuf(pAggSup->pState, winInfo.pStatePos, &pAggSup->pSessionAPI->stateStore);
414✔
2720
      break;
414✔
2721
    }
2722
    code =
2723
        compactTimeWindow(pSup, pAggSup, &pInfo->twAggSup, pTaskInfo, pCurWin, &winInfo, pStUpdated, pStDeleted, true);
20✔
2724
    QUERY_CHECK_CODE(code, lino, _end);
20✔
2725
    winNum++;
18✔
2726
  }
2727
  if (pWinNum) {
3,346✔
2728
    (*pWinNum) = winNum;
158✔
2729
  }
2730

2731
_end:
3,188✔
2732
  if (code != TSDB_CODE_SUCCESS) {
3,348✔
2733
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
2!
2734
  }
2735
  return code;
3,348✔
2736
}
2737

2738
static void compactSessionSemiWindow(SOperatorInfo* pOperator, SResultWindowInfo* pCurWin) {
24✔
2739
  SExprSupp*                     pSup = &pOperator->exprSupp;
24✔
2740
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
24✔
2741
  SStorageAPI*                   pAPI = &pOperator->pTaskInfo->storageAPI;
24✔
2742
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
24✔
2743
  SResultRow*                    pCurResult = NULL;
24✔
2744
  int32_t                        numOfOutput = pOperator->exprSupp.numOfExprs;
24✔
2745
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
24✔
2746
  // Just look for the window behind StartIndex
2747
  while (1) {
×
2748
    SResultWindowInfo winInfo = {0};
24✔
2749
    getNextSessionWinInfo(pAggSup, NULL, pCurWin, &winInfo);
24✔
2750
    if (!IS_VALID_SESSION_WIN(winInfo) || !isInWindow(pCurWin, winInfo.sessionWin.win.skey, pAggSup->gap) ||
24!
2751
        !inWinRange(&pAggSup->winRange, &winInfo.sessionWin.win)) {
×
2752
      releaseOutputBuf(pAggSup->pState, winInfo.pStatePos, &pAggSup->pSessionAPI->stateStore);
24✔
2753
      break;
24✔
2754
    }
2755
    pCurWin->sessionWin.win.ekey = TMAX(pCurWin->sessionWin.win.ekey, winInfo.sessionWin.win.ekey);
×
2756
    memcpy(pCurWin->pStatePos->pKey, &pCurWin->sessionWin, sizeof(SSessionKey));
×
2757
    doDeleteSessionWindow(pAggSup, &winInfo.sessionWin);
×
2758
    releaseOutputBuf(pAggSup->pState, winInfo.pStatePos, &pAggSup->pSessionAPI->stateStore);
×
2759
  }
2760
}
24✔
2761

2762
int32_t saveSessionOutputBuf(SStreamAggSupporter* pAggSup, SResultWindowInfo* pWinInfo) {
12,627✔
2763
  qDebug("===stream===try save session result skey:%" PRId64 ", ekey:%" PRId64 ".pos%d", pWinInfo->sessionWin.win.skey,
12,627✔
2764
         pWinInfo->sessionWin.win.ekey, pWinInfo->pStatePos->needFree);
2765
  return pAggSup->stateStore.streamStateSessionPut(pAggSup->pState, &pWinInfo->sessionWin, pWinInfo->pStatePos,
12,627✔
2766
                                                   pAggSup->resultRowSize);
2767
}
2768

2769
static void doStreamSessionAggImpl(SOperatorInfo* pOperator, SSDataBlock* pSDataBlock, SSHashObj* pStUpdated,
3,094✔
2770
                                   SSHashObj* pStDeleted, bool hasEndTs, bool addGap) {
2771
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
3,094✔
2772
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
3,094✔
2773
  int32_t                        numOfOutput = pOperator->exprSupp.numOfExprs;
3,094✔
2774
  uint64_t                       groupId = pSDataBlock->info.id.groupId;
3,094✔
2775
  int32_t                        code = TSDB_CODE_SUCCESS;
3,094✔
2776
  int32_t                        lino = 0;
3,094✔
2777
  SResultRow*                    pResult = NULL;
3,094✔
2778
  int32_t                        rows = pSDataBlock->info.rows;
3,094✔
2779
  int32_t                        winRows = 0;
3,094✔
2780
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
3,094✔
2781

2782
  pInfo->dataVersion = TMAX(pInfo->dataVersion, pSDataBlock->info.version);
3,094✔
2783
  pAggSup->winRange = pTaskInfo->streamInfo.fillHistoryWindow;
3,094✔
2784
  if (pAggSup->winRange.ekey <= 0) {
3,094!
2785
    pAggSup->winRange.ekey = INT64_MAX;
×
2786
  }
2787

2788
  SColumnInfoData* pStartTsCol = taosArrayGet(pSDataBlock->pDataBlock, pInfo->primaryTsIndex);
3,094✔
2789
  TSKEY*           startTsCols = (int64_t*)pStartTsCol->pData;
3,096✔
2790
  SColumnInfoData* pEndTsCol = NULL;
3,096✔
2791
  if (hasEndTs) {
3,096✔
2792
    pEndTsCol = taosArrayGet(pSDataBlock->pDataBlock, pInfo->endTsIndex);
454✔
2793
  } else {
2794
    pEndTsCol = taosArrayGet(pSDataBlock->pDataBlock, pInfo->primaryTsIndex);
2,642✔
2795
  }
2796

2797
  TSKEY* endTsCols = (int64_t*)pEndTsCol->pData;
3,096✔
2798

2799
  void*            pPkVal = NULL;
3,096✔
2800
  int32_t          pkLen = 0;
3,096✔
2801
  SColumnInfoData* pPkColDataInfo = NULL;
3,096✔
2802
  if (hasSrcPrimaryKeyCol(&pInfo->basic)) {
3,096✔
2803
    pPkColDataInfo = taosArrayGet(pSDataBlock->pDataBlock, pInfo->basic.primaryPkIndex);
14✔
2804
  }
2805

2806
  for (int32_t i = 0; i < rows;) {
6,284✔
2807
    if (hasSrcPrimaryKeyCol(&pInfo->basic) && !IS_FINAL_SESSION_OP(pOperator) && pInfo->ignoreExpiredData) {
3,190!
2808
      pPkVal = colDataGetData(pPkColDataInfo, i);
×
2809
      pkLen = colDataGetRowLength(pPkColDataInfo, i);
×
2810
    }
2811
    if (!IS_FINAL_SESSION_OP(pOperator) && pInfo->ignoreExpiredData &&
3,385✔
2812
        checkExpiredData(&pInfo->streamAggSup.stateStore, pInfo->streamAggSup.pUpdateInfo, &pInfo->twAggSup,
196✔
2813
                         pSDataBlock->info.id.uid, endTsCols[i], pPkVal, pkLen)) {
196✔
2814
      i++;
21✔
2815
      continue;
21✔
2816
    }
2817
    SResultWindowInfo winInfo = {0};
3,168✔
2818
    int32_t           winCode = TSDB_CODE_SUCCESS;
3,168✔
2819
    code = setSessionOutputBuf(pAggSup, startTsCols[i], endTsCols[i], groupId, &winInfo, &winCode);
3,168✔
2820
    QUERY_CHECK_CODE(code, lino, _end);
3,171!
2821

2822
    if (winCode != TSDB_CODE_SUCCESS && IS_NORMAL_SESSION_OP(pOperator) &&
3,169✔
2823
        BIT_FLAG_TEST_MASK(pTaskInfo->streamInfo.eventTypes, SNOTIFY_EVENT_WINDOW_OPEN)) {
1,981!
2824
      code = addSessionAggNotifyEvent(SNOTIFY_EVENT_WINDOW_OPEN, &winInfo.sessionWin, &pInfo->basic.notifyEventSup,
×
2825
                                      pTaskInfo->streamInfo.pNotifyEventStat);
2826
      QUERY_CHECK_CODE(code, lino, _end);
×
2827
    }
2828

2829
    // coverity scan error
2830
    if (!winInfo.pStatePos) {
3,169!
2831
      continue;
×
2832
    }
2833
    setSessionWinOutputInfo(pStUpdated, &winInfo);
3,169✔
2834
    code = updateSessionWindowInfo(pAggSup, &winInfo, startTsCols, endTsCols, groupId, rows, i, pAggSup->gap,
3,167✔
2835
                                   pAggSup->pResultRows, pStUpdated, pStDeleted, &winRows);
2836
    QUERY_CHECK_CODE(code, lino, _end);
3,164!
2837

2838
    int64_t winDelta = 0;
3,164✔
2839
    if (addGap) {
3,164✔
2840
      winDelta = pAggSup->gap;
2,557✔
2841
    }
2842
    code = doOneWindowAggImpl(&pInfo->twAggSup.timeWindowData, &winInfo, &pResult, i, winRows, rows, numOfOutput,
3,164✔
2843
                              pOperator, winDelta);
2844
    QUERY_CHECK_CODE(code, lino, _end);
3,170!
2845

2846
    code = compactSessionWindow(pOperator, &winInfo, pStUpdated, pStDeleted, addGap, NULL, NULL);
3,170✔
2847
    QUERY_CHECK_CODE(code, lino, _end);
3,169✔
2848

2849
    code = saveSessionOutputBuf(pAggSup, &winInfo);
3,167✔
2850
    QUERY_CHECK_CODE(code, lino, _end);
3,167!
2851

2852
    if (pInfo->destHasPrimaryKey && winInfo.isOutput && IS_NORMAL_SESSION_OP(pOperator)) {
3,167✔
2853
      code = saveDeleteRes(pInfo->pPkDeleted, winInfo.sessionWin);
5✔
2854
      QUERY_CHECK_CODE(code, lino, _end);
6!
2855
    }
2856
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_AT_ONCE && pStUpdated) {
3,168✔
2857
      code = saveResult(winInfo, pStUpdated);
2,284✔
2858
      QUERY_CHECK_CODE(code, lino, _end);
2,285!
2859
    }
2860
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_WINDOW_CLOSE) {
3,169✔
2861
      winInfo.pStatePos->beUpdated = true;
620✔
2862
      SSessionKey key = {0};
620✔
2863
      getSessionHashKey(&winInfo.sessionWin, &key);
620✔
2864
      code = tSimpleHashPut(pAggSup->pResultRows, &key, sizeof(SSessionKey), &winInfo, sizeof(SResultWindowInfo));
620✔
2865
      QUERY_CHECK_CODE(code, lino, _end);
619!
2866
    }
2867

2868
    i += winRows;
3,168✔
2869
  }
2870

2871
_end:
3,094✔
2872
  if (code != TSDB_CODE_SUCCESS) {
3,096✔
2873
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
2!
2874
  }
2875
}
3,096✔
2876

2877
int32_t doDeleteTimeWindows(SStreamAggSupporter* pAggSup, SSDataBlock* pBlock, SArray* result) {
1,127✔
2878
  int32_t          code = TSDB_CODE_SUCCESS;
1,127✔
2879
  int32_t          lino = 0;
1,127✔
2880
  SColumnInfoData* pStartTsCol = taosArrayGet(pBlock->pDataBlock, START_TS_COLUMN_INDEX);
1,127✔
2881
  TSKEY*           startDatas = (TSKEY*)pStartTsCol->pData;
1,127✔
2882
  SColumnInfoData* pEndTsCol = taosArrayGet(pBlock->pDataBlock, END_TS_COLUMN_INDEX);
1,127✔
2883
  TSKEY*           endDatas = (TSKEY*)pEndTsCol->pData;
1,127✔
2884
  SColumnInfoData* pGroupCol = taosArrayGet(pBlock->pDataBlock, GROUPID_COLUMN_INDEX);
1,127✔
2885
  uint64_t*        gpDatas = (uint64_t*)pGroupCol->pData;
1,128✔
2886
  for (int32_t i = 0; i < pBlock->info.rows; i++) {
2,317✔
2887
    while (1) {
1,167✔
2888
      SSessionKey curWin = {0};
2,356✔
2889
      getCurSessionWindow(pAggSup, startDatas[i], endDatas[i], gpDatas[i], &curWin);
2,356✔
2890
      if (IS_INVALID_SESSION_WIN_KEY(curWin)) {
2,360✔
2891
        break;
1,189✔
2892
      }
2893
      doDeleteSessionWindow(pAggSup, &curWin);
1,171✔
2894
      if (result) {
1,167✔
2895
        code = saveDeleteInfo(result, curWin);
1,124✔
2896
        QUERY_CHECK_CODE(code, lino, _end);
1,124!
2897
      }
2898
    }
2899
  }
2900

2901
_end:
1,128✔
2902
  if (code != TSDB_CODE_SUCCESS) {
1,128!
2903
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
2904
  }
2905
  return code;
1,128✔
2906
}
2907

2908
inline int32_t sessionKeyCompareAsc(const void* pKey1, const void* pKey2) {
6,397✔
2909
  SResultWindowInfo* pWinInfo1 = (SResultWindowInfo*)pKey1;
6,397✔
2910
  SResultWindowInfo* pWinInfo2 = (SResultWindowInfo*)pKey2;
6,397✔
2911
  SSessionKey*       pWin1 = &pWinInfo1->sessionWin;
6,397✔
2912
  SSessionKey*       pWin2 = &pWinInfo2->sessionWin;
6,397✔
2913

2914
  if (pWin1->groupId > pWin2->groupId) {
6,397✔
2915
    return 1;
2,285✔
2916
  } else if (pWin1->groupId < pWin2->groupId) {
4,112✔
2917
    return -1;
1,911✔
2918
  }
2919

2920
  if (pWin1->win.skey > pWin2->win.skey) {
2,201✔
2921
    return 1;
1,203✔
2922
  } else if (pWin1->win.skey < pWin2->win.skey) {
998!
2923
    return -1;
1,001✔
2924
  }
2925

2926
  return 0;
×
2927
}
2928

2929
static int32_t appendToDeleteDataBlock(SOperatorInfo* pOp, SSDataBlock *pBlock, SSessionKey *pKey) {
670✔
2930
  int32_t        code = TSDB_CODE_SUCCESS;
670✔
2931
  int32_t        lino = 0;
670✔
2932
  SExecTaskInfo* pTaskInfo = pOp->pTaskInfo;
670✔
2933

2934
  QUERY_CHECK_NULL(pBlock, code, lino, _end, TSDB_CODE_INVALID_PARA);
670!
2935
  QUERY_CHECK_NULL(pKey, code, lino, _end, TSDB_CODE_INVALID_PARA);
670!
2936

2937
  SColumnInfoData* pStartTsCol = taosArrayGet(pBlock->pDataBlock, START_TS_COLUMN_INDEX);
670✔
2938
  code = colDataSetVal(pStartTsCol, pBlock->info.rows, (const char*)&pKey->win.skey, false);
670✔
2939
  QUERY_CHECK_CODE(code, lino, _end);
670!
2940

2941
  SColumnInfoData* pEndTsCol = taosArrayGet(pBlock->pDataBlock, END_TS_COLUMN_INDEX);
670✔
2942
  code = colDataSetVal(pEndTsCol, pBlock->info.rows, (const char*)&pKey->win.skey, false);
670✔
2943
  QUERY_CHECK_CODE(code, lino, _end);
670!
2944

2945
  SColumnInfoData* pUidCol = taosArrayGet(pBlock->pDataBlock, UID_COLUMN_INDEX);
670✔
2946
  colDataSetNULL(pUidCol, pBlock->info.rows);
670!
2947

2948
  SColumnInfoData* pGpCol = taosArrayGet(pBlock->pDataBlock, GROUPID_COLUMN_INDEX);
670✔
2949
  code = colDataSetVal(pGpCol, pBlock->info.rows, (const char*)&pKey->groupId, false);
670✔
2950
  QUERY_CHECK_CODE(code, lino, _end);
670!
2951

2952
  SColumnInfoData* pCalStCol = taosArrayGet(pBlock->pDataBlock, CALCULATE_START_TS_COLUMN_INDEX);
670✔
2953
  colDataSetNULL(pCalStCol, pBlock->info.rows);
670!
2954

2955
  SColumnInfoData* pCalEdCol = taosArrayGet(pBlock->pDataBlock, CALCULATE_END_TS_COLUMN_INDEX);
670✔
2956
  colDataSetNULL(pCalEdCol, pBlock->info.rows);
670!
2957

2958
  SColumnInfoData* pTableCol = taosArrayGet(pBlock->pDataBlock, TABLE_NAME_COLUMN_INDEX);
670✔
2959
  if (!pTableCol) {
670!
2960
    QUERY_CHECK_CODE(code, lino, _end);
×
2961
  }
2962

2963
  void*        tbname = NULL;
670✔
2964
  int32_t      winCode = TSDB_CODE_SUCCESS;
670✔
2965
  SStorageAPI* pAPI = &pOp->pTaskInfo->storageAPI;
670✔
2966
  code =
2967
      pAPI->stateStore.streamStateGetParName(pOp->pTaskInfo->streamInfo.pState, pKey->groupId, &tbname, false, &winCode);
670✔
2968
  QUERY_CHECK_CODE(code, lino, _end);
670!
2969

2970
  if (winCode != TSDB_CODE_SUCCESS) {
670✔
2971
    colDataSetNULL(pTableCol, pBlock->info.rows);
240!
2972
  } else {
2973
    char parTbName[VARSTR_HEADER_SIZE + TSDB_TABLE_NAME_LEN];
2974
    STR_WITH_MAXSIZE_TO_VARSTR(parTbName, tbname, sizeof(parTbName));
430✔
2975
    code = colDataSetVal(pTableCol, pBlock->info.rows, (const char*)parTbName, false);
430✔
2976
    QUERY_CHECK_CODE(code, lino, _end);
430!
2977
    pAPI->stateStore.streamStateFreeVal(tbname);
430✔
2978
  }
2979
  pBlock->info.rows += 1;
670✔
2980

2981
_end:
670✔
2982
  if (code != TSDB_CODE_SUCCESS) {
670!
2983
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
2984
  }
2985
  return code;
670✔
2986
}
2987

2988
void doBuildDeleteDataBlock(SOperatorInfo* pOp, SSHashObj* pStDeleted, SSDataBlock* pBlock, void** Ite,
17,137✔
2989
                            SGroupResInfo* pGroupResInfo) {
2990
  int32_t        code = TSDB_CODE_SUCCESS;
17,137✔
2991
  int32_t        lino = 0;
17,137✔
2992
  SExecTaskInfo* pTaskInfo = pOp->pTaskInfo;
17,137✔
2993
  int64_t        minWindowSize = getMinWindowSize(pOp);
17,137✔
2994
  int32_t        numOfRows = getNumOfTotalRes(pGroupResInfo);
17,131✔
2995

2996
  blockDataCleanup(pBlock);
17,129✔
2997
  int32_t size = tSimpleHashGetSize(pStDeleted);
17,126✔
2998
  if (minWindowSize > 0) {
17,129✔
2999
    // Add the number of windows that are below the minimum width limit.
3000
    for (int32_t i = pGroupResInfo->delIndex; i < numOfRows; ++i) {
252✔
3001
      SResultWindowInfo* pWinInfo = taosArrayGet(pGroupResInfo->pRows, i);
120✔
3002
      SRowBuffPos*       pPos = pWinInfo->pStatePos;
120✔
3003
      SSessionKey*       pKey = (SSessionKey*)pPos->pKey;
120✔
3004
      if (pKey->win.ekey - pKey->win.skey < minWindowSize) {
120✔
3005
        size++;
60✔
3006
      }
3007
    }
3008
  }
3009
  if (size == 0) {
17,129✔
3010
    return;
16,583✔
3011
  }
3012
  code = blockDataEnsureCapacity(pBlock, size);
546✔
3013
  QUERY_CHECK_CODE(code, lino, _end);
546!
3014

3015
  int32_t iter = 0;
546✔
3016
  while (((*Ite) = tSimpleHashIterate(pStDeleted, *Ite, &iter)) != NULL) {
1,156✔
3017
    if (pBlock->info.rows + 1 > pBlock->info.capacity) {
610!
3018
      break;
×
3019
    }
3020
    SSessionKey*     res = tSimpleHashGetKey(*Ite, NULL);
610!
3021
    code = appendToDeleteDataBlock(pOp, pBlock, res);
610✔
3022
    QUERY_CHECK_CODE(code, lino, _end);
610!
3023
  }
3024

3025
  if (minWindowSize > 0) {
546✔
3026
    for (int32_t i = pGroupResInfo->delIndex; i < numOfRows; ++i) {
138✔
3027
      SResultWindowInfo* pWinInfo = taosArrayGet(pGroupResInfo->pRows, i);
120✔
3028
      SRowBuffPos*       pPos = pWinInfo->pStatePos;
120✔
3029
      SSessionKey*       pKey = (SSessionKey*)pPos->pKey;
120✔
3030
      if (pKey->win.ekey - pKey->win.skey < minWindowSize) {
120✔
3031
        code = appendToDeleteDataBlock(pOp, pBlock, pKey);
60✔
3032
        QUERY_CHECK_CODE(code, lino, _end);
60!
3033
      }
3034
    }
3035
    pGroupResInfo->delIndex = numOfRows;
18✔
3036
  }
3037

3038
_end:
528✔
3039
  if ((*Ite) == NULL) {
546!
3040
    tSimpleHashClear(pStDeleted);
546✔
3041
  }
3042

3043
  if (code != TSDB_CODE_SUCCESS) {
546!
3044
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
3045
  }
3046
}
3047

3048
static int32_t rebuildSessionWindow(SOperatorInfo* pOperator, SArray* pWinArray, SSHashObj* pStUpdated) {
54✔
3049
  int32_t        winCode = TSDB_CODE_SUCCESS;
54✔
3050
  int32_t        code = TSDB_CODE_SUCCESS;
54✔
3051
  int32_t        lino = 0;
54✔
3052
  SExprSupp*     pSup = &pOperator->exprSupp;
54✔
3053
  SExecTaskInfo* pTaskInfo = pOperator->pTaskInfo;
54✔
3054
  SStorageAPI*   pAPI = &pOperator->pTaskInfo->storageAPI;
54✔
3055

3056
  int32_t                        size = taosArrayGetSize(pWinArray);
54✔
3057
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
54✔
3058
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
54✔
3059
  int32_t                        numOfOutput = pSup->numOfExprs;
54✔
3060
  int32_t                        numOfChild = taosArrayGetSize(pInfo->pChildren);
54✔
3061

3062
  for (int32_t i = 0; i < size; i++) {
107✔
3063
    SSessionKey*      pWinKey = taosArrayGet(pWinArray, i);
53✔
3064
    int32_t           num = 0;
53✔
3065
    SResultWindowInfo parentWin = {0};
53✔
3066
    for (int32_t j = 0; j < numOfChild; j++) {
241✔
3067
      SOperatorInfo*                 pChild = taosArrayGetP(pInfo->pChildren, j);
188✔
3068
      SStreamSessionAggOperatorInfo* pChInfo = pChild->info;
188✔
3069
      SStreamAggSupporter*           pChAggSup = &pChInfo->streamAggSup;
188✔
3070
      SSessionKey                    chWinKey = {0};
188✔
3071
      getSessionHashKey(pWinKey, &chWinKey);
188✔
3072
      SStreamStateCur* pCur = pAggSup->stateStore.streamStateSessionSeekKeyCurrentNext(pChAggSup->pState, &chWinKey);
188✔
3073
      SResultRow*      pResult = NULL;
188✔
3074
      SResultRow*      pChResult = NULL;
188✔
3075
      while (1) {
21✔
3076
        SResultWindowInfo childWin = {0};
209✔
3077
        childWin.sessionWin = *pWinKey;
209✔
3078
        getSessionWinBuf(pChAggSup, pCur, &childWin, &winCode);
209✔
3079

3080
        if (winCode == TSDB_CODE_SUCCESS && !inWinRange(&pAggSup->winRange, &childWin.sessionWin.win)) {
209!
3081
          releaseOutputBuf(pAggSup->pState, childWin.pStatePos, &pAggSup->stateStore);
×
3082
          continue;
×
3083
        }
3084

3085
        if (winCode == TSDB_CODE_SUCCESS && inWinRange(&pWinKey->win, &childWin.sessionWin.win)) {
209✔
3086
          if (num == 0) {
21!
3087
            code = setSessionOutputBuf(pAggSup, pWinKey->win.skey, pWinKey->win.ekey, pWinKey->groupId, &parentWin,
21✔
3088
                                       &winCode);
3089
            QUERY_CHECK_CODE(code, lino, _end);
21!
3090

3091
            parentWin.sessionWin = childWin.sessionWin;
21✔
3092
            memcpy(parentWin.pStatePos->pKey, &parentWin.sessionWin, sizeof(SSessionKey));
21✔
3093
            code = initSessionOutputBuf(&parentWin, &pResult, pSup->pCtx, numOfOutput, pSup->rowEntryInfoOffset);
21✔
3094
            QUERY_CHECK_CODE(code, lino, _end);
21!
3095
          }
3096
          num++;
21✔
3097
          parentWin.sessionWin.win.skey = TMIN(parentWin.sessionWin.win.skey, childWin.sessionWin.win.skey);
21✔
3098
          parentWin.sessionWin.win.ekey = TMAX(parentWin.sessionWin.win.ekey, childWin.sessionWin.win.ekey);
21✔
3099
          memcpy(parentWin.pStatePos->pKey, &parentWin.sessionWin, sizeof(SSessionKey));
21✔
3100

3101
          updateTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &parentWin.sessionWin.win, pAggSup->gap);
21✔
3102
          code = initSessionOutputBuf(&childWin, &pChResult, pChild->exprSupp.pCtx, numOfOutput,
21✔
3103
                                      pChild->exprSupp.rowEntryInfoOffset);
3104
          QUERY_CHECK_CODE(code, lino, _end);
21!
3105

3106
          code = compactFunctions(pSup->pCtx, pChild->exprSupp.pCtx, numOfOutput, pTaskInfo,
21✔
3107
                                  &pInfo->twAggSup.timeWindowData);
3108
          QUERY_CHECK_CODE(code, lino, _end);
21!
3109

3110
          code = compactSessionWindow(pOperator, &parentWin, pStUpdated, NULL, true, NULL, NULL);
21✔
3111
          QUERY_CHECK_CODE(code, lino, _end);
21!
3112

3113
          releaseOutputBuf(pAggSup->pState, childWin.pStatePos, &pAggSup->stateStore);
21✔
3114
        } else {
3115
          releaseOutputBuf(pAggSup->pState, childWin.pStatePos, &pAggSup->stateStore);
188✔
3116
          break;
188✔
3117
        }
3118
      }
3119
      pAPI->stateStore.streamStateFreeCur(pCur);
188✔
3120
    }
3121
    if (num > 0) {
53✔
3122
      code = saveResult(parentWin, pStUpdated);
21✔
3123
      QUERY_CHECK_CODE(code, lino, _end);
21!
3124

3125
      code = saveSessionOutputBuf(pAggSup, &parentWin);
21✔
3126
      QUERY_CHECK_CODE(code, lino, _end);
21!
3127
    }
3128
  }
3129

3130
_end:
54✔
3131
  if (code != TSDB_CODE_SUCCESS) {
54!
3132
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
3133
  }
3134
  return code;
54✔
3135
}
3136

3137
int32_t closeSessionWindow(SSHashObj* pHashMap, STimeWindowAggSupp* pTwSup, SSHashObj* pClosed) {
10,402✔
3138
  int32_t code = TSDB_CODE_SUCCESS;
10,402✔
3139
  int32_t lino = 0;
10,402✔
3140
  void*   pIte = NULL;
10,402✔
3141
  int32_t iter = 0;
10,402✔
3142
  while ((pIte = tSimpleHashIterate(pHashMap, pIte, &iter)) != NULL) {
11,942✔
3143
    SResultWindowInfo* pWinInfo = pIte;
1,541✔
3144
    if (isCloseWindow(&pWinInfo->sessionWin.win, pTwSup)) {
1,541✔
3145
      if (pTwSup->calTrigger == STREAM_TRIGGER_WINDOW_CLOSE && pClosed) {
563!
3146
        code = saveResult(*pWinInfo, pClosed);
563✔
3147
        QUERY_CHECK_CODE(code, lino, _end);
564!
3148
      }
3149
      SSessionKey* pKey = tSimpleHashGetKey(pIte, NULL);
564!
3150
      code = tSimpleHashIterateRemove(pHashMap, pKey, sizeof(SSessionKey), &pIte, &iter);
564✔
3151
      QUERY_CHECK_CODE(code, lino, _end);
563!
3152
    }
3153
  }
3154
_end:
10,406✔
3155
  if (code != TSDB_CODE_SUCCESS) {
10,406!
3156
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
3157
  }
3158
  return code;
10,407✔
3159
}
3160

3161
static int32_t closeChildSessionWindow(SArray* pChildren, TSKEY maxTs) {
3,743✔
3162
  int32_t code = TSDB_CODE_SUCCESS;
3,743✔
3163
  int32_t lino = 0;
3,743✔
3164

3165
  int32_t size = taosArrayGetSize(pChildren);
3,743✔
3166
  for (int32_t i = 0; i < size; i++) {
4,272✔
3167
    SOperatorInfo*                 pChildOp = taosArrayGetP(pChildren, i);
529✔
3168
    SStreamSessionAggOperatorInfo* pChInfo = pChildOp->info;
529✔
3169
    pChInfo->twAggSup.maxTs = TMAX(pChInfo->twAggSup.maxTs, maxTs);
529✔
3170
    code = closeSessionWindow(pChInfo->streamAggSup.pResultRows, &pChInfo->twAggSup, NULL);
529✔
3171
    QUERY_CHECK_CODE(code, lino, _end);
529!
3172
  }
3173
_end:
3,743✔
3174
  if (code != TSDB_CODE_SUCCESS) {
3,743!
3175
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
3176
  }
3177
  return code;
3,743✔
3178
}
3179

3180
int32_t getAllSessionWindow(SSHashObj* pHashMap, SSHashObj* pStUpdated) {
211✔
3181
  int32_t code = TSDB_CODE_SUCCESS;
211✔
3182
  int32_t lino = 0;
211✔
3183
  void*   pIte = NULL;
211✔
3184
  int32_t iter = 0;
211✔
3185
  while ((pIte = tSimpleHashIterate(pHashMap, pIte, &iter)) != NULL) {
302✔
3186
    SResultWindowInfo* pWinInfo = pIte;
91✔
3187
    if (!pWinInfo->pStatePos->beUpdated) {
91✔
3188
      continue;
1✔
3189
    }
3190
    pWinInfo->pStatePos->beUpdated = false;
90✔
3191
    code = saveResult(*pWinInfo, pStUpdated);
90✔
3192
    QUERY_CHECK_CODE(code, lino, _end);
90!
3193
  }
3194

3195
_end:
211✔
3196
  if (code != TSDB_CODE_SUCCESS) {
211!
3197
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
3198
  }
3199
  return code;
211✔
3200
}
3201

3202
int32_t copyDeleteWindowInfo(SArray* pResWins, SSHashObj* pStDeleted) {
1,085✔
3203
  int32_t code = TSDB_CODE_SUCCESS;
1,085✔
3204
  int32_t lino = 0;
1,085✔
3205
  int32_t size = taosArrayGetSize(pResWins);
1,085✔
3206
  for (int32_t i = 0; i < size; i++) {
2,248✔
3207
    SSessionKey* pWinKey = taosArrayGet(pResWins, i);
1,161✔
3208
    if (!pWinKey) continue;
1,161!
3209
    SSessionKey winInfo = {0};
1,161✔
3210
    getSessionHashKey(pWinKey, &winInfo);
1,161✔
3211
    code = tSimpleHashPut(pStDeleted, &winInfo, sizeof(SSessionKey), NULL, 0);
1,161✔
3212
    QUERY_CHECK_CODE(code, lino, _end);
1,161!
3213
  }
3214

3215
_end:
1,087✔
3216
  if (code != TSDB_CODE_SUCCESS) {
1,087!
3217
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
3218
  }
3219
  return code;
1,086✔
3220
}
3221

3222
// the allocated memory comes from outer function.
3223
void initGroupResInfoFromArrayList(SGroupResInfo* pGroupResInfo, SArray* pArrayList) {
10,369✔
3224
  pGroupResInfo->pRows = pArrayList;
10,369✔
3225
  pGroupResInfo->index = 0;
10,369✔
3226
  pGroupResInfo->pBuf = NULL;
10,369✔
3227
  pGroupResInfo->freeItem = false;
10,369✔
3228
  pGroupResInfo->delIndex = 0;
10,369✔
3229
}
10,369✔
3230

3231
int32_t buildSessionResultDataBlock(SOperatorInfo* pOperator, void* pState, SSDataBlock* pBlock, SExprSupp* pSup,
5,580✔
3232
                                    SGroupResInfo* pGroupResInfo, SArray* pSessionKeys) {
3233
  int32_t         code = TSDB_CODE_SUCCESS;
5,580✔
3234
  int32_t         lino = 0;
5,580✔
3235
  SExecTaskInfo*  pTaskInfo = pOperator->pTaskInfo;
5,580✔
3236
  SStorageAPI*    pAPI = &pTaskInfo->storageAPI;
5,580✔
3237
  SExprInfo*      pExprInfo = pSup->pExprInfo;
5,580✔
3238
  int32_t         numOfExprs = pSup->numOfExprs;
5,580✔
3239
  int32_t*        rowEntryOffset = pSup->rowEntryInfoOffset;
5,580✔
3240
  SqlFunctionCtx* pCtx = pSup->pCtx;
5,580✔
3241
  int64_t         minWindowSize = getMinWindowSize(pOperator);
5,580✔
3242

3243
  int32_t numOfRows = getNumOfTotalRes(pGroupResInfo);
5,580✔
3244

3245
  for (int32_t i = pGroupResInfo->index; i < numOfRows; i += 1) {
12,365✔
3246
    SResultWindowInfo* pWinInfo = taosArrayGet(pGroupResInfo->pRows, i);
8,592✔
3247
    SRowBuffPos*       pPos = pWinInfo->pStatePos;
8,591✔
3248
    SResultRow*        pRow = NULL;
8,591✔
3249
    SSessionKey*       pKey = (SSessionKey*)pPos->pKey;
8,591✔
3250

3251
    if (pBlock->info.id.groupId == 0) {
8,591✔
3252
      pBlock->info.id.groupId = pKey->groupId;
6,039✔
3253

3254
      void*   tbname = NULL;
6,039✔
3255
      int32_t winCode = TSDB_CODE_SUCCESS;
6,039✔
3256
      code = pAPI->stateStore.streamStateGetParName((void*)pTaskInfo->streamInfo.pState, pBlock->info.id.groupId,
6,039✔
3257
                                                    &tbname, false, &winCode);
3258
      QUERY_CHECK_CODE(code, lino, _end);
6,039!
3259

3260
      if (winCode != TSDB_CODE_SUCCESS) {
6,039✔
3261
        pBlock->info.parTbName[0] = 0;
1,692✔
3262
      } else {
3263
        memcpy(pBlock->info.parTbName, tbname, TSDB_TABLE_NAME_LEN);
4,347✔
3264
      }
3265

3266
      qDebug("%s partName:%s, groupId:%"PRIu64, __FUNCTION__, (char*)tbname, pKey->groupId);
6,039✔
3267
      pAPI->stateStore.streamStateFreeVal(tbname);
6,039✔
3268
    } else {
3269
      // current value belongs to different group, it can't be packed into one datablock
3270
      if (pBlock->info.id.groupId != pKey->groupId) {
2,552✔
3271
        break;
1,773✔
3272
      }
3273
    }
3274

3275
    code = pAPI->stateStore.streamStateGetByPos(pState, pPos, (void**)&pRow);
6,818✔
3276
    QUERY_CHECK_CODE(code, lino, _end);
6,820!
3277

3278
    doUpdateNumOfRows(pCtx, pRow, numOfExprs, rowEntryOffset);
6,820✔
3279
    // no results, continue to check the next one
3280
    if (pRow->numOfRows == 0) {
6,819!
UNCOV
3281
      pGroupResInfo->index += 1;
×
3282
      continue;
60✔
3283
    }
3284
    // skip the window which is less than the windowMinSize
3285
    if (pKey->win.ekey - pKey->win.skey < minWindowSize) {
6,819✔
3286
      qDebug("skip small window, groupId: %" PRId64 ", windowSize: %" PRId64 ", minWindowSize: %" PRId64, pKey->groupId,
60!
3287
             pKey->win.ekey - pKey->win.skey, minWindowSize);
3288
      pGroupResInfo->index += 1;
60✔
3289
      continue;
60✔
3290
    }
3291

3292
    if (pBlock->info.rows + pRow->numOfRows > pBlock->info.capacity) {
6,759!
UNCOV
3293
      break;
×
3294
    }
3295

3296
    pGroupResInfo->index += 1;
6,759✔
3297

3298
    for (int32_t j = 0; j < numOfExprs; ++j) {
113,416✔
3299
      int32_t slotId = pExprInfo[j].base.resSchema.slotId;
106,691✔
3300

3301
      pCtx[j].resultInfo = getResultEntryInfo(pRow, j, rowEntryOffset);
106,691✔
3302
      if (pCtx[j].fpSet.finalize) {
106,688✔
3303
        int32_t tmpRes = pCtx[j].fpSet.finalize(&pCtx[j], pBlock);
97,665✔
3304
        if (TAOS_FAILED(tmpRes)) {
97,653!
UNCOV
3305
          qError("%s build result data block error, code %s", GET_TASKID(pTaskInfo), tstrerror(tmpRes));
×
3306
          QUERY_CHECK_CODE(code, lino, _end);
×
3307
        }
3308
      } else if (strcmp(pCtx[j].pExpr->pExpr->_function.functionName, "_select_value") == 0) {
9,023!
3309
        // do nothing, todo refactor
3310
      } else {
3311
        // expand the result into multiple rows. E.g., _wstart, top(k, 20)
3312
        // the _wstart needs to copy to 20 following rows, since the results of top-k expands to 20 different rows.
3313
        SColumnInfoData* pColInfoData = taosArrayGet(pBlock->pDataBlock, slotId);
9,025✔
3314
        char*            in = GET_ROWCELL_INTERBUF(pCtx[j].resultInfo);
9,025✔
3315
        for (int32_t k = 0; k < pRow->numOfRows; ++k) {
18,050✔
3316
          code = colDataSetVal(pColInfoData, pBlock->info.rows + k, in, pCtx[j].resultInfo->isNullRes);
9,025✔
3317
          QUERY_CHECK_CODE(code, lino, _end);
9,025!
3318
        }
3319
      }
3320
    }
3321

3322
    if (pSessionKeys) {
6,725!
UNCOV
3323
      for (int32_t j = 0; j < pRow->numOfRows; ++j) {
×
3324
        const void* px = taosArrayPush(pSessionKeys, pKey);
×
3325
        QUERY_CHECK_NULL(px, code, lino, _end, terrno);
×
3326
      }
3327
    }
3328

3329
    pBlock->info.dataLoad = 1;
6,725✔
3330
    pBlock->info.rows += pRow->numOfRows;
6,725✔
3331
  }
3332
  code = blockDataUpdateTsWindow(pBlock, 0);
5,546✔
3333
  QUERY_CHECK_CODE(code, lino, _end);
5,580!
3334

3335
_end:
5,580✔
3336
  if (code != TSDB_CODE_SUCCESS) {
5,580!
UNCOV
3337
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
3338
  }
3339
  return code;
5,580✔
3340
}
3341

3342
void doBuildSessionResult(SOperatorInfo* pOperator, void* pState, SGroupResInfo* pGroupResInfo, SSDataBlock* pBlock,
16,582✔
3343
                          SArray* pSessionKeys) {
3344
  int32_t        code = TSDB_CODE_SUCCESS;
16,582✔
3345
  int32_t        lino = 0;
16,582✔
3346
  SExecTaskInfo* pTaskInfo = pOperator->pTaskInfo;
16,582✔
3347
  // set output datablock version
3348
  pBlock->info.version = pTaskInfo->version;
16,582✔
3349

3350
  blockDataCleanup(pBlock);
16,582✔
3351
  taosArrayClear(pSessionKeys);
16,589✔
3352
  if (!hasRemainResults(pGroupResInfo)) {
16,590✔
3353
    cleanupGroupResInfo(pGroupResInfo);
11,015✔
3354
    goto _end;
11,022✔
3355
  }
3356

3357
  // clear the existed group id
3358
  pBlock->info.id.groupId = 0;
5,580✔
3359
  code = buildSessionResultDataBlock(pOperator, pState, pBlock, &pOperator->exprSupp, pGroupResInfo, pSessionKeys);
5,580✔
3360
  QUERY_CHECK_CODE(code, lino, _end);
5,580!
3361

3362
  if (pBlock->info.rows == 0) {
5,580!
UNCOV
3363
    cleanupGroupResInfo(pGroupResInfo);
×
3364
  }
3365

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

3372
static int32_t buildSessionResult(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
6,988✔
3373
  int32_t                        code = TSDB_CODE_SUCCESS;
6,988✔
3374
  int32_t                        lino = 0;
6,988✔
3375
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
6,988✔
3376
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
6,988✔
3377
  SOptrBasicInfo*                pBInfo = &pInfo->binfo;
6,988✔
3378
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
6,988✔
3379
  SStreamNotifyEventSupp*        pNotifySup = &pInfo->basic.notifyEventSup;
6,988✔
3380
  STaskNotifyEventStat*          pNotifyEventStat = pTaskInfo->streamInfo.pNotifyEventStat;
6,988✔
3381
  bool                           addNotifyEvent = false;
6,988✔
3382
  addNotifyEvent = IS_NORMAL_SESSION_OP(pOperator) &&
12,566✔
3383
                   BIT_FLAG_TEST_MASK(pTaskInfo->streamInfo.eventTypes, SNOTIFY_EVENT_WINDOW_CLOSE);
5,578!
3384
  doBuildDeleteDataBlock(pOperator, pInfo->pStDeleted, pInfo->pDelRes, &pInfo->pDelIterator, &pInfo->groupResInfo);
6,988✔
3385
  if (pInfo->pDelRes->info.rows > 0) {
6,982✔
3386
    printDataBlock(pInfo->pDelRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
255✔
3387
    if (addNotifyEvent) {
253!
UNCOV
3388
      code = addAggDeleteNotifyEvent(pInfo->pDelRes, pNotifySup, pNotifyEventStat);
×
3389
      QUERY_CHECK_CODE(code, lino, _end);
×
3390
    }
3391
    (*ppRes) = pInfo->pDelRes;
253✔
3392
    return code;
253✔
3393
  }
3394

3395
  doBuildSessionResult(pOperator, pAggSup->pState, &pInfo->groupResInfo, pBInfo->pRes,
6,727!
3396
                       addNotifyEvent ? pNotifySup->pSessionKeys : NULL);
3397
  if (pBInfo->pRes->info.rows > 0) {
6,742✔
3398
    printDataBlock(pBInfo->pRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
1,872✔
3399
    if (addNotifyEvent) {
1,872!
3400
      // Adjust the window end time based on the Session Window gap
UNCOV
3401
      for (int32_t i = 0; i < taosArrayGetSize(pNotifySup->pSessionKeys); ++i) {
×
3402
        SSessionKey* pKey = taosArrayGet(pNotifySup->pSessionKeys, i);
×
3403
        pKey->win.ekey += pAggSup->gap;
×
3404
      }
UNCOV
3405
      code = addAggResultNotifyEvent(pBInfo->pRes, pNotifySup->pSessionKeys, pTaskInfo->streamInfo.notifyResultSchema,
×
3406
                                     pNotifySup, pNotifyEventStat);
UNCOV
3407
      QUERY_CHECK_CODE(code, lino, _end);
×
3408
    }
3409
    (*ppRes) = pBInfo->pRes;
1,872✔
3410
    return code;
1,872✔
3411
  }
3412

3413
  code = buildNotifyEventBlock(pTaskInfo, pNotifySup, pNotifyEventStat);
4,870✔
3414
  QUERY_CHECK_CODE(code, lino, _end);
4,867!
3415
  if (pNotifySup->pEventBlock && pNotifySup->pEventBlock->info.rows > 0) {
4,867!
UNCOV
3416
    printDataBlock(pNotifySup->pEventBlock, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
3417
    (*ppRes) = pNotifySup->pEventBlock;
×
3418
    return code;
×
3419
  }
3420

3421
  code = removeOutdatedNotifyEvents(&pInfo->twAggSup, pNotifySup, pNotifyEventStat);
4,867✔
3422
  QUERY_CHECK_CODE(code, lino, _end);
4,866!
3423

3424
_end:
4,866✔
3425
  if (code != TSDB_CODE_SUCCESS) {
4,866!
UNCOV
3426
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
3427
  }
3428
  (*ppRes) = NULL;
4,866✔
3429
  return code;
4,866✔
3430
}
3431

3432
int32_t getMaxTsWins(const SArray* pAllWins, SArray* pMaxWins) {
370✔
3433
  int32_t code = TSDB_CODE_SUCCESS;
370✔
3434
  int32_t lino = 0;
370✔
3435
  int32_t size = taosArrayGetSize(pAllWins);
370✔
3436
  if (size == 0) {
370✔
3437
    goto _end;
237✔
3438
  }
3439
  SResultWindowInfo* pWinInfo = taosArrayGet(pAllWins, size - 1);
133✔
3440
  SSessionKey*       pSeKey = &pWinInfo->sessionWin;
133✔
3441
  void*              tmp = taosArrayPush(pMaxWins, pSeKey);
133✔
3442
  if (!tmp) {
133!
UNCOV
3443
    code = terrno;
×
3444
    QUERY_CHECK_CODE(code, lino, _end);
×
3445
  }
3446

3447
  if (pSeKey->groupId == 0) {
133✔
3448
    goto _end;
17✔
3449
  }
3450
  uint64_t preGpId = pSeKey->groupId;
116✔
3451
  for (int32_t i = size - 2; i >= 0; i--) {
445✔
3452
    pWinInfo = taosArrayGet(pAllWins, i);
329✔
3453
    pSeKey = &pWinInfo->sessionWin;
329✔
3454
    if (preGpId != pSeKey->groupId) {
329✔
3455
      void* tmp = taosArrayPush(pMaxWins, pSeKey);
206✔
3456
      if (!tmp) {
206!
UNCOV
3457
        code = terrno;
×
3458
        QUERY_CHECK_CODE(code, lino, _end);
×
3459
      }
3460
      preGpId = pSeKey->groupId;
206✔
3461
    }
3462
  }
3463

3464
_end:
116✔
3465
  if (code != TSDB_CODE_SUCCESS) {
370!
UNCOV
3466
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
3467
  }
3468
  return code;
370✔
3469
}
3470

UNCOV
3471
int32_t encodeSSessionKey(void** buf, SSessionKey* key) {
×
UNCOV
3472
  int32_t tlen = 0;
×
UNCOV
3473
  tlen += encodeSTimeWindow(buf, &key->win);
×
UNCOV
3474
  tlen += taosEncodeFixedU64(buf, key->groupId);
×
UNCOV
3475
  return tlen;
×
3476
}
3477

UNCOV
3478
void* decodeSSessionKey(void* buf, SSessionKey* key) {
×
3479
  buf = decodeSTimeWindow(buf, &key->win);
×
3480
  buf = taosDecodeFixedU64(buf, &key->groupId);
×
3481
  return buf;
×
3482
}
3483

UNCOV
3484
int32_t encodeSResultWindowInfo(void** buf, SResultWindowInfo* key, int32_t outLen) {
×
UNCOV
3485
  int32_t tlen = 0;
×
UNCOV
3486
  tlen += taosEncodeFixedBool(buf, key->isOutput);
×
UNCOV
3487
  tlen += encodeSSessionKey(buf, &key->sessionWin);
×
UNCOV
3488
  return tlen;
×
3489
}
3490

UNCOV
3491
void* decodeSResultWindowInfo(void* buf, SResultWindowInfo* key, int32_t outLen) {
×
3492
  buf = taosDecodeFixedBool(buf, &key->isOutput);
×
3493
  buf = decodeSSessionKey(buf, &key->sessionWin);
×
3494
  return buf;
×
3495
}
3496

UNCOV
3497
int32_t doStreamSessionEncodeOpState(void** buf, int32_t len, SOperatorInfo* pOperator, bool isParent) {
×
3498
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
×
3499
  if (!pInfo) {
×
3500
    return 0;
×
3501
  }
3502

UNCOV
3503
  void* pData = (buf == NULL) ? NULL : *buf;
×
3504

3505
  // 1.streamAggSup.pResultRows
UNCOV
3506
  int32_t tlen = 0;
×
3507
  int32_t mapSize = tSimpleHashGetSize(pInfo->streamAggSup.pResultRows);
×
3508
  tlen += taosEncodeFixedI32(buf, mapSize);
×
3509
  void*   pIte = NULL;
×
3510
  size_t  keyLen = 0;
×
3511
  int32_t iter = 0;
×
3512
  while ((pIte = tSimpleHashIterate(pInfo->streamAggSup.pResultRows, pIte, &iter)) != NULL) {
×
3513
    void* key = tSimpleHashGetKey(pIte, &keyLen);
×
3514
    tlen += encodeSSessionKey(buf, key);
×
3515
    tlen += encodeSResultWindowInfo(buf, pIte, pInfo->streamAggSup.resultRowSize);
×
3516
  }
3517

3518
  // 2.twAggSup
UNCOV
3519
  tlen += encodeSTimeWindowAggSupp(buf, &pInfo->twAggSup);
×
3520

3521
  // 3.pChildren
UNCOV
3522
  int32_t size = taosArrayGetSize(pInfo->pChildren);
×
3523
  tlen += taosEncodeFixedI32(buf, size);
×
3524
  for (int32_t i = 0; i < size; i++) {
×
3525
    SOperatorInfo* pChOp = taosArrayGetP(pInfo->pChildren, i);
×
3526
    tlen += doStreamSessionEncodeOpState(buf, 0, pChOp, false);
×
3527
  }
3528

3529
  // 4.dataVersion
UNCOV
3530
  tlen += taosEncodeFixedI64(buf, pInfo->dataVersion);
×
3531

3532
  // 5.basicInfo
UNCOV
3533
  tlen += encodeStreamBasicInfo(buf, &pInfo->basic);
×
3534

3535
  // 6.checksum
UNCOV
3536
  if (isParent) {
×
3537
    if (buf) {
×
3538
      uint32_t cksum = taosCalcChecksum(0, pData, len - sizeof(uint32_t));
×
3539
      tlen += taosEncodeFixedU32(buf, cksum);
×
3540
    } else {
UNCOV
3541
      tlen += sizeof(uint32_t);
×
3542
    }
3543
  }
3544

UNCOV
3545
  return tlen;
×
3546
}
3547

UNCOV
3548
int32_t doStreamSessionDecodeOpState(void* buf, int32_t len, SOperatorInfo* pOperator, bool isParent, void** ppBuf) {
×
3549
  int32_t                        code = TSDB_CODE_SUCCESS;
×
3550
  int32_t                        lino = 0;
×
3551
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
×
3552
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
×
3553
  void*                        pDataEnd = POINTER_SHIFT(buf, len);
×
3554
  if (!pInfo) {
×
3555
    code = TSDB_CODE_FAILED;
×
3556
    QUERY_CHECK_CODE(code, lino, _end);
×
3557
  }
UNCOV
3558
  SStreamAggSupporter* pAggSup = &pInfo->streamAggSup;
×
3559

3560
  // 6.checksum
UNCOV
3561
  if (isParent) {
×
3562
    int32_t dataLen = len - sizeof(uint32_t);
×
3563
    void*   pCksum = POINTER_SHIFT(buf, dataLen);
×
3564
    if (taosCheckChecksum(buf, dataLen, *(uint32_t*)pCksum) != TSDB_CODE_SUCCESS) {
×
3565
      qError("stream session state is invalid");
×
3566
      code = TSDB_CODE_FAILED;
×
3567
      QUERY_CHECK_CODE(code, lino, _end);
×
3568
    }
UNCOV
3569
    pDataEnd = pCksum;
×
3570
  }
3571

3572
  // 1.streamAggSup.pResultRows
UNCOV
3573
  int32_t mapSize = 0;
×
3574
  buf = taosDecodeFixedI32(buf, &mapSize);
×
3575
  for (int32_t i = 0; i < mapSize; i++) {
×
3576
    SResultWindowInfo winfo = {0};
×
3577
    buf = decodeSSessionKey(buf, &winfo.sessionWin);
×
3578
    int32_t winCode = TSDB_CODE_SUCCESS;
×
3579
    code = pAggSup->stateStore.streamStateSessionAddIfNotExist(
×
3580
        pAggSup->pState, &winfo.sessionWin, pAggSup->gap, (void**)&winfo.pStatePos, &pAggSup->resultRowSize, &winCode);
UNCOV
3581
    QUERY_CHECK_CODE(code, lino, _end);
×
3582
    QUERY_CHECK_CONDITION((winCode == TSDB_CODE_SUCCESS), code, lino, _end, TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR);
×
3583

UNCOV
3584
    buf = decodeSResultWindowInfo(buf, &winfo, pInfo->streamAggSup.resultRowSize);
×
3585
    code = tSimpleHashPut(pInfo->streamAggSup.pResultRows, &winfo.sessionWin, sizeof(SSessionKey), &winfo,
×
3586
                          sizeof(SResultWindowInfo));
UNCOV
3587
    QUERY_CHECK_CODE(code, lino, _end);
×
3588
  }
3589

3590
  // 2.twAggSup
UNCOV
3591
  buf = decodeSTimeWindowAggSupp(buf, &pInfo->twAggSup);
×
3592

3593
  // 3.pChildren
UNCOV
3594
  int32_t size = 0;
×
3595
  buf = taosDecodeFixedI32(buf, &size);
×
3596
  for (int32_t i = 0; i < size; i++) {
×
3597
    SOperatorInfo* pChOp = taosArrayGetP(pInfo->pChildren, i);
×
3598
    code = doStreamSessionDecodeOpState(buf, 0, pChOp, false, &buf);
×
3599
    QUERY_CHECK_CODE(code, lino, _end);
×
3600
  }
3601

3602
  // 4.dataVersion
UNCOV
3603
  buf = taosDecodeFixedI64(buf, &pInfo->dataVersion);
×
3604
  if (ppBuf) {
×
3605
    (*ppBuf) = buf;
×
3606
  }
3607

3608
  // 5.basicInfo
UNCOV
3609
  if (buf < pDataEnd) {
×
3610
    code = decodeStreamBasicInfo(&buf, &pInfo->basic);
×
3611
    QUERY_CHECK_CODE(code, lino, _end);
×
3612
  }
3613

UNCOV
3614
_end:
×
3615
  if (code != TSDB_CODE_SUCCESS) {
×
3616
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
3617
  }
UNCOV
3618
  return code;
×
3619
}
3620

3621
void doStreamSessionSaveCheckpoint(SOperatorInfo* pOperator) {
191✔
3622
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
191✔
3623
  if (needSaveStreamOperatorInfo(&pInfo->basic)) {
191!
UNCOV
3624
    int32_t len = doStreamSessionEncodeOpState(NULL, 0, pOperator, true);
×
3625
    void*   buf = taosMemoryCalloc(1, len);
×
3626
    if (!buf) {
×
3627
      qError("%s failed at line %d since %s", __func__, __LINE__, tstrerror(TSDB_CODE_OUT_OF_MEMORY));
×
3628
      return;
×
3629
    }
UNCOV
3630
    void* pBuf = buf;
×
3631
    len = doStreamSessionEncodeOpState(&pBuf, len, pOperator, true);
×
3632
    pInfo->streamAggSup.stateStore.streamStateSaveInfo(pInfo->streamAggSup.pState, STREAM_SESSION_OP_CHECKPOINT_NAME,
×
3633
                                                       strlen(STREAM_SESSION_OP_CHECKPOINT_NAME), buf, len);
UNCOV
3634
    taosMemoryFree(buf);
×
3635
    saveStreamOperatorStateComplete(&pInfo->basic);
×
3636
  }
3637
}
3638

3639
void resetUnCloseSessionWinInfo(SSHashObj* winMap) {
92✔
3640
  void*   pIte = NULL;
92✔
3641
  int32_t iter = 0;
92✔
3642
  while ((pIte = tSimpleHashIterate(winMap, pIte, &iter)) != NULL) {
182✔
3643
    SResultWindowInfo* pResInfo = pIte;
90✔
3644
    pResInfo->pStatePos->beUsed = true;
90✔
3645
  }
3646
}
92✔
3647

3648
int32_t copyDeleteSessionKey(SSHashObj* source, SSHashObj* dest) {
32✔
3649
  int32_t code = TSDB_CODE_SUCCESS;
32✔
3650
  int32_t lino = 0;
32✔
3651
  if (tSimpleHashGetSize(source) == 0) {
32✔
3652
    goto _end;
23✔
3653
  }
3654
  void*   pIte = NULL;
9✔
3655
  int32_t iter = 0;
9✔
3656
  size_t  keyLen = 0;
9✔
3657
  while ((pIte = tSimpleHashIterate(source, pIte, &iter)) != NULL) {
21✔
3658
    SSessionKey* pKey = tSimpleHashGetKey(pIte, &keyLen);
12✔
3659
    code = saveDeleteRes(dest, *pKey);
12✔
3660
    QUERY_CHECK_CODE(code, lino, _end);
12!
3661
  }
3662
  tSimpleHashClear(source);
9✔
3663

3664
_end:
32✔
3665
  if (code != TSDB_CODE_SUCCESS) {
32!
UNCOV
3666
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
3667
  }
3668
  return code;
32✔
3669
}
3670

3671
static int32_t doStreamSessionAggNext(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
6,423✔
3672
  int32_t                        code = TSDB_CODE_SUCCESS;
6,423✔
3673
  int32_t                        lino = 0;
6,423✔
3674
  SExprSupp*                     pSup = &pOperator->exprSupp;
6,423✔
3675
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
6,423✔
3676
  SOptrBasicInfo*                pBInfo = &pInfo->binfo;
6,423✔
3677
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
6,423✔
3678
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
6,423✔
3679
  qDebug("stask:%s  %s status: %d", GET_TASKID(pTaskInfo), getStreamOpName(pOperator->operatorType), pOperator->status);
6,423✔
3680
  if (pOperator->status == OP_EXEC_DONE) {
6,424!
UNCOV
3681
    (*ppRes) = NULL;
×
3682
    return code;
×
3683
  } else if (pOperator->status == OP_RES_TO_RETURN) {
6,424✔
3684
    SSDataBlock* opRes = NULL;
1,842✔
3685
    code = buildSessionResult(pOperator, &opRes);
1,842✔
3686
    QUERY_CHECK_CODE(code, lino, _end);
1,843!
3687
    if (opRes) {
1,843✔
3688
      (*ppRes) = opRes;
448✔
3689
      return code;
1,844✔
3690
    }
3691

3692
    if (pInfo->recvGetAll) {
1,395✔
3693
      pInfo->recvGetAll = false;
83✔
3694
      resetUnCloseSessionWinInfo(pInfo->streamAggSup.pResultRows);
83✔
3695
    }
3696

3697
    if (pInfo->reCkBlock) {
1,395!
UNCOV
3698
      pInfo->reCkBlock = false;
×
3699
      printDataBlock(pInfo->pCheckpointRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
3700
      (*ppRes) = pInfo->pCheckpointRes;
×
3701
      return code;
×
3702
    }
3703

3704
    setStreamOperatorCompleted(pOperator);
1,395✔
3705
    (*ppRes) = NULL;
1,396✔
3706
    return code;
1,396✔
3707
  }
3708

3709
  SOperatorInfo* downstream = pOperator->pDownstream[0];
4,582✔
3710
  if (!pInfo->pUpdated) {
4,582✔
3711
    pInfo->pUpdated = taosArrayInit(16, sizeof(SResultWindowInfo));
3,744✔
3712
    QUERY_CHECK_NULL(pInfo->pUpdated, code, lino, _end, terrno);
3,739!
3713
  }
3714
  if (!pInfo->pStUpdated) {
4,577✔
3715
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
3,670✔
3716
    pInfo->pStUpdated = tSimpleHashInit(64, hashFn);
3,670✔
3717
    QUERY_CHECK_NULL(pInfo->pStUpdated, code, lino, _end, terrno);
3,679!
3718
  }
3719
  while (1) {
3,287✔
3720
    SSDataBlock* pBlock = NULL;
7,873✔
3721
    code = downstream->fpSet.getNextFn(downstream, &pBlock);
7,873✔
3722
    QUERY_CHECK_CODE(code, lino, _end);
7,868!
3723

3724
    if (pBlock == NULL) {
7,868✔
3725
      break;
3,742✔
3726
    }
3727
    printSpecDataBlock(pBlock, getStreamOpName(pOperator->operatorType), "recv", GET_TASKID(pTaskInfo));
4,126✔
3728
    setStreamOperatorState(&pInfo->basic, pBlock->info.type);
4,125✔
3729

3730
    if (pBlock->info.type == STREAM_DELETE_DATA || pBlock->info.type == STREAM_DELETE_RESULT ||
4,127✔
3731
        pBlock->info.type == STREAM_CLEAR) {
3,893✔
3732
      SArray* pWins = taosArrayInit(16, sizeof(SSessionKey));
399✔
3733
      QUERY_CHECK_NULL(pWins, code, lino, _end, terrno);
398!
3734
      // gap must be 0
3735
      code = doDeleteTimeWindows(pAggSup, pBlock, pWins);
398✔
3736
      QUERY_CHECK_CODE(code, lino, _end);
398!
3737

3738
      removeSessionResults(pAggSup, pInfo->pStUpdated, pWins);
398✔
3739
      if (IS_FINAL_SESSION_OP(pOperator)) {
399✔
3740
        int32_t                        childIndex = getChildIndex(pBlock);
54✔
3741
        SOperatorInfo*                 pChildOp = taosArrayGetP(pInfo->pChildren, childIndex);
54✔
3742
        SStreamSessionAggOperatorInfo* pChildInfo = pChildOp->info;
54✔
3743
        // gap must be 0
3744
        code = doDeleteTimeWindows(&pChildInfo->streamAggSup, pBlock, NULL);
54✔
3745
        QUERY_CHECK_CODE(code, lino, _end);
54!
3746

3747
        code = rebuildSessionWindow(pOperator, pWins, pInfo->pStUpdated);
54✔
3748
        QUERY_CHECK_CODE(code, lino, _end);
54!
3749
      }
3750
      code = copyDeleteWindowInfo(pWins, pInfo->pStDeleted);
399✔
3751
      QUERY_CHECK_CODE(code, lino, _end);
398!
3752

3753
      if (pInfo->destHasPrimaryKey && IS_NORMAL_SESSION_OP(pOperator)) {
398!
3754
        code = copyDeleteWindowInfo(pWins, pInfo->pPkDeleted);
2✔
3755
        QUERY_CHECK_CODE(code, lino, _end);
2!
3756
      }
3757
      taosArrayDestroy(pWins);
398✔
3758
      continue;
762✔
3759
    } else if (pBlock->info.type == STREAM_GET_ALL) {
3,728✔
3760
      pInfo->recvGetAll = true;
187✔
3761
      code = getAllSessionWindow(pAggSup->pResultRows, pInfo->pStUpdated);
187✔
3762
      QUERY_CHECK_CODE(code, lino, _end);
187!
3763
      continue;
187✔
3764
    } else if (pBlock->info.type == STREAM_CREATE_CHILD_TABLE) {
3,541✔
3765
      (*ppRes) = pBlock;
841✔
3766
      return code;
841✔
3767
    } else if (pBlock->info.type == STREAM_CHECKPOINT) {
2,700✔
3768
      pAggSup->stateStore.streamStateCommit(pAggSup->pState);
176✔
3769
      doStreamSessionSaveCheckpoint(pOperator);
176✔
3770
      code = copyDataBlock(pInfo->pCheckpointRes, pBlock);
176✔
3771
      QUERY_CHECK_CODE(code, lino, _end);
176!
3772

3773
      continue;
176✔
3774
    } else {
3775
      if (pBlock->info.type != STREAM_NORMAL && pBlock->info.type != STREAM_INVALID) {
2,524!
UNCOV
3776
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
3777
        QUERY_CHECK_CODE(code, lino, _end);
×
3778
      }
3779
    }
3780

3781
    if (pInfo->scalarSupp.pExprInfo != NULL) {
2,524✔
3782
      SExprSupp* pExprSup = &pInfo->scalarSupp;
13✔
3783
      code = projectApplyFunctions(pExprSup->pExprInfo, pBlock, pBlock, pExprSup->pCtx, pExprSup->numOfExprs, NULL);
13✔
3784
      QUERY_CHECK_CODE(code, lino, _end);
13!
3785
    }
3786
    // the pDataBlock are always the same one, no need to call this again
3787
    code = setInputDataBlock(pSup, pBlock, TSDB_ORDER_ASC, MAIN_SCAN, true);
2,524✔
3788
    QUERY_CHECK_CODE(code, lino, _end);
2,526!
3789

3790
    doStreamSessionAggImpl(pOperator, pBlock, pInfo->pStUpdated, pInfo->pStDeleted, IS_FINAL_SESSION_OP(pOperator),
2,526✔
3791
                           true);
3792
    if (IS_FINAL_SESSION_OP(pOperator)) {
2,525✔
3793
      int32_t chIndex = getChildIndex(pBlock);
227✔
3794
      int32_t size = taosArrayGetSize(pInfo->pChildren);
227✔
3795
      // if chIndex + 1 - size > 0, add new child
3796
      for (int32_t i = 0; i < chIndex + 1 - size; i++) {
227!
UNCOV
3797
        SOperatorInfo* pChildOp = NULL;
×
3798
        code = createStreamFinalSessionAggOperatorInfo(NULL, pInfo->pPhyNode, pOperator->pTaskInfo, 0, NULL, &pChildOp);
×
3799
        if (pChildOp == NULL || code != 0) {
×
3800
          qError("%s create stream child of final session error", GET_TASKID(pTaskInfo));
×
3801
          code = TSDB_CODE_FAILED;
×
3802
          QUERY_CHECK_CODE(code, lino, _end);
×
3803
        }
3804

UNCOV
3805
        void* tmp = taosArrayPush(pInfo->pChildren, &pChildOp);
×
3806
        if (!tmp) {
×
3807
          code = terrno;
×
3808
          QUERY_CHECK_CODE(code, lino, _end);
×
3809
        }
3810
      }
3811

3812
      SOperatorInfo* pChildOp = taosArrayGetP(pInfo->pChildren, chIndex);
227✔
3813
      code = setInputDataBlock(&pChildOp->exprSupp, pBlock, TSDB_ORDER_ASC, MAIN_SCAN, true);
227✔
3814
      QUERY_CHECK_CODE(code, lino, _end);
227!
3815
      doStreamSessionAggImpl(pChildOp, pBlock, NULL, NULL, true, false);
227✔
3816
    }
3817
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.window.ekey);
2,525✔
3818
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.watermark);
2,525✔
3819
  }
3820
  // restore the value
3821
  pOperator->status = OP_RES_TO_RETURN;
3,742✔
3822

3823
  code = closeSessionWindow(pAggSup->pResultRows, &pInfo->twAggSup, pInfo->pStUpdated);
3,742✔
3824
  QUERY_CHECK_CODE(code, lino, _end);
3,743!
3825

3826
  code = closeChildSessionWindow(pInfo->pChildren, pInfo->twAggSup.maxTs);
3,743✔
3827
  QUERY_CHECK_CODE(code, lino, _end);
3,743!
3828

3829
  code = copyUpdateResult(&pInfo->pStUpdated, pInfo->pUpdated, sessionKeyCompareAsc);
3,743✔
3830
  QUERY_CHECK_CODE(code, lino, _end);
3,742!
3831

3832
  if (!pInfo->destHasPrimaryKey) {
3,742✔
3833
    removeSessionDeleteResults(pInfo->pStDeleted, pInfo->pUpdated);
3,722✔
3834
  }
3835
  if (pInfo->isHistoryOp) {
3,741✔
3836
    code = getMaxTsWins(pInfo->pUpdated, pInfo->historyWins);
194✔
3837
    QUERY_CHECK_CODE(code, lino, _end);
194!
3838
  }
3839
  if (pInfo->destHasPrimaryKey && IS_NORMAL_SESSION_OP(pOperator)) {
3,741!
3840
    code = copyDeleteSessionKey(pInfo->pPkDeleted, pInfo->pStDeleted);
21✔
3841
    QUERY_CHECK_CODE(code, lino, _end);
21!
3842
  }
3843
  initGroupResInfoFromArrayList(&pInfo->groupResInfo, pInfo->pUpdated);
3,741✔
3844
  pInfo->pUpdated = NULL;
3,738✔
3845
  code = blockDataEnsureCapacity(pInfo->binfo.pRes, pOperator->resultInfo.capacity);
3,738✔
3846
  QUERY_CHECK_CODE(code, lino, _end);
3,740!
3847

3848
  SSDataBlock* opRes = NULL;
3,740✔
3849
  code = buildSessionResult(pOperator, &opRes);
3,740✔
3850
  QUERY_CHECK_CODE(code, lino, _end);
3,742!
3851
  if (opRes) {
3,742✔
3852
    (*ppRes) = opRes;
1,396✔
3853
    return code;
1,396✔
3854
  }
3855

3856
_end:
2,346✔
3857
  if (code != TSDB_CODE_SUCCESS) {
2,346!
UNCOV
3858
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
3859
    pTaskInfo->code = code;
×
3860
    T_LONG_JMP(pTaskInfo->env, code);
×
3861
  }
3862
  setStreamOperatorCompleted(pOperator);
2,346✔
3863
  (*ppRes) = NULL;
2,346✔
3864
  return code;
2,346✔
3865
}
3866

UNCOV
3867
static SSDataBlock* doStreamSessionAgg(SOperatorInfo* pOperator) {
×
3868
  SSDataBlock* pRes = NULL;
×
3869
  int32_t      code = doStreamSessionAggNext(pOperator, &pRes);
×
3870
  return pRes;
×
3871
}
3872

3873
void streamSessionReleaseState(SOperatorInfo* pOperator) {
191✔
3874
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
191✔
3875
  int32_t                        winSize = taosArrayGetSize(pInfo->historyWins) * sizeof(SSessionKey);
191✔
3876
  int32_t                        resSize = winSize + sizeof(TSKEY);
191✔
3877
  char*                          pBuff = taosMemoryCalloc(1, resSize);
191!
3878
  if (!pBuff) {
191!
UNCOV
3879
    return;
×
3880
  }
3881
  memcpy(pBuff, pInfo->historyWins->pData, winSize);
191✔
3882
  memcpy(pBuff + winSize, &pInfo->twAggSup.maxTs, sizeof(TSKEY));
191✔
3883
  pInfo->streamAggSup.stateStore.streamStateSaveInfo(pInfo->streamAggSup.pState, STREAM_SESSION_OP_STATE_NAME,
191✔
3884
                                                     strlen(STREAM_SESSION_OP_STATE_NAME), pBuff, resSize);
3885
  pInfo->streamAggSup.stateStore.streamStateCommit(pInfo->streamAggSup.pState);
191✔
3886
  taosMemoryFreeClear(pBuff);
191!
3887
  SOperatorInfo* downstream = pOperator->pDownstream[0];
191✔
3888
  if (downstream->fpSet.releaseStreamStateFn) {
191!
3889
    downstream->fpSet.releaseStreamStateFn(downstream);
191✔
3890
  }
3891
}
3892

3893
void resetWinRange(STimeWindow* winRange) {
357✔
3894
  winRange->skey = INT64_MIN;
357✔
3895
  winRange->ekey = INT64_MAX;
357✔
3896
}
357✔
3897

3898
int32_t getSessionWindowInfoByKey(SStreamAggSupporter* pAggSup, SSessionKey* pKey, SResultWindowInfo* pWinInfo) {
339✔
3899
  int32_t code = TSDB_CODE_SUCCESS;
339✔
3900
  int32_t lino = 0;
339✔
3901
  int32_t rowSize = pAggSup->resultRowSize;
339✔
3902
  int32_t winCode = TSDB_CODE_SUCCESS;
339✔
3903
  code = pAggSup->stateStore.streamStateSessionGet(pAggSup->pState, pKey, (void**)&pWinInfo->pStatePos, &rowSize,
339✔
3904
                                                   &winCode);
3905
  QUERY_CHECK_CODE(code, lino, _end);
339!
3906

3907
  if (winCode == TSDB_CODE_SUCCESS) {
339!
3908
    pWinInfo->sessionWin = *pKey;
339✔
3909
    pWinInfo->isOutput = true;
339✔
3910
    if (pWinInfo->pStatePos->needFree) {
339!
3911
      pAggSup->stateStore.streamStateSessionDel(pAggSup->pState, &pWinInfo->sessionWin);
339✔
3912
    }
3913
  } else {
UNCOV
3914
    SET_SESSION_WIN_INVALID((*pWinInfo));
×
3915
  }
3916

3917
_end:
339✔
3918
  if (code != TSDB_CODE_SUCCESS) {
339!
UNCOV
3919
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
3920
  }
3921
  return code;
339✔
3922
}
3923

3924
void reloadAggSupFromDownStream(SOperatorInfo* downstream, SStreamAggSupporter* pAggSup) {
639✔
3925
  SStateStore* pAPI = &downstream->pTaskInfo->storageAPI.stateStore;
639✔
3926

3927
  if (downstream->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_SCAN) {
639✔
3928
    reloadAggSupFromDownStream(downstream->pDownstream[0], pAggSup);
203✔
3929
    return;
203✔
3930
  }
3931

3932
  SStreamScanInfo* pScanInfo = downstream->info;
436✔
3933
  pAggSup->pUpdateInfo = pScanInfo->pUpdateInfo;
436✔
3934
}
3935

3936
void streamSessionSemiReloadState(SOperatorInfo* pOperator) {
15✔
3937
  int32_t                        code = TSDB_CODE_SUCCESS;
15✔
3938
  int32_t                        lino = 0;
15✔
3939
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
15✔
3940
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
15✔
3941
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
15✔
3942
  resetWinRange(&pAggSup->winRange);
15✔
3943

3944
  SResultWindowInfo winInfo = {0};
15✔
3945
  int32_t           size = 0;
15✔
3946
  void*             pBuf = NULL;
15✔
3947
  code = pAggSup->stateStore.streamStateGetInfo(pAggSup->pState, STREAM_SESSION_OP_STATE_NAME,
15✔
3948
                                                strlen(STREAM_SESSION_OP_STATE_NAME), &pBuf, &size);
3949
  QUERY_CHECK_CODE(code, lino, _end);
15!
3950

3951
  int32_t      num = (size - sizeof(TSKEY)) / sizeof(SSessionKey);
15✔
3952
  SSessionKey* pSeKeyBuf = (SSessionKey*)pBuf;
15✔
3953
  for (int32_t i = 0; i < num; i++) {
39✔
3954
    SResultWindowInfo winInfo = {0};
24✔
3955
    code = getSessionWindowInfoByKey(pAggSup, pSeKeyBuf + i, &winInfo);
24✔
3956
    QUERY_CHECK_CODE(code, lino, _end);
24!
3957
    if (!IS_VALID_SESSION_WIN(winInfo)) {
24!
UNCOV
3958
      continue;
×
3959
    }
3960
    compactSessionSemiWindow(pOperator, &winInfo);
24✔
3961
    code = saveSessionOutputBuf(pAggSup, &winInfo);
24✔
3962
    QUERY_CHECK_CODE(code, lino, _end);
24!
3963
  }
3964
  TSKEY ts = *(TSKEY*)((char*)pBuf + size - sizeof(TSKEY));
15✔
3965
  taosMemoryFree(pBuf);
15!
3966
  pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, ts);
15✔
3967
  pAggSup->stateStore.streamStateReloadInfo(pAggSup->pState, ts);
15✔
3968

3969
  SOperatorInfo* downstream = pOperator->pDownstream[0];
15✔
3970
  if (downstream->fpSet.reloadStreamStateFn) {
15!
3971
    downstream->fpSet.reloadStreamStateFn(downstream);
15✔
3972
  }
3973
  reloadAggSupFromDownStream(downstream, &pInfo->streamAggSup);
15✔
3974

3975
_end:
15✔
3976
  if (code != TSDB_CODE_SUCCESS) {
15!
UNCOV
3977
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
3978
  }
3979
}
15✔
3980

3981
void streamSessionReloadState(SOperatorInfo* pOperator) {
176✔
3982
  int32_t                        code = TSDB_CODE_SUCCESS;
176✔
3983
  int32_t                        lino = 0;
176✔
3984
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
176✔
3985
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
176✔
3986
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
176✔
3987
  resetWinRange(&pAggSup->winRange);
176✔
3988

3989
  int32_t size = 0;
176✔
3990
  void*   pBuf = NULL;
176✔
3991
  code = pAggSup->stateStore.streamStateGetInfo(pAggSup->pState, STREAM_SESSION_OP_STATE_NAME,
176✔
3992
                                                strlen(STREAM_SESSION_OP_STATE_NAME), &pBuf, &size);
3993

3994
  QUERY_CHECK_CODE(code, lino, _end);
176!
3995

3996
  int32_t      num = (size - sizeof(TSKEY)) / sizeof(SSessionKey);
176✔
3997
  SSessionKey* pSeKeyBuf = (SSessionKey*)pBuf;
176✔
3998

3999
  TSKEY ts = *(TSKEY*)((char*)pBuf + size - sizeof(TSKEY));
176✔
4000
  pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, ts);
176✔
4001
  pAggSup->stateStore.streamStateReloadInfo(pAggSup->pState, ts);
176✔
4002

4003
  if (!pInfo->pStUpdated && num > 0) {
176!
4004
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
70✔
4005
    pInfo->pStUpdated = tSimpleHashInit(64, hashFn);
70✔
4006
    QUERY_CHECK_NULL(pInfo->pStUpdated, code, lino, _end, terrno);
70!
4007
  }
4008
  for (int32_t i = 0; i < num; i++) {
334✔
4009
    SResultWindowInfo winInfo = {0};
158✔
4010
    code = getSessionWindowInfoByKey(pAggSup, pSeKeyBuf + i, &winInfo);
158✔
4011
    QUERY_CHECK_CODE(code, lino, _end);
158!
4012
    if (!IS_VALID_SESSION_WIN(winInfo)) {
158!
UNCOV
4013
      continue;
×
4014
    }
4015

4016
    int32_t winNum = 0;
158✔
4017
    code = compactSessionWindow(pOperator, &winInfo, pInfo->pStUpdated, pInfo->pStDeleted, true, &winNum, NULL);
158✔
4018
    QUERY_CHECK_CODE(code, lino, _end);
158!
4019

4020
    if (winNum > 0) {
158!
UNCOV
4021
      qDebug("===stream=== reload state. save result %" PRId64 ", %" PRIu64, winInfo.sessionWin.win.skey,
×
4022
             winInfo.sessionWin.groupId);
UNCOV
4023
      if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_AT_ONCE) {
×
4024
        code = saveResult(winInfo, pInfo->pStUpdated);
×
4025
        QUERY_CHECK_CODE(code, lino, _end);
×
4026
      } else if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_WINDOW_CLOSE) {
×
4027
        if (!isCloseWindow(&winInfo.sessionWin.win, &pInfo->twAggSup)) {
×
4028
          code = saveDeleteRes(pInfo->pStDeleted, winInfo.sessionWin);
×
4029
          QUERY_CHECK_CODE(code, lino, _end);
×
4030
        }
UNCOV
4031
        SSessionKey key = {0};
×
4032
        getSessionHashKey(&winInfo.sessionWin, &key);
×
4033
        code = tSimpleHashPut(pAggSup->pResultRows, &key, sizeof(SSessionKey), &winInfo, sizeof(SResultWindowInfo));
×
4034
        QUERY_CHECK_CODE(code, lino, _end);
×
4035
      }
4036
    }
4037
    code = saveSessionOutputBuf(pAggSup, &winInfo);
158✔
4038
    QUERY_CHECK_CODE(code, lino, _end);
158!
4039
  }
4040
  taosMemoryFree(pBuf);
176!
4041

4042
  SOperatorInfo* downstream = pOperator->pDownstream[0];
176✔
4043
  if (downstream->fpSet.reloadStreamStateFn) {
176!
4044
    downstream->fpSet.reloadStreamStateFn(downstream);
176✔
4045
  }
4046
  reloadAggSupFromDownStream(downstream, &pInfo->streamAggSup);
176✔
4047

4048
_end:
176✔
4049
  if (code != TSDB_CODE_SUCCESS) {
176!
UNCOV
4050
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
4051
  }
4052
}
176✔
4053

4054
int32_t createStreamSessionAggOperatorInfo(SOperatorInfo* downstream, SPhysiNode* pPhyNode, SExecTaskInfo* pTaskInfo,
895✔
4055
                                           SReadHandle* pHandle, SOperatorInfo** pOptrInfo) {
4056
  QRY_PARAM_CHECK(pOptrInfo);
895!
4057

4058
  SSessionWinodwPhysiNode*       pSessionNode = (SSessionWinodwPhysiNode*)pPhyNode;
895✔
4059
  int32_t                        numOfCols = 0;
895✔
4060
  int32_t                        code = TSDB_CODE_OUT_OF_MEMORY;
895✔
4061
  int32_t                        lino = 0;
895✔
4062
  SStreamSessionAggOperatorInfo* pInfo = taosMemoryCalloc(1, sizeof(SStreamSessionAggOperatorInfo));
895!
4063
  SOperatorInfo*                 pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo));
895!
4064
  if (pInfo == NULL || pOperator == NULL) {
897!
UNCOV
4065
    code = terrno;
×
4066
    goto _error;
×
4067
  }
4068

4069
  pOperator->pTaskInfo = pTaskInfo;
897✔
4070

4071
  initResultSizeInfo(&pOperator->resultInfo, 4096);
897✔
4072
  if (pSessionNode->window.pExprs != NULL) {
896✔
4073
    int32_t    numOfScalar = 0;
1✔
4074
    SExprInfo* pScalarExprInfo = NULL;
1✔
4075
    code = createExprInfo(pSessionNode->window.pExprs, NULL, &pScalarExprInfo, &numOfScalar);
1✔
4076
    QUERY_CHECK_CODE(code, lino, _error);
1!
4077

4078
    code = initExprSupp(&pInfo->scalarSupp, pScalarExprInfo, numOfScalar, &pTaskInfo->storageAPI.functionStore);
1✔
4079
    if (code != TSDB_CODE_SUCCESS) {
1!
UNCOV
4080
      goto _error;
×
4081
    }
4082
  }
4083
  SExprSupp* pExpSup = &pOperator->exprSupp;
896✔
4084

4085
  SSDataBlock* pResBlock = createDataBlockFromDescNode(pPhyNode->pOutputDataBlockDesc);
896✔
4086
  QUERY_CHECK_NULL(pResBlock, code, lino, _error, terrno);
897!
4087
  pInfo->binfo.pRes = pResBlock;
897✔
4088

4089
  SExprInfo* pExprInfo = NULL;
897✔
4090
  code = createExprInfo(pSessionNode->window.pFuncs, NULL, &pExprInfo, &numOfCols);
897✔
4091
  QUERY_CHECK_CODE(code, lino, _error);
897!
4092

4093
  code = initBasicInfoEx(&pInfo->binfo, pExpSup, pExprInfo, numOfCols, pResBlock, &pTaskInfo->storageAPI.functionStore);
897✔
4094
  QUERY_CHECK_CODE(code, lino, _error);
896!
4095

4096
  pInfo->twAggSup = (STimeWindowAggSupp){
897✔
4097
      .waterMark = pSessionNode->window.watermark,
897✔
4098
      .calTrigger = pSessionNode->window.triggerType,
896✔
4099
      .maxTs = INT64_MIN,
4100
      .minTs = INT64_MAX,
4101
      .deleteMark = getDeleteMark(&pSessionNode->window, 0),
896✔
4102
  };
4103

4104
  pInfo->primaryTsIndex = ((SColumnNode*)pSessionNode->window.pTspk)->slotId;
897✔
4105
  code =
4106
      initStreamAggSupporter(&pInfo->streamAggSup, pExpSup, numOfCols, pSessionNode->gap, pTaskInfo->streamInfo.pState,
897✔
4107
                             0, 0, &pTaskInfo->storageAPI.stateStore, pHandle, &pInfo->twAggSup, GET_TASKID(pTaskInfo),
897✔
4108
                             &pTaskInfo->storageAPI, pInfo->primaryTsIndex, STREAM_STATE_BUFF_SORT, 1);
4109
  if (code != TSDB_CODE_SUCCESS) {
897!
UNCOV
4110
    goto _error;
×
4111
  }
4112

4113
  code = initExecTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &pTaskInfo->window);
897✔
4114
  QUERY_CHECK_CODE(code, lino, _error);
896!
4115

4116
  if (pSessionNode->window.pTsEnd) {
896!
4117
    pInfo->endTsIndex = ((SColumnNode*)pSessionNode->window.pTsEnd)->slotId;
897✔
4118
  }
4119

4120
  pInfo->order = TSDB_ORDER_ASC;
896✔
4121
  _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
896✔
4122
  pInfo->pStDeleted = tSimpleHashInit(64, hashFn);
897✔
4123
  QUERY_CHECK_NULL(pInfo->pStDeleted, code, lino, _error, terrno);
896!
4124
  pInfo->pDelIterator = NULL;
896✔
4125
  code = createSpecialDataBlock(STREAM_DELETE_RESULT, &pInfo->pDelRes);
896✔
4126
  QUERY_CHECK_CODE(code, lino, _error);
897!
4127

4128
  pInfo->pChildren = NULL;
897✔
4129
  pInfo->pPhyNode = pPhyNode;
897✔
4130
  pInfo->ignoreExpiredData = pSessionNode->window.igExpired;
897✔
4131
  pInfo->ignoreExpiredDataSaved = false;
897✔
4132
  pInfo->pUpdated = NULL;
897✔
4133
  pInfo->pStUpdated = NULL;
897✔
4134
  pInfo->dataVersion = 0;
897✔
4135
  pInfo->historyWins = taosArrayInit(4, sizeof(SSessionKey));
897✔
4136
  if (!pInfo->historyWins) {
897!
UNCOV
4137
    goto _error;
×
4138
  }
4139
  if (pHandle) {
897!
4140
    pInfo->isHistoryOp = (pHandle->fillHistory == STREAM_HISTORY_OPERATOR);
897✔
4141
  }
4142

4143
  code = createSpecialDataBlock(STREAM_CHECKPOINT, &pInfo->pCheckpointRes);
897✔
4144
  QUERY_CHECK_CODE(code, lino, _error);
897!
4145

4146
  pInfo->clearState = false;
897✔
4147
  pInfo->recvGetAll = false;
897✔
4148
  pInfo->destHasPrimaryKey = pSessionNode->window.destHasPrimaryKey;
897✔
4149
  pInfo->pPkDeleted = tSimpleHashInit(64, hashFn);
897✔
4150
  QUERY_CHECK_NULL(pInfo->pPkDeleted, code, lino, _error, terrno);
897!
4151
  pInfo->pOperator = pOperator;
897✔
4152
  initNonBlockAggSupptor(&pInfo->nbSup, NULL, NULL);
897✔
4153

4154
  setOperatorInfo(pOperator, getStreamOpName(pOperator->operatorType), nodeType(pSessionNode), true,
895✔
4155
                  OP_NOT_OPENED, pInfo, pTaskInfo);
4156
  if (pPhyNode->type != QUERY_NODE_PHYSICAL_PLAN_STREAM_FINAL_SESSION) {
896✔
4157
    // for stream
4158
    void*   buff = NULL;
738✔
4159
    int32_t len = 0;
738✔
4160
    int32_t res =
4161
        pInfo->streamAggSup.stateStore.streamStateGetInfo(pInfo->streamAggSup.pState, STREAM_SESSION_OP_CHECKPOINT_NAME,
738✔
4162
                                                          strlen(STREAM_SESSION_OP_CHECKPOINT_NAME), &buff, &len);
4163
    if (res == TSDB_CODE_SUCCESS) {
738!
UNCOV
4164
      code = doStreamSessionDecodeOpState(buff, len, pOperator, true, NULL);
×
4165
      taosMemoryFree(buff);
×
4166
      QUERY_CHECK_CODE(code, lino, _error);
×
4167
    }
4168
  }
4169

4170
  code = initStreamBasicInfo(&pInfo->basic, pOperator);
896✔
4171
  QUERY_CHECK_CODE(code, lino, _error);
897!
4172

4173
  if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_CONTINUOUS_WINDOW_CLOSE) {
897!
UNCOV
4174
    if (pHandle->fillHistory == STREAM_HISTORY_OPERATOR) {
×
4175
      setFillHistoryOperatorFlag(&pInfo->basic);
×
4176
    } else if (pHandle->fillHistory == STREAM_RECALCUL_OPERATOR) {
×
4177
      setRecalculateOperatorFlag(&pInfo->basic);
×
4178
    }
4179
    pOperator->fpSet =
UNCOV
4180
        createOperatorFpSet(optrDummyOpenFn, doStreamSessionNonblockAggNext, NULL, destroyStreamSessionAggOperatorInfo,
×
4181
                            optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
UNCOV
4182
    setOperatorStreamStateFn(pOperator, streamSessionNonblockReleaseState, streamSessionNonblockReloadState);
×
4183
  } else {
4184
    pOperator->fpSet =
4185
        createOperatorFpSet(optrDummyOpenFn, doStreamSessionAggNext, NULL, destroyStreamSessionAggOperatorInfo,
897✔
4186
                            optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
4187
    setOperatorStreamStateFn(pOperator, streamSessionReleaseState, streamSessionReloadState);
897✔
4188
  }
4189

4190
  if (downstream) {
897✔
4191
    pInfo->basic.primaryPkIndex = -1;
776✔
4192
    code = initDownStream(downstream, &pInfo->streamAggSup, pOperator->operatorType, pInfo->primaryTsIndex,
776✔
4193
                          &pInfo->twAggSup, &pInfo->basic, pSessionNode->window.recalculateInterval);
776✔
4194
    QUERY_CHECK_CODE(code, lino, _error);
776!
4195

4196
    code = appendDownstream(pOperator, &downstream, 1);
776✔
4197
    QUERY_CHECK_CODE(code, lino, _error);
776!
4198
  }
4199

4200
  *pOptrInfo = pOperator;
897✔
4201
  return TSDB_CODE_SUCCESS;
897✔
4202

UNCOV
4203
_error:
×
4204
  if (pInfo != NULL) {
×
4205
    destroyStreamSessionAggOperatorInfo(pInfo);
×
4206
  }
UNCOV
4207
  destroyOperatorAndDownstreams(pOperator, &downstream, 1);
×
4208
  pTaskInfo->code = code;
×
4209
  qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
4210
  return code;
×
4211
}
4212

4213
static void clearStreamSessionOperator(SStreamSessionAggOperatorInfo* pInfo) {
492✔
4214
  tSimpleHashClear(pInfo->streamAggSup.pResultRows);
492✔
4215
  pInfo->streamAggSup.stateStore.streamStateSessionClear(pInfo->streamAggSup.pState);
493✔
4216
  pInfo->clearState = false;
494✔
4217
}
494✔
4218

4219
int32_t deleteSessionWinState(SStreamAggSupporter* pAggSup, SSDataBlock* pBlock, SSHashObj* pMapUpdate,
617✔
4220
                              SSHashObj* pMapDelete, SSHashObj* pPkDelete, bool needAdd) {
4221
  int32_t code = TSDB_CODE_SUCCESS;
617✔
4222
  int32_t lino = 0;
617✔
4223
  SArray* pWins = taosArrayInit(16, sizeof(SSessionKey));
617✔
4224
  if (!pWins) {
617!
UNCOV
4225
    code = terrno;
×
4226
    QUERY_CHECK_CODE(code, lino, _end);
×
4227
  }
4228
  code = doDeleteTimeWindows(pAggSup, pBlock, pWins);
617✔
4229
  QUERY_CHECK_CODE(code, lino, _end);
617!
4230

4231
  removeSessionResults(pAggSup, pMapUpdate, pWins);
617✔
4232
  code = copyDeleteWindowInfo(pWins, pMapDelete);
617✔
4233
  QUERY_CHECK_CODE(code, lino, _end);
617!
4234

4235
  if (needAdd) {
617!
UNCOV
4236
    code = copyDeleteWindowInfo(pWins, pPkDelete);
×
4237
    QUERY_CHECK_CODE(code, lino, _end);
×
4238
  }
4239
  taosArrayDestroy(pWins);
617✔
4240

4241
_end:
617✔
4242
  if (code != TSDB_CODE_SUCCESS) {
617!
UNCOV
4243
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
4244
  }
4245
  return code;
617✔
4246
}
4247

4248
static int32_t doStreamSessionSemiAggNext(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
917✔
4249
  int32_t                        code = TSDB_CODE_SUCCESS;
917✔
4250
  int32_t                        lino = 0;
917✔
4251
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
917✔
4252
  SOptrBasicInfo*                pBInfo = &pInfo->binfo;
917✔
4253
  TSKEY                          maxTs = INT64_MIN;
917✔
4254
  SExprSupp*                     pSup = &pOperator->exprSupp;
917✔
4255
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
917✔
4256
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
917✔
4257

4258
  qDebug("stask:%s  %s status: %d", GET_TASKID(pTaskInfo), getStreamOpName(pOperator->operatorType), pOperator->status);
917✔
4259
  if (pOperator->status == OP_EXEC_DONE) {
917!
UNCOV
4260
    (*ppRes) = NULL;
×
4261
    return code;
×
4262
  }
4263

4264
  {
4265
    SSDataBlock* opRes = NULL;
917✔
4266
    code = buildSessionResult(pOperator, &opRes);
917✔
4267
    QUERY_CHECK_CODE(code, lino, _end);
914!
4268
    if (opRes) {
914✔
4269
      (*ppRes) = opRes;
89✔
4270
      return code;
227✔
4271
    }
4272

4273
    if (pInfo->clearState) {
825✔
4274
      clearFunctionContext(&pOperator->exprSupp);
54✔
4275
      // semi session operator clear disk buffer
4276
      clearStreamSessionOperator(pInfo);
54✔
4277
    }
4278

4279
    if (pOperator->status == OP_RES_TO_RETURN) {
825✔
4280
      if (pInfo->reCkBlock) {
138!
UNCOV
4281
        pInfo->reCkBlock = false;
×
4282
        printDataBlock(pInfo->pCheckpointRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
4283
        (*ppRes) = pInfo->pCheckpointRes;
×
4284
        return code;
×
4285
      }
4286
      clearFunctionContext(&pOperator->exprSupp);
138✔
4287
      // semi session operator clear disk buffer
4288
      clearStreamSessionOperator(pInfo);
138✔
4289
      setStreamOperatorCompleted(pOperator);
138✔
4290
      (*ppRes) = NULL;
138✔
4291
      return code;
138✔
4292
    }
4293
  }
4294

4295
  SOperatorInfo* downstream = pOperator->pDownstream[0];
687✔
4296
  if (!pInfo->pUpdated) {
687✔
4297
    pInfo->pUpdated = taosArrayInit(16, sizeof(SResultWindowInfo));
492✔
4298
    QUERY_CHECK_NULL(pInfo->pUpdated, code, lino, _end, terrno);
493!
4299
  }
4300
  if (!pInfo->pStUpdated) {
688✔
4301
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
493✔
4302
    pInfo->pStUpdated = tSimpleHashInit(64, hashFn);
493✔
4303
    QUERY_CHECK_NULL(pInfo->pStUpdated, code, lino, _end, terrno);
494!
4304
  }
4305
  while (1) {
358✔
4306
    SSDataBlock* pBlock = NULL;
1,047✔
4307
    code = downstream->fpSet.getNextFn(downstream, &pBlock);
1,047✔
4308
    QUERY_CHECK_CODE(code, lino, _end);
1,048!
4309

4310
    if (pBlock == NULL) {
1,048✔
4311
      pOperator->status = OP_RES_TO_RETURN;
440✔
4312
      break;
440✔
4313
    }
4314
    printSpecDataBlock(pBlock, getStreamOpName(pOperator->operatorType), "recv", GET_TASKID(pTaskInfo));
608✔
4315
    setStreamOperatorState(&pInfo->basic, pBlock->info.type);
608✔
4316

4317
    if (pBlock->info.type == STREAM_DELETE_DATA || pBlock->info.type == STREAM_DELETE_RESULT ||
608✔
4318
        pBlock->info.type == STREAM_CLEAR) {
559✔
4319
      // gap must be 0
4320
      code = deleteSessionWinState(pAggSup, pBlock, pInfo->pStUpdated, pInfo->pStDeleted, NULL, false);
54✔
4321
      QUERY_CHECK_CODE(code, lino, _end);
54!
4322
      pInfo->clearState = true;
54✔
4323
      break;
54✔
4324
    } else if (pBlock->info.type == STREAM_GET_ALL) {
554!
UNCOV
4325
      code = getAllSessionWindow(pInfo->streamAggSup.pResultRows, pInfo->pStUpdated);
×
4326
      QUERY_CHECK_CODE(code, lino, _end);
×
4327
      continue;
15✔
4328
    } else if (pBlock->info.type == STREAM_CREATE_CHILD_TABLE) {
554✔
4329
      (*ppRes) = pBlock;
196✔
4330
      return code;
196✔
4331
    } else if (pBlock->info.type == STREAM_CHECKPOINT) {
358✔
4332
      pAggSup->stateStore.streamStateCommit(pAggSup->pState);
15✔
4333
      doStreamSessionSaveCheckpoint(pOperator);
15✔
4334
      continue;
15✔
4335
    } else {
4336
      if (pBlock->info.type != STREAM_NORMAL && pBlock->info.type != STREAM_INVALID) {
343!
UNCOV
4337
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
4338
        QUERY_CHECK_CODE(code, lino, _end);
×
4339
      }
4340
    }
4341

4342
    if (pInfo->scalarSupp.pExprInfo != NULL) {
343!
UNCOV
4343
      SExprSupp* pExprSup = &pInfo->scalarSupp;
×
4344
      code = projectApplyFunctions(pExprSup->pExprInfo, pBlock, pBlock, pExprSup->pCtx, pExprSup->numOfExprs, NULL);
×
4345
      QUERY_CHECK_CODE(code, lino, _end);
×
4346
    }
4347
    // the pDataBlock are always the same one, no need to call this again
4348
    code = setInputDataBlock(pSup, pBlock, TSDB_ORDER_ASC, MAIN_SCAN, true);
343✔
4349
    QUERY_CHECK_CODE(code, lino, _end);
343!
4350
    doStreamSessionAggImpl(pOperator, pBlock, pInfo->pStUpdated, NULL, false, false);
343✔
4351
    maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.window.ekey);
343✔
4352
  }
4353

4354
  pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, maxTs);
494✔
4355
  pBInfo->pRes->info.watermark = pInfo->twAggSup.maxTs;
494✔
4356

4357
  code = copyUpdateResult(&pInfo->pStUpdated, pInfo->pUpdated, sessionKeyCompareAsc);
494✔
4358
  QUERY_CHECK_CODE(code, lino, _end);
494!
4359

4360
  removeSessionDeleteResults(pInfo->pStDeleted, pInfo->pUpdated);
494✔
4361

4362
  if (pInfo->isHistoryOp) {
494✔
4363
    code = getMaxTsWins(pInfo->pUpdated, pInfo->historyWins);
15✔
4364
    QUERY_CHECK_CODE(code, lino, _end);
15!
4365
  }
4366

4367
  initGroupResInfoFromArrayList(&pInfo->groupResInfo, pInfo->pUpdated);
494✔
4368
  pInfo->pUpdated = NULL;
494✔
4369
  code = blockDataEnsureCapacity(pBInfo->pRes, pOperator->resultInfo.capacity);
494✔
4370
  QUERY_CHECK_CODE(code, lino, _end);
494!
4371

4372
  SSDataBlock* opRes = NULL;
494✔
4373
  code = buildSessionResult(pOperator, &opRes);
494✔
4374
  QUERY_CHECK_CODE(code, lino, _end);
494!
4375
  if (opRes) {
494✔
4376
    (*ppRes) = opRes;
192✔
4377
    return code;
192✔
4378
  }
4379

4380
_end:
302✔
4381
  if (code != TSDB_CODE_SUCCESS) {
302!
UNCOV
4382
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
4383
    pTaskInfo->code = code;
×
4384
    T_LONG_JMP(pTaskInfo->env, code);
×
4385
  }
4386

4387
  clearFunctionContext(&pOperator->exprSupp);
302✔
4388
  // semi session operator clear disk buffer
4389
  clearStreamSessionOperator(pInfo);
299✔
4390
  setStreamOperatorCompleted(pOperator);
302✔
4391
  (*ppRes) = NULL;
300✔
4392
  return code;
300✔
4393
}
4394

UNCOV
4395
static SSDataBlock* doStreamSessionSemiAgg(SOperatorInfo* pOperator) {
×
4396
  SSDataBlock* pRes = NULL;
×
4397
  int32_t      code = doStreamSessionSemiAggNext(pOperator, &pRes);
×
4398
  return pRes;
×
4399
}
4400

4401
int32_t createStreamFinalSessionAggOperatorInfo(SOperatorInfo* downstream, SPhysiNode* pPhyNode,
279✔
4402
                                                SExecTaskInfo* pTaskInfo, int32_t numOfChild, SReadHandle* pHandle,
4403
                                                SOperatorInfo** pOptrInfo) {
4404
  QRY_PARAM_CHECK(pOptrInfo);
279!
4405

4406
  int32_t        code = TSDB_CODE_SUCCESS;
279✔
4407
  int32_t        lino = 0;
279✔
4408
  SOperatorInfo* pOperator = NULL;
279✔
4409
  code = createStreamSessionAggOperatorInfo(downstream, pPhyNode, pTaskInfo, pHandle, &pOperator);
279✔
4410
  if (pOperator == NULL || code != 0) {
279!
UNCOV
4411
    downstream = NULL;
×
4412
    QUERY_CHECK_CODE(code, lino, _error);
×
4413
  }
4414

4415
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
279✔
4416
  pInfo->pOperator = pOperator;
279✔
4417

4418
  if (pPhyNode->type != QUERY_NODE_PHYSICAL_PLAN_STREAM_FINAL_SESSION) {
279✔
4419
    pOperator->fpSet =
121✔
4420
        createOperatorFpSet(optrDummyOpenFn, doStreamSessionSemiAggNext, NULL, destroyStreamSessionAggOperatorInfo,
121✔
4421
                            optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
4422
    setOperatorStreamStateFn(pOperator, streamSessionReleaseState, streamSessionSemiReloadState);
121✔
4423
  }
4424

4425
  if (numOfChild > 0) {
279✔
4426
    pInfo->pChildren = taosArrayInit(numOfChild, sizeof(void*));
37✔
4427
    QUERY_CHECK_NULL(pInfo->pChildren, code, lino, _error, terrno);
37!
4428
    for (int32_t i = 0; i < numOfChild; i++) {
158✔
4429
      SOperatorInfo* pChildOp = NULL;
121✔
4430
      code = createStreamFinalSessionAggOperatorInfo(NULL, pPhyNode, pTaskInfo, 0, pHandle, &pChildOp);
121✔
4431
      if (pChildOp == NULL || code != 0) {
121!
UNCOV
4432
        QUERY_CHECK_CODE(code, lino, _error);
×
4433
      }
4434

4435
      SStreamSessionAggOperatorInfo* pChInfo = pChildOp->info;
121✔
4436
      pChInfo->twAggSup.calTrigger = STREAM_TRIGGER_AT_ONCE;
121✔
4437
      pTaskInfo->storageAPI.stateStore.streamStateSetNumber(pChInfo->streamAggSup.pState, i, pInfo->primaryTsIndex);
121✔
4438
      void* tmp = taosArrayPush(pInfo->pChildren, &pChildOp);
121✔
4439
      if (!tmp) {
121!
UNCOV
4440
        code = terrno;
×
4441
        QUERY_CHECK_CODE(code, lino, _error);
×
4442
      }
4443
    }
4444

4445
    void*   buff = NULL;
37✔
4446
    int32_t len = 0;
37✔
4447
    int32_t res =
4448
        pInfo->streamAggSup.stateStore.streamStateGetInfo(pInfo->streamAggSup.pState, STREAM_SESSION_OP_CHECKPOINT_NAME,
37✔
4449
                                                          strlen(STREAM_SESSION_OP_CHECKPOINT_NAME), &buff, &len);
4450
    if (res == TSDB_CODE_SUCCESS) {
37!
UNCOV
4451
      code = doStreamSessionDecodeOpState(buff, len, pOperator, true, NULL);
×
4452
      taosMemoryFree(buff);
×
4453
      QUERY_CHECK_CODE(code, lino, _error);
×
4454
    }
4455
  }
4456

4457
  if (!IS_FINAL_SESSION_OP(pOperator) || numOfChild == 0) {
279✔
4458
    pInfo->twAggSup.calTrigger = STREAM_TRIGGER_AT_ONCE;
242✔
4459
  }
4460

4461
  *pOptrInfo = pOperator;
279✔
4462
  return code;
279✔
4463

UNCOV
4464
_error:
×
4465
  if (pInfo != NULL) {
×
4466
    destroyStreamSessionAggOperatorInfo(pInfo);
×
4467
  }
UNCOV
4468
  if (pOperator != NULL) {
×
4469
    pOperator->info = NULL;
×
4470
    destroyOperator(pOperator);
×
4471
  }
UNCOV
4472
  pTaskInfo->code = code;
×
4473
  if (code != TSDB_CODE_SUCCESS) {
×
4474
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
4475
  }
UNCOV
4476
  return code;
×
4477
}
4478

4479
void destroyStreamStateOperatorInfo(void* param) {
349✔
4480
  if (param == NULL) {
349!
UNCOV
4481
    return;
×
4482
  }
4483
  SStreamStateAggOperatorInfo* pInfo = (SStreamStateAggOperatorInfo*)param;
349✔
4484
  cleanupBasicInfo(&pInfo->binfo);
349✔
4485
  if (pInfo->pOperator) {
349!
4486
    cleanupResultInfoInStream(pInfo->pOperator->pTaskInfo, pInfo->streamAggSup.pState, &pInfo->pOperator->exprSupp,
349✔
4487
                              &pInfo->groupResInfo);
4488
    pInfo->pOperator = NULL;
349✔
4489
  }
4490

4491
  destroyStreamBasicInfo(&pInfo->basic);
349✔
4492
  clearSessionGroupResInfo(&pInfo->groupResInfo);
349✔
4493
  taosArrayDestroyEx(pInfo->pUpdated, destroyResultWinInfo);
349✔
4494
  pInfo->pUpdated = NULL;
349✔
4495
  destroyStreamAggSupporter(&pInfo->streamAggSup);
349✔
4496

4497
  cleanupExprSupp(&pInfo->scalarSupp);
349✔
4498
  if (pInfo->pChildren != NULL) {
349!
UNCOV
4499
    int32_t size = taosArrayGetSize(pInfo->pChildren);
×
4500
    for (int32_t i = 0; i < size; i++) {
×
4501
      SOperatorInfo* pChild = taosArrayGetP(pInfo->pChildren, i);
×
4502
      destroyOperator(pChild);
×
4503
    }
UNCOV
4504
    taosArrayDestroy(pInfo->pChildren);
×
4505
  }
4506
  colDataDestroy(&pInfo->twAggSup.timeWindowData);
349✔
4507
  blockDataDestroy(pInfo->pDelRes);
349✔
4508
  tSimpleHashCleanup(pInfo->pSeUpdated);
349✔
4509
  tSimpleHashCleanup(pInfo->pSeDeleted);
349✔
4510
  cleanupGroupResInfo(&pInfo->groupResInfo);
349✔
4511

4512
  taosArrayDestroy(pInfo->historyWins);
349✔
4513
  blockDataDestroy(pInfo->pCheckpointRes);
349✔
4514
  tSimpleHashCleanup(pInfo->pPkDeleted);
349✔
4515
  destroyNonBlockAggSupptor(&pInfo->nbSup);
349✔
4516

4517
  taosMemoryFreeClear(param);
349!
4518
}
4519

4520
bool isTsInWindow(SStateWindowInfo* pWin, TSKEY ts) {
3,902✔
4521
  if (pWin->winInfo.sessionWin.win.skey <= ts && ts <= pWin->winInfo.sessionWin.win.ekey) {
3,902✔
4522
    return true;
1,246✔
4523
  }
4524
  return false;
2,656✔
4525
}
4526

4527
bool isEqualStateKey(SStateWindowInfo* pWin, char* pKeyData) {
6,450✔
4528
  return pKeyData && compareVal(pKeyData, pWin->pStateKey);
6,450!
4529
}
4530

4531
bool compareStateKey(void* data, void* key) {
2,524✔
4532
  if (!data || !key) {
2,524!
UNCOV
4533
    return true;
×
4534
  }
4535
  SStateKeys* stateKey = (SStateKeys*)key;
2,524✔
4536
  stateKey->pData = (char*)key + sizeof(SStateKeys);
2,524✔
4537
  return compareVal(data, stateKey);
2,524✔
4538
}
4539

4540
bool compareWinStateKey(SStateKeys* left, SStateKeys* right) {
129✔
4541
  if (!left || !right) {
129!
4542
    return false;
129✔
4543
  }
UNCOV
4544
  return compareVal(left->pData, right);
×
4545
}
4546

4547
void getNextStateWin(const SStreamAggSupporter* pAggSup, SStateWindowInfo* pNextWin, bool asc) {
3,319✔
4548
  SStreamStateCur* pCur = NULL;
3,319✔
4549

4550
  if (pAggSup == NULL || pNextWin == NULL) {
3,319!
UNCOV
4551
    return;
×
4552
  }
4553

4554
  if (asc)
3,319!
4555
    pCur = pAggSup->stateStore.streamStateSessionSeekKeyNext(pAggSup->pState, &pNextWin->winInfo.sessionWin);
3,319✔
4556
  else
UNCOV
4557
    pCur = pAggSup->stateStore.streamStateSessionSeekKeyPrev(pAggSup->pState, &pNextWin->winInfo.sessionWin);
×
4558
  int32_t nextSize = pAggSup->resultRowSize;
3,318✔
4559
  int32_t winCode = pAggSup->stateStore.streamStateSessionGetKVByCur(pCur, &pNextWin->winInfo.sessionWin,
3,318✔
4560
                                                                     (void**)&pNextWin->winInfo.pStatePos, &nextSize);
3,318✔
4561
  if (winCode != TSDB_CODE_SUCCESS) {
3,319✔
4562
    SET_SESSION_WIN_INVALID(pNextWin->winInfo);
3,207✔
4563
  } else {
4564
    pNextWin->pStateKey =
112✔
4565
        (SStateKeys*)((char*)pNextWin->winInfo.pStatePos->pRowBuff + (pAggSup->resultRowSize - pAggSup->stateKeySize));
112✔
4566
    pNextWin->pStateKey->bytes = pAggSup->stateKeySize - sizeof(SStateKeys);
112✔
4567
    pNextWin->pStateKey->type = pAggSup->stateKeyType;
112✔
4568
    pNextWin->pStateKey->pData = (char*)pNextWin->pStateKey + sizeof(SStateKeys);
112✔
4569
    pNextWin->pStateKey->isNull = false;
112✔
4570
    pNextWin->winInfo.isOutput = true;
112✔
4571
  }
4572
  pAggSup->stateStore.streamStateFreeCur(pCur);
3,319✔
4573
}
4574

4575
int32_t getStateWindowInfoByKey(SStreamAggSupporter* pAggSup, SSessionKey* pKey, SStateWindowInfo* pCurWin,
129✔
4576
                                SStateWindowInfo* pNextWin) {
4577
  int32_t code = TSDB_CODE_SUCCESS;
129✔
4578
  int32_t lino = 0;
129✔
4579
  int32_t size = pAggSup->resultRowSize;
129✔
4580
  pCurWin->winInfo.sessionWin.groupId = pKey->groupId;
129✔
4581
  pCurWin->winInfo.sessionWin.win.skey = pKey->win.skey;
129✔
4582
  pCurWin->winInfo.sessionWin.win.ekey = pKey->win.ekey;
129✔
4583
  code = getSessionWindowInfoByKey(pAggSup, pKey, &pCurWin->winInfo);
129✔
4584
  QUERY_CHECK_CODE(code, lino, _end);
129!
4585
  QUERY_CHECK_CONDITION((IS_VALID_SESSION_WIN(pCurWin->winInfo)), code, lino, _end,
129!
4586
                        TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR);
4587

4588
  pCurWin->pStateKey =
129✔
4589
      (SStateKeys*)((char*)pCurWin->winInfo.pStatePos->pRowBuff + (pAggSup->resultRowSize - pAggSup->stateKeySize));
129✔
4590
  pCurWin->pStateKey->bytes = pAggSup->stateKeySize - sizeof(SStateKeys);
129✔
4591
  pCurWin->pStateKey->type = pAggSup->stateKeyType;
129✔
4592
  pCurWin->pStateKey->pData = (char*)pCurWin->pStateKey + sizeof(SStateKeys);
129✔
4593
  pCurWin->pStateKey->isNull = false;
129✔
4594
  pCurWin->winInfo.isOutput = true;
129✔
4595
  if (pCurWin->winInfo.pStatePos->needFree) {
129!
4596
    pAggSup->stateStore.streamStateSessionDel(pAggSup->pState, &pCurWin->winInfo.sessionWin);
129✔
4597
  }
4598

4599
  qDebug("===stream===get state cur win buff. skey:%" PRId64 ", endkey:%" PRId64, pCurWin->winInfo.sessionWin.win.skey,
129✔
4600
         pCurWin->winInfo.sessionWin.win.ekey);
4601

4602
  pNextWin->winInfo.sessionWin = pCurWin->winInfo.sessionWin;
129✔
4603
  getNextStateWin(pAggSup, pNextWin, true);
129✔
4604

4605
_end:
129✔
4606
  qDebug("===stream===get state next win buff. skey:%" PRId64 ", endkey:%" PRId64,
129✔
4607
         pNextWin->winInfo.sessionWin.win.skey, pNextWin->winInfo.sessionWin.win.ekey);
4608
  if (code != TSDB_CODE_SUCCESS) {
129!
UNCOV
4609
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
4610
  }
4611
  return code;
129✔
4612
}
4613

4614
int32_t setStateOutputBuf(SStreamAggSupporter* pAggSup, TSKEY ts, uint64_t groupId, char* pKeyData,
3,190✔
4615
                          SStateWindowInfo* pCurWin, SStateWindowInfo* pNextWin, int32_t* pWinCode) {
4616
  int32_t size = pAggSup->resultRowSize;
3,190✔
4617
  pCurWin->winInfo.sessionWin.groupId = groupId;
3,190✔
4618
  pCurWin->winInfo.sessionWin.win.skey = ts;
3,190✔
4619
  pCurWin->winInfo.sessionWin.win.ekey = ts;
3,190✔
4620
  int32_t code = TSDB_CODE_SUCCESS;
3,190✔
4621
  int32_t lino = 0;
3,190✔
4622
  int32_t winCode = TSDB_CODE_SUCCESS;
3,190✔
4623
  code = pAggSup->stateStore.streamStateStateAddIfNotExist(pAggSup->pState, &pCurWin->winInfo.sessionWin, pKeyData,
3,190✔
4624
                                                           pAggSup->stateKeySize, compareStateKey,
4625
                                                           (void**)&pCurWin->winInfo.pStatePos, &size, &winCode);
3,190✔
4626
  QUERY_CHECK_CODE(code, lino, _end);
3,190!
4627

4628
  pCurWin->pStateKey =
3,190✔
4629
      (SStateKeys*)((char*)pCurWin->winInfo.pStatePos->pRowBuff + (pAggSup->resultRowSize - pAggSup->stateKeySize));
3,190✔
4630
  pCurWin->pStateKey->bytes = pAggSup->stateKeySize - sizeof(SStateKeys);
3,190✔
4631
  pCurWin->pStateKey->type = pAggSup->stateKeyType;
3,190✔
4632
  pCurWin->pStateKey->pData = (char*)pCurWin->pStateKey + sizeof(SStateKeys);
3,190✔
4633
  pCurWin->pStateKey->isNull = false;
3,190✔
4634

4635
  if (winCode == TSDB_CODE_SUCCESS && !inWinRange(&pAggSup->winRange, &pCurWin->winInfo.sessionWin.win)) {
3,190!
UNCOV
4636
    winCode = TSDB_CODE_FAILED;
×
4637
    clearOutputBuf(pAggSup->pState, pCurWin->winInfo.pStatePos, &pAggSup->pSessionAPI->stateStore);
×
4638
    pCurWin->pStateKey =
×
4639
        (SStateKeys*)((char*)pCurWin->winInfo.pStatePos->pRowBuff + (pAggSup->resultRowSize - pAggSup->stateKeySize));
×
4640
    pCurWin->pStateKey->bytes = pAggSup->stateKeySize - sizeof(SStateKeys);
×
4641
    pCurWin->pStateKey->type = pAggSup->stateKeyType;
×
4642
    pCurWin->pStateKey->pData = (char*)pCurWin->pStateKey + sizeof(SStateKeys);
×
4643
    pCurWin->pStateKey->isNull = false;
×
4644
    pCurWin->winInfo.sessionWin.groupId = groupId;
×
4645
    pCurWin->winInfo.sessionWin.win.skey = ts;
×
4646
    pCurWin->winInfo.sessionWin.win.ekey = ts;
×
4647
    qDebug("===stream===reset state win key. skey:%" PRId64 ", endkey:%" PRId64, pCurWin->winInfo.sessionWin.win.skey,
×
4648
           pCurWin->winInfo.sessionWin.win.ekey);
4649
  }
4650

4651
  if (winCode == TSDB_CODE_SUCCESS) {
3,190✔
4652
    pCurWin->winInfo.isOutput = true;
1,991✔
4653
    if (pCurWin->winInfo.pStatePos->needFree) {
1,991✔
4654
      pAggSup->stateStore.streamStateSessionDel(pAggSup->pState, &pCurWin->winInfo.sessionWin);
34✔
4655
    }
4656
  } else if (pKeyData) {
1,199!
4657
    if (IS_VAR_DATA_TYPE(pAggSup->stateKeyType)) {
1,199!
4658
      varDataCopy(pCurWin->pStateKey->pData, pKeyData);
4✔
4659
    } else {
4660
      memcpy(pCurWin->pStateKey->pData, pKeyData, pCurWin->pStateKey->bytes);
1,195✔
4661
    }
4662
  }
4663

4664
  *pWinCode = winCode;
3,190✔
4665

4666
  qDebug("===stream===set state cur win buff. skey:%" PRId64 ", endkey:%" PRId64, pCurWin->winInfo.sessionWin.win.skey,
3,190✔
4667
         pCurWin->winInfo.sessionWin.win.ekey);
4668

4669
  pNextWin->winInfo.sessionWin = pCurWin->winInfo.sessionWin;
3,190✔
4670
  getNextStateWin(pAggSup, pNextWin, true);
3,190✔
4671
  qDebug("===stream===set state next win buff. skey:%" PRId64 ", endkey:%" PRId64,
3,190✔
4672
         pNextWin->winInfo.sessionWin.win.skey, pNextWin->winInfo.sessionWin.win.ekey);
4673
_end:
1,539✔
4674
  if (code != TSDB_CODE_SUCCESS) {
3,190!
UNCOV
4675
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
4676
  }
4677
  return code;
3,190✔
4678
}
4679

4680
int32_t updateStateWindowInfo(SStreamAggSupporter* pAggSup, SStateWindowInfo* pWinInfo, SStateWindowInfo* pNextWin,
3,190✔
4681
                              TSKEY* pTs, uint64_t groupId, SColumnInfoData* pKeyCol, int32_t rows, int32_t start,
4682
                              bool* allEqual, SSHashObj* pResultRows, SSHashObj* pSeUpdated, SSHashObj* pSeDeleted,
4683
                              int32_t* pWinRows) {
4684
  int32_t code = TSDB_CODE_SUCCESS;
3,190✔
4685
  int32_t lino = 0;
3,190✔
4686
  *allEqual = true;
3,190✔
4687
  for (int32_t i = start; i < rows; ++i) {
6,984✔
4688
    char* pKeyData = colDataGetData(pKeyCol, i);
3,903!
4689
    if (!isTsInWindow(pWinInfo, pTs[i])) {
3,903✔
4690
      if (isEqualStateKey(pWinInfo, pKeyData)) {
2,657✔
4691
        if (IS_VALID_SESSION_WIN(pNextWin->winInfo)) {
2,548✔
4692
          // ts belongs to the next window
4693
          if (pTs[i] >= pNextWin->winInfo.sessionWin.win.skey) {
87!
UNCOV
4694
            (*pWinRows) = i - start;
×
4695
            goto _end;
×
4696
          }
4697
        }
4698
      } else {
4699
        (*pWinRows) = i - start;
108✔
4700
        goto _end;
108✔
4701
      }
4702
    }
4703

4704
    if (pWinInfo->winInfo.sessionWin.win.skey > pTs[i]) {
3,794✔
4705
      if (pSeDeleted && pWinInfo->winInfo.isOutput) {
6!
4706
        code = saveDeleteRes(pSeDeleted, pWinInfo->winInfo.sessionWin);
6✔
4707
        QUERY_CHECK_CODE(code, lino, _end);
6!
4708
      }
4709
      removeSessionResult(pAggSup, pSeUpdated, pResultRows, &pWinInfo->winInfo.sessionWin);
6✔
4710
      pWinInfo->winInfo.sessionWin.win.skey = pTs[i];
6✔
4711
    }
4712
    pWinInfo->winInfo.sessionWin.win.ekey = TMAX(pWinInfo->winInfo.sessionWin.win.ekey, pTs[i]);
3,794✔
4713
    memcpy(pWinInfo->winInfo.pStatePos->pKey, &pWinInfo->winInfo.sessionWin, sizeof(SSessionKey));
3,794✔
4714
    if (!isEqualStateKey(pWinInfo, pKeyData)) {
3,794✔
4715
      *allEqual = false;
24✔
4716
    }
4717
  }
4718
  (*pWinRows) = rows - start;
3,081✔
4719

4720
_end:
3,189✔
4721
  if (code != TSDB_CODE_SUCCESS) {
3,189!
UNCOV
4722
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
4723
  }
4724
  return code;
3,189✔
4725
}
4726

4727
static bool isWinResult(SSessionKey* pKey, SSHashObj* pSeUpdate, SSHashObj* pResults) {
3,190✔
4728
  SSessionKey checkKey = {0};
3,190✔
4729
  getSessionHashKey(pKey, &checkKey);
3,190✔
4730
  if (tSimpleHashGet(pSeUpdate, &checkKey, sizeof(SSessionKey)) != NULL) {
3,190✔
4731
    return true;
28✔
4732
  }
4733

4734
  if (tSimpleHashGet(pResults, &checkKey, sizeof(SSessionKey)) != NULL) {
3,162✔
4735
    return true;
17✔
4736
  }
4737
  return false;
3,145✔
4738
}
4739

4740
static void doStreamStateAggImpl(SOperatorInfo* pOperator, SSDataBlock* pSDataBlock, SSHashObj* pSeUpdated,
3,093✔
4741
                                 SSHashObj* pStDeleted) {
4742
  SExecTaskInfo* pTaskInfo = pOperator->pTaskInfo;
3,093✔
4743
  SStorageAPI*   pAPI = &pOperator->pTaskInfo->storageAPI;
3,093✔
4744

4745
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
3,093✔
4746
  int32_t                      numOfOutput = pOperator->exprSupp.numOfExprs;
3,093✔
4747
  uint64_t                     groupId = pSDataBlock->info.id.groupId;
3,093✔
4748
  int32_t                      code = TSDB_CODE_SUCCESS;
3,093✔
4749
  int32_t                      lino = 0;
3,093✔
4750
  TSKEY*                       tsCols = NULL;
3,093✔
4751
  SResultRow*                  pResult = NULL;
3,093✔
4752
  int32_t                      winRows = 0;
3,093✔
4753
  SStreamAggSupporter*         pAggSup = &pInfo->streamAggSup;
3,093✔
4754
  SStreamNotifyEventSupp*      pNotifySup = &pInfo->basic.notifyEventSup;
3,093✔
4755
  STaskNotifyEventStat*        pNotifyEventStat = pTaskInfo->streamInfo.pNotifyEventStat;
3,093✔
4756

4757
  pInfo->dataVersion = TMAX(pInfo->dataVersion, pSDataBlock->info.version);
3,093✔
4758
  pAggSup->winRange = pTaskInfo->streamInfo.fillHistoryWindow;
3,093✔
4759
  if (pAggSup->winRange.ekey <= 0) {
3,093!
UNCOV
4760
    pAggSup->winRange.ekey = INT64_MAX;
×
4761
  }
4762

4763
  if (pSDataBlock->pDataBlock != NULL) {
3,093!
4764
    SColumnInfoData* pColDataInfo = taosArrayGet(pSDataBlock->pDataBlock, pInfo->primaryTsIndex);
3,093✔
4765
    if (!pColDataInfo) {
3,093!
UNCOV
4766
      code = TSDB_CODE_FAILED;
×
4767
      QUERY_CHECK_CODE(code, lino, _end);
×
4768
    }
4769
    tsCols = (int64_t*)pColDataInfo->pData;
3,093✔
4770
  } else {
UNCOV
4771
    return;
×
4772
  }
4773

4774
  int32_t rows = pSDataBlock->info.rows;
3,093✔
4775
  code = blockDataEnsureCapacity(pAggSup->pScanBlock, rows);
3,093✔
4776
  QUERY_CHECK_CODE(code, lino, _end);
3,093!
4777

4778
  SColumnInfoData* pKeyColInfo = taosArrayGet(pSDataBlock->pDataBlock, pInfo->stateCol.slotId);
3,093✔
4779
  for (int32_t i = 0; i < rows; i += winRows) {
6,304✔
4780
    if (pInfo->ignoreExpiredData && checkExpiredData(&pInfo->streamAggSup.stateStore, pInfo->streamAggSup.pUpdateInfo,
3,275✔
4781
                                                     &pInfo->twAggSup, pSDataBlock->info.id.uid, tsCols[i], NULL, 0) ||
64✔
4782
        colDataIsNull_s(pKeyColInfo, i)) {
6,396✔
4783
      i++;
21✔
4784
      continue;
42✔
4785
    }
4786
    char*            pKeyData = colDataGetData(pKeyColInfo, i);
3,190!
4787
    int32_t          winIndex = 0;
3,190✔
4788
    bool             allEqual = true;
3,190✔
4789
    SStateWindowInfo curWin = {0};
3,190✔
4790
    SStateWindowInfo nextWin = {0};
3,190✔
4791
    int32_t          winCode = TSDB_CODE_SUCCESS;
3,190✔
4792
    code = setStateOutputBuf(pAggSup, tsCols[i], groupId, pKeyData, &curWin, &nextWin, &winCode);
3,190✔
4793
    QUERY_CHECK_CODE(code, lino, _end);
3,190!
4794

4795
    if (winCode != TSDB_CODE_SUCCESS && pTaskInfo->streamInfo.eventTypes) {
3,190!
UNCOV
4796
      SStateWindowInfo prevWin = {.winInfo.sessionWin = curWin.winInfo.sessionWin};
×
4797
      getNextStateWin(pAggSup, &prevWin, false);
×
4798
      qDebug("===stream===get state prev win buff. skey:%" PRId64 ", endkey:%" PRId64,
×
4799
             prevWin.winInfo.sessionWin.win.skey, prevWin.winInfo.sessionWin.win.ekey);
UNCOV
4800
      releaseOutputBuf(pAggSup->pState, prevWin.winInfo.pStatePos, &pAPI->stateStore);
×
4801
      // For ordered data, the previous window's closure did not record the corresponding state values, so they need to
4802
      // be added here.
UNCOV
4803
      if (BIT_FLAG_TEST_MASK(pTaskInfo->streamInfo.eventTypes, SNOTIFY_EVENT_WINDOW_CLOSE) &&
×
4804
          IS_VALID_SESSION_WIN(prevWin.winInfo)) {
×
4805
        code = addStateAggNotifyEvent(SNOTIFY_EVENT_WINDOW_CLOSE, &prevWin.winInfo.sessionWin, prevWin.pStateKey,
×
4806
                                      curWin.pStateKey, true, pNotifySup, pNotifyEventStat);
×
4807
        QUERY_CHECK_CODE(code, lino, _end);
×
4808
      }
UNCOV
4809
      if (BIT_FLAG_TEST_MASK(pTaskInfo->streamInfo.eventTypes, SNOTIFY_EVENT_WINDOW_OPEN)) {
×
4810
        code = addStateAggNotifyEvent(SNOTIFY_EVENT_WINDOW_OPEN, &curWin.winInfo.sessionWin, curWin.pStateKey,
×
4811
                                      prevWin.pStateKey, false, pNotifySup, pNotifyEventStat);
×
4812
        QUERY_CHECK_CODE(code, lino, _end);
×
4813
      }
4814
    }
4815

4816
    if (isWinResult(&nextWin.winInfo.sessionWin, pSeUpdated, pAggSup->pResultRows) == false) {
3,190✔
4817
      releaseOutputBuf(pAggSup->pState, nextWin.winInfo.pStatePos, &pAPI->stateStore);
3,145✔
4818
    }
4819

4820
    setSessionWinOutputInfo(pSeUpdated, &curWin.winInfo);
3,190✔
4821
    code = updateStateWindowInfo(pAggSup, &curWin, &nextWin, tsCols, groupId, pKeyColInfo, rows, i, &allEqual,
3,190✔
4822
                                 pAggSup->pResultRows, pSeUpdated, pStDeleted, &winRows);
4823
    QUERY_CHECK_CODE(code, lino, _end);
3,189!
4824

4825
    if (!allEqual) {
3,189✔
4826
      uint64_t uid = 0;
21✔
4827
      code = appendDataToSpecialBlock(pAggSup->pScanBlock, &curWin.winInfo.sessionWin.win.skey,
21✔
4828
                                      &curWin.winInfo.sessionWin.win.ekey, &uid, &groupId, NULL);
4829
      QUERY_CHECK_CODE(code, lino, _end);
21!
4830
      int32_t tmpRes = tSimpleHashRemove(pSeUpdated, &curWin.winInfo.sessionWin, sizeof(SSessionKey));
21✔
4831
      qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
21!
4832

4833
      doDeleteSessionWindow(pAggSup, &curWin.winInfo.sessionWin);
21✔
4834
      releaseOutputBuf(pAggSup->pState, curWin.winInfo.pStatePos, &pAPI->stateStore);
21✔
4835
      continue;
21✔
4836
    }
4837

4838
    code = doOneWindowAggImpl(&pInfo->twAggSup.timeWindowData, &curWin.winInfo, &pResult, i, winRows, rows, numOfOutput,
3,168✔
4839
                              pOperator, 0);
4840
    QUERY_CHECK_CODE(code, lino, _end);
3,168!
4841

4842
    code = saveSessionOutputBuf(pAggSup, &curWin.winInfo);
3,168✔
4843
    QUERY_CHECK_CODE(code, lino, _end);
3,167!
4844

4845
    if (pInfo->destHasPrimaryKey && curWin.winInfo.isOutput && IS_NORMAL_STATE_OP(pOperator)) {
3,167!
4846
      code = saveDeleteRes(pInfo->pPkDeleted, curWin.winInfo.sessionWin);
1✔
4847
      QUERY_CHECK_CODE(code, lino, _end);
1!
4848
    }
4849

4850
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_AT_ONCE) {
3,167✔
4851
      code = saveResult(curWin.winInfo, pSeUpdated);
2,856✔
4852
      QUERY_CHECK_CODE(code, lino, _end);
2,856!
4853
    }
4854

4855
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_WINDOW_CLOSE) {
3,167✔
4856
      curWin.winInfo.pStatePos->beUpdated = true;
311✔
4857
      SSessionKey key = {0};
311✔
4858
      getSessionHashKey(&curWin.winInfo.sessionWin, &key);
311✔
4859
      code =
4860
          tSimpleHashPut(pAggSup->pResultRows, &key, sizeof(SSessionKey), &curWin.winInfo, sizeof(SResultWindowInfo));
311✔
4861
      QUERY_CHECK_CODE(code, lino, _end);
313!
4862
    }
4863

4864
    // If this is a windown recalculation, add the corresponding state values here since the next window may not require
4865
    // recalculation.
4866
    if (BIT_FLAG_TEST_MASK(pTaskInfo->streamInfo.eventTypes, SNOTIFY_EVENT_WINDOW_CLOSE)) {
3,169!
UNCOV
4867
      code = addStateAggNotifyEvent(SNOTIFY_EVENT_WINDOW_CLOSE, &curWin.winInfo.sessionWin, curWin.pStateKey,
×
4868
                                    nextWin.pStateKey, false, pNotifySup, pNotifyEventStat);
×
4869
      QUERY_CHECK_CODE(code, lino, _end);
×
4870
    }
4871
  }
4872

4873
_end:
3,093✔
4874
  if (code != TSDB_CODE_SUCCESS) {
3,093!
UNCOV
4875
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
4876
  }
4877
}
4878

UNCOV
4879
int32_t doStreamStateEncodeOpState(void** buf, int32_t len, SOperatorInfo* pOperator, bool isParent) {
×
UNCOV
4880
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
×
UNCOV
4881
  if (!pInfo) {
×
UNCOV
4882
    return 0;
×
4883
  }
4884

UNCOV
4885
  void* pData = (buf == NULL) ? NULL : *buf;
×
4886

4887
  // 1.streamAggSup.pResultRows
UNCOV
4888
  int32_t tlen = 0;
×
UNCOV
4889
  int32_t mapSize = tSimpleHashGetSize(pInfo->streamAggSup.pResultRows);
×
UNCOV
4890
  tlen += taosEncodeFixedI32(buf, mapSize);
×
UNCOV
4891
  void*   pIte = NULL;
×
UNCOV
4892
  size_t  keyLen = 0;
×
UNCOV
4893
  int32_t iter = 0;
×
UNCOV
4894
  while ((pIte = tSimpleHashIterate(pInfo->streamAggSup.pResultRows, pIte, &iter)) != NULL) {
×
UNCOV
4895
    void* key = tSimpleHashGetKey(pIte, &keyLen);
×
UNCOV
4896
    tlen += encodeSSessionKey(buf, key);
×
UNCOV
4897
    tlen += encodeSResultWindowInfo(buf, pIte, pInfo->streamAggSup.resultRowSize);
×
4898
  }
4899

4900
  // 2.twAggSup
UNCOV
4901
  tlen += encodeSTimeWindowAggSupp(buf, &pInfo->twAggSup);
×
4902

4903
  // 3.pChildren
UNCOV
4904
  int32_t size = taosArrayGetSize(pInfo->pChildren);
×
UNCOV
4905
  tlen += taosEncodeFixedI32(buf, size);
×
UNCOV
4906
  for (int32_t i = 0; i < size; i++) {
×
UNCOV
4907
    SOperatorInfo* pChOp = taosArrayGetP(pInfo->pChildren, i);
×
4908
    tlen += doStreamStateEncodeOpState(buf, 0, pChOp, false);
×
4909
  }
4910

4911
  // 4.dataVersion
UNCOV
4912
  tlen += taosEncodeFixedI64(buf, pInfo->dataVersion);
×
4913

4914
  // 5.basicInfo
UNCOV
4915
  tlen += encodeStreamBasicInfo(buf, &pInfo->basic);
×
4916

4917
  // 6.checksum
UNCOV
4918
  if (isParent) {
×
UNCOV
4919
    if (buf) {
×
UNCOV
4920
      uint32_t cksum = taosCalcChecksum(0, pData, len - sizeof(uint32_t));
×
UNCOV
4921
      tlen += taosEncodeFixedU32(buf, cksum);
×
4922
    } else {
UNCOV
4923
      tlen += sizeof(uint32_t);
×
4924
    }
4925
  }
4926

UNCOV
4927
  return tlen;
×
4928
}
4929

UNCOV
4930
int32_t doStreamStateDecodeOpState(void* buf, int32_t len, SOperatorInfo* pOperator, bool isParent, void** ppBuf) {
×
4931
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
×
4932
  int32_t                      code = TSDB_CODE_SUCCESS;
×
4933
  int32_t                      lino = 0;
×
4934
  SStreamAggSupporter*         pAggSup = &pInfo->streamAggSup;
×
4935
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
×
4936
  void*                        pDataEnd = POINTER_SHIFT(buf, len);
×
4937
  if (!pInfo) {
×
4938
    code = TSDB_CODE_FAILED;
×
4939
    QUERY_CHECK_CODE(code, lino, _end);
×
4940
  }
4941

4942
  // 6.checksum
UNCOV
4943
  if (isParent) {
×
4944
    int32_t dataLen = len - sizeof(uint32_t);
×
4945
    void*   pCksum = POINTER_SHIFT(buf, dataLen);
×
4946
    if (taosCheckChecksum(buf, dataLen, *(uint32_t*)pCksum) != TSDB_CODE_SUCCESS) {
×
4947
      qError("stream state_window state is invalid");
×
4948
      code = TSDB_CODE_FAILED;
×
4949
      QUERY_CHECK_CODE(code, lino, _end);
×
4950
    }
UNCOV
4951
    pDataEnd = pCksum;
×
4952
  }
4953

4954
  // 1.streamAggSup.pResultRows
UNCOV
4955
  int32_t mapSize = 0;
×
4956
  buf = taosDecodeFixedI32(buf, &mapSize);
×
4957
  for (int32_t i = 0; i < mapSize; i++) {
×
4958
    SResultWindowInfo winfo = {0};
×
4959
    buf = decodeSSessionKey(buf, &winfo.sessionWin);
×
4960
    int32_t winCode = TSDB_CODE_SUCCESS;
×
4961
    code = pAggSup->stateStore.streamStateStateAddIfNotExist(
×
4962
        pAggSup->pState, &winfo.sessionWin, NULL, pAggSup->stateKeySize, compareStateKey, (void**)&winfo.pStatePos,
4963
        &pAggSup->resultRowSize, &winCode);
UNCOV
4964
    QUERY_CHECK_CODE(code, lino, _end);
×
4965

UNCOV
4966
    buf = decodeSResultWindowInfo(buf, &winfo, pInfo->streamAggSup.resultRowSize);
×
4967
    code = tSimpleHashPut(pInfo->streamAggSup.pResultRows, &winfo.sessionWin, sizeof(SSessionKey), &winfo,
×
4968
                          sizeof(SResultWindowInfo));
UNCOV
4969
    QUERY_CHECK_CODE(code, lino, _end);
×
4970
  }
4971

4972
  // 2.twAggSup
UNCOV
4973
  buf = decodeSTimeWindowAggSupp(buf, &pInfo->twAggSup);
×
4974

4975
  // 3.pChildren
UNCOV
4976
  int32_t size = 0;
×
4977
  buf = taosDecodeFixedI32(buf, &size);
×
4978
  for (int32_t i = 0; i < size; i++) {
×
4979
    SOperatorInfo* pChOp = taosArrayGetP(pInfo->pChildren, i);
×
4980
    code = doStreamStateDecodeOpState(buf, 0, pChOp, false, &buf);
×
4981
    QUERY_CHECK_CODE(code, lino, _end);
×
4982
  }
4983

4984
  // 4.dataVersion
UNCOV
4985
  buf = taosDecodeFixedI64(buf, &pInfo->dataVersion);
×
4986

UNCOV
4987
  if (ppBuf) {
×
4988
    (*ppBuf) = buf;
×
4989
  }
4990

4991
  // 5.basicInfo
UNCOV
4992
  if (buf < pDataEnd) {
×
4993
    code = decodeStreamBasicInfo(&buf, &pInfo->basic);
×
4994
    QUERY_CHECK_CODE(code, lino, _end);
×
4995
  }
4996

UNCOV
4997
_end:
×
4998
  if (code != TSDB_CODE_SUCCESS) {
×
4999
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
5000
  }
UNCOV
5001
  return code;
×
5002
}
5003

5004
void doStreamStateSaveCheckpoint(SOperatorInfo* pOperator) {
85✔
5005
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
85✔
5006
  if (needSaveStreamOperatorInfo(&pInfo->basic)) {
85!
UNCOV
5007
    int32_t len = doStreamStateEncodeOpState(NULL, 0, pOperator, true);
×
UNCOV
5008
    void*   buf = taosMemoryCalloc(1, len);
×
UNCOV
5009
    if (!buf) {
×
UNCOV
5010
      qError("%s failed at line %d since %s", __func__, __LINE__, tstrerror(TSDB_CODE_OUT_OF_MEMORY));
×
5011
      return;
×
5012
    }
UNCOV
5013
    void* pBuf = buf;
×
UNCOV
5014
    len = doStreamStateEncodeOpState(&pBuf, len, pOperator, true);
×
UNCOV
5015
    pInfo->streamAggSup.stateStore.streamStateSaveInfo(pInfo->streamAggSup.pState, STREAM_STATE_OP_CHECKPOINT_NAME,
×
5016
                                                       strlen(STREAM_STATE_OP_CHECKPOINT_NAME), buf, len);
UNCOV
5017
    taosMemoryFree(buf);
×
UNCOV
5018
    saveStreamOperatorStateComplete(&pInfo->basic);
×
5019
  }
5020
}
5021

5022
static int32_t buildStateResult(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
3,854✔
5023
  int32_t                      code = TSDB_CODE_SUCCESS;
3,854✔
5024
  int32_t                      lino = 0;
3,854✔
5025
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
3,854✔
5026
  SOptrBasicInfo*              pBInfo = &pInfo->binfo;
3,854✔
5027
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
3,854✔
5028
  SStreamNotifyEventSupp*      pNotifySup = &pInfo->basic.notifyEventSup;
3,854✔
5029
  STaskNotifyEventStat*        pNotifyEventStat = pTaskInfo->streamInfo.pNotifyEventStat;
3,854✔
5030
  bool                         addNotifyEvent = false;
3,854✔
5031
  addNotifyEvent = BIT_FLAG_TEST_MASK(pTaskInfo->streamInfo.eventTypes, SNOTIFY_EVENT_WINDOW_CLOSE);
3,854✔
5032
  doBuildDeleteDataBlock(pOperator, pInfo->pSeDeleted, pInfo->pDelRes, &pInfo->pDelIterator, &pInfo->groupResInfo);
3,854✔
5033
  if (pInfo->pDelRes->info.rows > 0) {
3,854✔
5034
    printDataBlock(pInfo->pDelRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
200✔
5035
    if (addNotifyEvent) {
200!
UNCOV
5036
      code = addAggDeleteNotifyEvent(pInfo->pDelRes, pNotifySup, pNotifyEventStat);
×
5037
      QUERY_CHECK_CODE(code, lino, _end);
×
5038
    }
5039
    (*ppRes) = pInfo->pDelRes;
200✔
5040
    return code;
200✔
5041
  }
5042

5043
  doBuildSessionResult(pOperator, pInfo->streamAggSup.pState, &pInfo->groupResInfo, pBInfo->pRes,
3,654!
5044
                       addNotifyEvent ? pNotifySup->pSessionKeys : NULL);
5045
  if (pBInfo->pRes->info.rows > 0) {
3,654✔
5046
    printDataBlock(pBInfo->pRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
1,292✔
5047
    if (addNotifyEvent) {
1,292!
UNCOV
5048
      code = addAggResultNotifyEvent(pBInfo->pRes, pNotifySup->pSessionKeys, pTaskInfo->streamInfo.notifyResultSchema,
×
5049
                                     pNotifySup, pNotifyEventStat);
UNCOV
5050
      QUERY_CHECK_CODE(code, lino, _end);
×
5051
    }
5052
    (*ppRes) = pBInfo->pRes;
1,292✔
5053
    return code;
1,292✔
5054
  }
5055

5056
  code = buildNotifyEventBlock(pTaskInfo, pNotifySup, pNotifyEventStat);
2,362✔
5057
  QUERY_CHECK_CODE(code, lino, _end);
2,362!
5058
  if (pNotifySup->pEventBlock && pNotifySup->pEventBlock->info.rows > 0) {
2,362!
UNCOV
5059
    printDataBlock(pNotifySup->pEventBlock, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
5060
    (*ppRes) = pNotifySup->pEventBlock;
×
5061
    return code;
×
5062
  }
5063

5064
  code = removeOutdatedNotifyEvents(&pInfo->twAggSup, pNotifySup, pNotifyEventStat);
2,362✔
5065
  QUERY_CHECK_CODE(code, lino, _end);
2,359!
5066

5067
_end:
2,359✔
5068
  if (code != TSDB_CODE_SUCCESS) {
2,359!
UNCOV
5069
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
5070
  }
5071
  (*ppRes) = NULL;
2,359✔
5072
  return code;
2,359✔
5073
}
5074

5075
static int32_t doStreamStateAggNext(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
4,254✔
5076
  if (pOperator->status == OP_EXEC_DONE) {
4,254!
UNCOV
5077
    (*ppRes) = NULL;
×
5078
    return TSDB_CODE_SUCCESS;
×
5079
  }
5080

5081
  int32_t                      code = TSDB_CODE_SUCCESS;
4,254✔
5082
  int32_t                      lino = 0;
4,254✔
5083
  SExprSupp*                   pSup = &pOperator->exprSupp;
4,254✔
5084
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
4,254✔
5085
  SOptrBasicInfo*              pBInfo = &pInfo->binfo;
4,254✔
5086
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
4,254✔
5087
  qDebug("===stream=== stream state agg");
4,254✔
5088
  if (pOperator->status == OP_RES_TO_RETURN) {
4,254✔
5089
    SSDataBlock* resBlock = NULL;
1,492✔
5090
    code = buildStateResult(pOperator, &resBlock);
1,492✔
5091
    QUERY_CHECK_CODE(code, lino, _end);
1,492!
5092
    if (resBlock != NULL) {
1,492✔
5093
      (*ppRes) = resBlock;
360✔
5094
      return code;
1,492✔
5095
    }
5096

5097
    if (pInfo->recvGetAll) {
1,132✔
5098
      pInfo->recvGetAll = false;
2✔
5099
      resetUnCloseSessionWinInfo(pInfo->streamAggSup.pResultRows);
2✔
5100
    }
5101

5102
    if (pInfo->reCkBlock) {
1,132!
UNCOV
5103
      pInfo->reCkBlock = false;
×
5104
      printDataBlock(pInfo->pCheckpointRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
5105
      (*ppRes) = pInfo->pCheckpointRes;
×
5106
      return code;
×
5107
    }
5108

5109
    setStreamOperatorCompleted(pOperator);
1,132✔
5110
    (*ppRes) = NULL;
1,132✔
5111
    return code;
1,132✔
5112
  }
5113

5114
  SOperatorInfo* downstream = pOperator->pDownstream[0];
2,762✔
5115
  if (!pInfo->pUpdated) {
2,762✔
5116
    pInfo->pUpdated = taosArrayInit(16, sizeof(SResultWindowInfo));
2,361✔
5117
    QUERY_CHECK_NULL(pInfo->pUpdated, code, lino, _end, terrno);
2,360!
5118
  }
5119
  if (!pInfo->pSeUpdated) {
2,761✔
5120
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
2,328✔
5121
    pInfo->pSeUpdated = tSimpleHashInit(64, hashFn);
2,328✔
5122
    QUERY_CHECK_NULL(pInfo->pSeUpdated, code, lino, _end, terrno);
2,330!
5123
  }
5124
  while (1) {
3,699✔
5125
    SSDataBlock* pBlock = NULL;
6,462✔
5126
    code = downstream->fpSet.getNextFn(downstream, &pBlock);
6,462✔
5127
    QUERY_CHECK_CODE(code, lino, _end);
6,462!
5128

5129
    if (pBlock == NULL) {
6,462✔
5130
      break;
2,362✔
5131
    }
5132
    printSpecDataBlock(pBlock, getStreamOpName(pOperator->operatorType), "recv", GET_TASKID(pTaskInfo));
4,100✔
5133
    setStreamOperatorState(&pInfo->basic, pBlock->info.type);
4,100✔
5134

5135
    if (pBlock->info.type == STREAM_DELETE_DATA || pBlock->info.type == STREAM_DELETE_RESULT ||
4,100✔
5136
        pBlock->info.type == STREAM_CLEAR) {
3,624✔
5137
      bool add = pInfo->destHasPrimaryKey && IS_NORMAL_STATE_OP(pOperator);
514!
5138
      code = deleteSessionWinState(&pInfo->streamAggSup, pBlock, pInfo->pSeUpdated, pInfo->pSeDeleted,
514✔
5139
                                   pInfo->pPkDeleted, add);
5140
      QUERY_CHECK_CODE(code, lino, _end);
514!
5141
      continue;
606✔
5142
    } else if (pBlock->info.type == STREAM_GET_ALL) {
3,586✔
5143
      pInfo->recvGetAll = true;
7✔
5144
      code = getAllSessionWindow(pInfo->streamAggSup.pResultRows, pInfo->pSeUpdated);
7✔
5145
      QUERY_CHECK_CODE(code, lino, _end);
7!
5146
      continue;
7✔
5147
    } else if (pBlock->info.type == STREAM_CREATE_CHILD_TABLE) {
3,579✔
5148
      (*ppRes) = pBlock;
401✔
5149
      return code;
401✔
5150
    } else if (pBlock->info.type == STREAM_CHECKPOINT) {
3,178✔
5151
      pInfo->streamAggSup.stateStore.streamStateCommit(pInfo->streamAggSup.pState);
85✔
5152
      doStreamStateSaveCheckpoint(pOperator);
85✔
5153
      code = copyDataBlock(pInfo->pCheckpointRes, pBlock);
85✔
5154
      QUERY_CHECK_CODE(code, lino, _end);
85!
5155

5156
      continue;
85✔
5157
    } else {
5158
      if (pBlock->info.type != STREAM_NORMAL && pBlock->info.type != STREAM_INVALID) {
3,093!
UNCOV
5159
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
5160
        QUERY_CHECK_CODE(code, lino, _end);
×
5161
      }
5162
    }
5163

5164
    if (pInfo->scalarSupp.pExprInfo != NULL) {
3,093✔
5165
      SExprSupp* pExprSup = &pInfo->scalarSupp;
256✔
5166
      code = projectApplyFunctions(pExprSup->pExprInfo, pBlock, pBlock, pExprSup->pCtx, pExprSup->numOfExprs, NULL);
256✔
5167
      QUERY_CHECK_CODE(code, lino, _end);
256!
5168
    }
5169
    // the pDataBlock are always the same one, no need to call this again
5170
    code = setInputDataBlock(pSup, pBlock, TSDB_ORDER_ASC, MAIN_SCAN, true);
3,093✔
5171
    QUERY_CHECK_CODE(code, lino, _end);
3,093!
5172
    doStreamStateAggImpl(pOperator, pBlock, pInfo->pSeUpdated, pInfo->pSeDeleted);
3,093✔
5173
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.window.ekey);
3,093✔
5174
  }
5175
  // restore the value
5176
  pOperator->status = OP_RES_TO_RETURN;
2,362✔
5177

5178
  code = closeSessionWindow(pInfo->streamAggSup.pResultRows, &pInfo->twAggSup, pInfo->pSeUpdated);
2,362✔
5179
  QUERY_CHECK_CODE(code, lino, _end);
2,362!
5180

5181
  code = copyUpdateResult(&pInfo->pSeUpdated, pInfo->pUpdated, sessionKeyCompareAsc);
2,362✔
5182
  QUERY_CHECK_CODE(code, lino, _end);
2,362!
5183

5184
  removeSessionDeleteResults(pInfo->pSeDeleted, pInfo->pUpdated);
2,362✔
5185

5186
  if (pInfo->isHistoryOp) {
2,362✔
5187
    code = getMaxTsWins(pInfo->pUpdated, pInfo->historyWins);
88✔
5188
    QUERY_CHECK_CODE(code, lino, _end);
88!
5189
  }
5190
  if (pInfo->destHasPrimaryKey && IS_NORMAL_STATE_OP(pOperator)) {
2,362!
5191
    code = copyDeleteSessionKey(pInfo->pPkDeleted, pInfo->pSeDeleted);
4✔
5192
    QUERY_CHECK_CODE(code, lino, _end);
4!
5193
  }
5194

5195
  initGroupResInfoFromArrayList(&pInfo->groupResInfo, pInfo->pUpdated);
2,362✔
5196
  pInfo->pUpdated = NULL;
2,362✔
5197
  code = blockDataEnsureCapacity(pInfo->binfo.pRes, pOperator->resultInfo.capacity);
2,362✔
5198
  QUERY_CHECK_CODE(code, lino, _end);
2,362!
5199

5200
  SSDataBlock* resBlock = NULL;
2,362✔
5201
  code = buildStateResult(pOperator, &resBlock);
2,362✔
5202
  QUERY_CHECK_CODE(code, lino, _end);
2,359!
5203
  if (resBlock != NULL) {
2,359✔
5204
    (*ppRes) = resBlock;
1,132✔
5205
    return code;
1,132✔
5206
  }
5207

5208
_end:
1,227✔
5209
  if (code != TSDB_CODE_SUCCESS) {
1,227!
UNCOV
5210
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
5211
    pTaskInfo->code = code;
×
5212
    T_LONG_JMP(pTaskInfo->env, code);
×
5213
  }
5214
  setStreamOperatorCompleted(pOperator);
1,227✔
5215
  (*ppRes) = NULL;
1,227✔
5216
  return code;
1,227✔
5217
}
5218

UNCOV
5219
static SSDataBlock* doStreamStateAgg(SOperatorInfo* pOperator) {
×
5220
  SSDataBlock* pRes = NULL;
×
5221
  int32_t      code = doStreamStateAggNext(pOperator, &pRes);
×
5222
  return pRes;
×
5223
}
5224

5225
void streamStateReleaseState(SOperatorInfo* pOperator) {
85✔
5226
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
85✔
5227
  int32_t                      winSize = taosArrayGetSize(pInfo->historyWins) * sizeof(SSessionKey);
85✔
5228
  int32_t                      resSize = winSize + sizeof(TSKEY);
85✔
5229
  char*                        pBuff = taosMemoryCalloc(1, resSize);
85!
5230
  if (!pBuff) {
85!
UNCOV
5231
    return;
×
5232
  }
5233
  memcpy(pBuff, pInfo->historyWins->pData, winSize);
85✔
5234
  memcpy(pBuff + winSize, &pInfo->twAggSup.maxTs, sizeof(TSKEY));
85✔
5235
  qDebug("===stream=== relase state. save result count:%d", (int32_t)taosArrayGetSize(pInfo->historyWins));
85✔
5236
  pInfo->streamAggSup.stateStore.streamStateSaveInfo(pInfo->streamAggSup.pState, STREAM_STATE_OP_STATE_NAME,
85✔
5237
                                                     strlen(STREAM_STATE_OP_STATE_NAME), pBuff, resSize);
5238
  pInfo->streamAggSup.stateStore.streamStateCommit(pInfo->streamAggSup.pState);
85✔
5239
  taosMemoryFreeClear(pBuff);
85!
5240

5241
  SOperatorInfo* downstream = pOperator->pDownstream[0];
85✔
5242
  if (downstream->fpSet.releaseStreamStateFn) {
85!
5243
    downstream->fpSet.releaseStreamStateFn(downstream);
85✔
5244
  }
5245
}
5246

UNCOV
5247
int32_t compactStateWindow(SOperatorInfo* pOperator, SResultWindowInfo* pCurWin, SResultWindowInfo* pNextWin,
×
5248
                           SSHashObj* pStUpdated, SSHashObj* pStDeleted) {
UNCOV
5249
  SExprSupp*                   pSup = &pOperator->exprSupp;
×
5250
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
×
5251
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
×
5252
  return compactTimeWindow(pSup, &pInfo->streamAggSup, &pInfo->twAggSup, pTaskInfo, pCurWin, pNextWin, pStUpdated,
×
5253
                           pStDeleted, false);
5254
}
5255

5256
void streamStateReloadState(SOperatorInfo* pOperator) {
85✔
5257
  int32_t                      code = TSDB_CODE_SUCCESS;
85✔
5258
  int32_t                      lino = 0;
85✔
5259
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
85✔
5260
  SStreamAggSupporter*         pAggSup = &pInfo->streamAggSup;
85✔
5261
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
85✔
5262
  resetWinRange(&pAggSup->winRange);
85✔
5263

5264
  SSessionKey seKey = {.win.skey = INT64_MIN, .win.ekey = INT64_MIN, .groupId = 0};
85✔
5265
  int32_t     size = 0;
85✔
5266
  void*       pBuf = NULL;
85✔
5267
  code = pAggSup->stateStore.streamStateGetInfo(pAggSup->pState, STREAM_STATE_OP_STATE_NAME,
85✔
5268
                                                strlen(STREAM_STATE_OP_STATE_NAME), &pBuf, &size);
5269
  QUERY_CHECK_CODE(code, lino, _end);
85!
5270

5271
  int32_t num = (size - sizeof(TSKEY)) / sizeof(SSessionKey);
85✔
5272
  qDebug("===stream=== reload state. get result count:%d", num);
85✔
5273
  SSessionKey* pSeKeyBuf = (SSessionKey*)pBuf;
85✔
5274

5275
  TSKEY ts = *(TSKEY*)((char*)pBuf + size - sizeof(TSKEY));
85✔
5276
  pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, ts);
85✔
5277
  pAggSup->stateStore.streamStateReloadInfo(pAggSup->pState, ts);
85✔
5278

5279
  if (!pInfo->pSeUpdated && num > 0) {
85!
5280
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
33✔
5281
    pInfo->pSeUpdated = tSimpleHashInit(64, hashFn);
33✔
5282
    QUERY_CHECK_NULL(pInfo->pSeUpdated, code, lino, _end, terrno);
33!
5283
  }
5284
  if (!pInfo->pSeDeleted && num > 0) {
85!
UNCOV
5285
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
×
5286
    pInfo->pSeDeleted = tSimpleHashInit(64, hashFn);
×
5287
    QUERY_CHECK_NULL(pInfo->pSeDeleted, code, lino, _end, terrno);
×
5288
  }
5289
  for (int32_t i = 0; i < num; i++) {
214✔
5290
    SStateWindowInfo curInfo = {0};
129✔
5291
    SStateWindowInfo nextInfo = {0};
129✔
5292
    qDebug("===stream=== reload state. try process result %" PRId64 ", %" PRIu64 ", index:%d", pSeKeyBuf[i].win.skey,
129✔
5293
           pSeKeyBuf[i].groupId, i);
5294
    code = getStateWindowInfoByKey(pAggSup, pSeKeyBuf + i, &curInfo, &nextInfo);
129✔
5295
    QUERY_CHECK_CODE(code, lino, _end);
129!
5296

5297
    bool cpRes = compareWinStateKey(curInfo.pStateKey, nextInfo.pStateKey);
129✔
5298
    qDebug("===stream=== reload state. next window info %" PRId64 ", %" PRIu64 ", compare:%d",
129✔
5299
           nextInfo.winInfo.sessionWin.win.skey, nextInfo.winInfo.sessionWin.groupId, cpRes);
5300
    if (cpRes) {
129!
UNCOV
5301
      code = compactStateWindow(pOperator, &curInfo.winInfo, &nextInfo.winInfo, pInfo->pSeUpdated, pInfo->pSeDeleted);
×
5302
      qDebug("===stream=== reload state. save result %" PRId64 ", %" PRIu64, curInfo.winInfo.sessionWin.win.skey,
×
5303
             curInfo.winInfo.sessionWin.groupId);
UNCOV
5304
      QUERY_CHECK_CODE(code, lino, _end);
×
5305

UNCOV
5306
      if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_AT_ONCE) {
×
5307
        code = saveResult(curInfo.winInfo, pInfo->pSeUpdated);
×
5308
        QUERY_CHECK_CODE(code, lino, _end);
×
5309
      } else if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_WINDOW_CLOSE) {
×
5310
        if (!isCloseWindow(&curInfo.winInfo.sessionWin.win, &pInfo->twAggSup)) {
×
5311
          code = saveDeleteRes(pInfo->pSeDeleted, curInfo.winInfo.sessionWin);
×
5312
          QUERY_CHECK_CODE(code, lino, _end);
×
5313
        }
UNCOV
5314
        SSessionKey key = {0};
×
5315
        getSessionHashKey(&curInfo.winInfo.sessionWin, &key);
×
5316
        code = tSimpleHashPut(pAggSup->pResultRows, &key, sizeof(SSessionKey), &curInfo.winInfo,
×
5317
                              sizeof(SResultWindowInfo));
UNCOV
5318
        QUERY_CHECK_CODE(code, lino, _end);
×
5319
      }
5320
    } else if (IS_VALID_SESSION_WIN(nextInfo.winInfo)) {
129!
UNCOV
5321
      releaseOutputBuf(pAggSup->pState, nextInfo.winInfo.pStatePos, &pAggSup->pSessionAPI->stateStore);
×
5322
    }
5323

5324
    if (IS_VALID_SESSION_WIN(curInfo.winInfo)) {
129!
5325
      code = saveSessionOutputBuf(pAggSup, &curInfo.winInfo);
129✔
5326
      QUERY_CHECK_CODE(code, lino, _end);
129!
5327
    }
5328
  }
5329
  taosMemoryFreeClear(pBuf);
85!
5330

5331
  SOperatorInfo* downstream = pOperator->pDownstream[0];
85✔
5332
  if (downstream->fpSet.reloadStreamStateFn) {
85!
5333
    downstream->fpSet.reloadStreamStateFn(downstream);
85✔
5334
  }
5335
  reloadAggSupFromDownStream(downstream, &pInfo->streamAggSup);
85✔
5336

5337
_end:
85✔
5338
  taosMemoryFreeClear(pBuf);
85!
5339
  if (code != TSDB_CODE_SUCCESS) {
85!
UNCOV
5340
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
5341
  }
5342
}
85✔
5343

5344
int32_t createStreamStateAggOperatorInfo(SOperatorInfo* downstream, SPhysiNode* pPhyNode, SExecTaskInfo* pTaskInfo,
348✔
5345
                                         SReadHandle* pHandle, SOperatorInfo** pOptrInfo) {
5346
  QRY_PARAM_CHECK(pOptrInfo);
348!
5347
  int32_t code = 0;
348✔
5348
  int32_t lino = 0;
348✔
5349

5350
  SStreamStateWinodwPhysiNode* pStateNode = (SStreamStateWinodwPhysiNode*)pPhyNode;
348✔
5351
  int32_t                      tsSlotId = ((SColumnNode*)pStateNode->window.pTspk)->slotId;
348✔
5352
  SColumnNode*                 pColNode = (SColumnNode*)(pStateNode->pStateKey);
348✔
5353
  SStreamStateAggOperatorInfo* pInfo = taosMemoryCalloc(1, sizeof(SStreamStateAggOperatorInfo));
348!
5354
  SOperatorInfo*               pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo));
349!
5355
  if (pInfo == NULL || pOperator == NULL) {
349!
UNCOV
5356
    code = terrno;
×
5357
    QUERY_CHECK_CODE(code, lino, _error);
×
5358
  }
5359

5360
  pInfo->stateCol = extractColumnFromColumnNode(pColNode);
349✔
5361
  initResultSizeInfo(&pOperator->resultInfo, 4096);
349✔
5362
  if (pStateNode->window.pExprs != NULL) {
349✔
5363
    int32_t    numOfScalar = 0;
25✔
5364
    SExprInfo* pScalarExprInfo = NULL;
25✔
5365
    code = createExprInfo(pStateNode->window.pExprs, NULL, &pScalarExprInfo, &numOfScalar);
25✔
5366
    QUERY_CHECK_CODE(code, lino, _error);
25!
5367

5368
    code = initExprSupp(&pInfo->scalarSupp, pScalarExprInfo, numOfScalar, &pTaskInfo->storageAPI.functionStore);
25✔
5369
    QUERY_CHECK_CODE(code, lino, _error);
25!
5370
  }
5371

5372
  pInfo->twAggSup = (STimeWindowAggSupp){
349✔
5373
      .waterMark = pStateNode->window.watermark,
349✔
5374
      .calTrigger = pStateNode->window.triggerType,
349✔
5375
      .maxTs = INT64_MIN,
5376
      .minTs = INT64_MAX,
5377
      .deleteMark = getDeleteMark(&pStateNode->window, 0),
349✔
5378
  };
5379

5380
  code = initExecTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &pTaskInfo->window);
349✔
5381
  QUERY_CHECK_CODE(code, lino, _error);
349!
5382

5383
  SSDataBlock* pResBlock = createDataBlockFromDescNode(pPhyNode->pOutputDataBlockDesc);
349✔
5384
  QUERY_CHECK_NULL(pResBlock, code, lino, _error, terrno);
349!
5385
  pInfo->binfo.pRes = pResBlock;
349✔
5386

5387
  SExprSupp* pExpSup = &pOperator->exprSupp;
349✔
5388
  int32_t    numOfCols = 0;
349✔
5389
  SExprInfo* pExprInfo = NULL;
349✔
5390
  code = createExprInfo(pStateNode->window.pFuncs, NULL, &pExprInfo, &numOfCols);
349✔
5391
  QUERY_CHECK_CODE(code, lino, _error);
349!
5392

5393
  code = initBasicInfoEx(&pInfo->binfo, pExpSup, pExprInfo, numOfCols, pResBlock, &pTaskInfo->storageAPI.functionStore);
349✔
5394
  if (code != TSDB_CODE_SUCCESS) {
349!
UNCOV
5395
    goto _error;
×
5396
  }
5397
  int32_t keySize = sizeof(SStateKeys) + pColNode->node.resType.bytes;
349✔
5398
  int16_t type = pColNode->node.resType.type;
349✔
5399
  pInfo->primaryTsIndex = tsSlotId;
349✔
5400
  code =
5401
      initStreamAggSupporter(&pInfo->streamAggSup, pExpSup, numOfCols, 0, pTaskInfo->streamInfo.pState, keySize, type,
349✔
5402
                             &pTaskInfo->storageAPI.stateStore, pHandle, &pInfo->twAggSup, GET_TASKID(pTaskInfo),
349✔
5403
                             &pTaskInfo->storageAPI, pInfo->primaryTsIndex, STREAM_STATE_BUFF_SORT, 1);
5404
  QUERY_CHECK_CODE(code, lino, _error);
349!
5405

5406
  _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
349✔
5407
  pInfo->pSeDeleted = tSimpleHashInit(64, hashFn);
349✔
5408
  QUERY_CHECK_NULL(pInfo->pSeDeleted, code, lino, _error, terrno);
349!
5409
  pInfo->pDelIterator = NULL;
349✔
5410

5411
  code = createSpecialDataBlock(STREAM_DELETE_RESULT, &pInfo->pDelRes);
349✔
5412
  QUERY_CHECK_CODE(code, lino, _error);
349!
5413

5414
  pInfo->pChildren = NULL;
349✔
5415
  pInfo->ignoreExpiredData = pStateNode->window.igExpired;
349✔
5416
  pInfo->ignoreExpiredDataSaved = false;
349✔
5417
  pInfo->pUpdated = NULL;
349✔
5418
  pInfo->pSeUpdated = NULL;
349✔
5419
  pInfo->dataVersion = 0;
349✔
5420
  pInfo->historyWins = taosArrayInit(4, sizeof(SSessionKey));
349✔
5421
  if (!pInfo->historyWins) {
349!
UNCOV
5422
    code = terrno;
×
5423
    QUERY_CHECK_CODE(code, lino, _error);
×
5424
  }
5425

5426
  if (pHandle) {
349!
5427
    pInfo->isHistoryOp = (pHandle->fillHistory == STREAM_HISTORY_OPERATOR);
349✔
5428
  }
5429

5430
  code = createSpecialDataBlock(STREAM_CHECKPOINT, &pInfo->pCheckpointRes);
349✔
5431
  QUERY_CHECK_CODE(code, lino, _error);
349!
5432

5433
  pInfo->recvGetAll = false;
349✔
5434
  pInfo->pPkDeleted = tSimpleHashInit(64, hashFn);
349✔
5435
  QUERY_CHECK_NULL(pInfo->pPkDeleted, code, lino, _error, terrno);
349!
5436
  pInfo->destHasPrimaryKey = pStateNode->window.destHasPrimaryKey;
349✔
5437
  pInfo->pOperator = pOperator;
349✔
5438

5439
  setOperatorInfo(pOperator, "StreamStateAggOperator", nodeType(pPhyNode), true, OP_NOT_OPENED,
349✔
5440
                  pInfo, pTaskInfo);
5441
  // for stream
5442
  void*   buff = NULL;
349✔
5443
  int32_t len = 0;
349✔
5444
  int32_t res =
5445
      pInfo->streamAggSup.stateStore.streamStateGetInfo(pInfo->streamAggSup.pState, STREAM_STATE_OP_CHECKPOINT_NAME,
349✔
5446
                                                        strlen(STREAM_STATE_OP_CHECKPOINT_NAME), &buff, &len);
5447
  if (res == TSDB_CODE_SUCCESS) {
349!
UNCOV
5448
    code = doStreamStateDecodeOpState(buff, len, pOperator, true, NULL);
×
5449
    taosMemoryFree(buff);
×
5450
    QUERY_CHECK_CODE(code, lino, _error);
×
5451
  }
5452
  initNonBlockAggSupptor(&pInfo->nbSup, NULL, NULL);
349✔
5453
  code = initStreamBasicInfo(&pInfo->basic, pOperator);
349✔
5454
  QUERY_CHECK_CODE(code, lino, _error);
349!
5455

5456
  if (pStateNode->window.triggerType == STREAM_TRIGGER_CONTINUOUS_WINDOW_CLOSE) {
349!
UNCOV
5457
    if (pHandle->fillHistory == STREAM_HISTORY_OPERATOR) {
×
5458
      setFillHistoryOperatorFlag(&pInfo->basic);
×
5459
    } else if (pHandle->fillHistory == STREAM_RECALCUL_OPERATOR) {
×
5460
      setRecalculateOperatorFlag(&pInfo->basic);
×
5461
    }
5462

5463
    pOperator->fpSet =
UNCOV
5464
        createOperatorFpSet(optrDummyOpenFn, doStreamStateNonblockAggNext, NULL, destroyStreamStateOperatorInfo,
×
5465
                            optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
UNCOV
5466
    setOperatorStreamStateFn(pOperator, streamStateNonblockReleaseState, streamStateNonblockReloadState);
×
5467
  } else {
5468
    pOperator->fpSet = createOperatorFpSet(optrDummyOpenFn, doStreamStateAggNext, NULL, destroyStreamStateOperatorInfo,
349✔
5469
                                           optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
5470
    setOperatorStreamStateFn(pOperator, streamStateReleaseState, streamStateReloadState);
349✔
5471
  }
5472

5473
  code = initDownStream(downstream, &pInfo->streamAggSup, pOperator->operatorType, pInfo->primaryTsIndex,
349✔
5474
                        &pInfo->twAggSup, &pInfo->basic, 0);
349✔
5475
  QUERY_CHECK_CODE(code, lino, _error);
349!
5476

5477
  code = appendDownstream(pOperator, &downstream, 1);
349✔
5478
  QUERY_CHECK_CODE(code, lino, _error);
349!
5479

5480
  pInfo->trueForLimit = pStateNode->trueForLimit;
349✔
5481

5482
  *pOptrInfo = pOperator;
349✔
5483
  return TSDB_CODE_SUCCESS;
349✔
5484

UNCOV
5485
_error:
×
5486
  if (pInfo != NULL) destroyStreamStateOperatorInfo(pInfo);
×
5487
  destroyOperatorAndDownstreams(pOperator, &downstream, 1);
×
5488
  pTaskInfo->code = code;
×
5489
  qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
5490
  return code;
×
5491
}
5492

5493
#ifdef BUILD_NO_CALL
5494
static void setInverFunction(SqlFunctionCtx* pCtx, int32_t num, EStreamType type) {
5495
  for (int i = 0; i < num; i++) {
5496
    if (type == STREAM_INVERT) {
5497
      fmSetInvertFunc(pCtx[i].functionId, &(pCtx[i].fpSet));
5498
    } else if (type == STREAM_NORMAL) {
5499
      fmSetNormalFunc(pCtx[i].functionId, &(pCtx[i].fpSet));
5500
    }
5501
  }
5502
}
5503
#endif
5504

5505
static int32_t doStreamIntervalAggNext(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
64,998✔
5506
  int32_t                      code = TSDB_CODE_SUCCESS;
64,998✔
5507
  int32_t                      lino = 0;
64,998✔
5508
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
64,998✔
5509
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
64,998✔
5510
  SStorageAPI*                 pAPI = &pOperator->pTaskInfo->storageAPI;
64,998✔
5511
  SExprSupp*                   pSup = &pOperator->exprSupp;
64,998✔
5512

5513
  qDebug("stask:%s  %s status: %d", GET_TASKID(pTaskInfo), getStreamOpName(pOperator->operatorType), pOperator->status);
64,998✔
5514

5515
  if (pOperator->status == OP_EXEC_DONE) {
65,001✔
5516
    (*ppRes) = NULL;
1,285✔
5517
    return code;
1,285✔
5518
  }
5519

5520
  if (pOperator->status == OP_RES_TO_RETURN) {
63,716✔
5521
    SSDataBlock* resBlock = NULL;
49,429✔
5522
    code = buildIntervalResult(pOperator, &resBlock);
49,429✔
5523
    QUERY_CHECK_CODE(code, lino, _end);
49,427!
5524
    if (resBlock != NULL) {
49,427✔
5525
      (*ppRes) = resBlock;
43,905✔
5526
      return code;
49,427✔
5527
    }
5528

5529
    if (pInfo->recvGetAll) {
5,522✔
5530
      pInfo->recvGetAll = false;
143✔
5531
      resetUnCloseWinInfo(pInfo->aggSup.pResultRowHashTable);
143✔
5532
    }
5533

5534
    if (pInfo->reCkBlock) {
5,523✔
5535
      pInfo->reCkBlock = false;
87✔
5536
      printDataBlock(pInfo->pCheckpointRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
87✔
5537
      (*ppRes) = pInfo->pCheckpointRes;
87✔
5538
      return code;
87✔
5539
    }
5540

5541
    setStreamOperatorCompleted(pOperator);
5,436✔
5542
    (*ppRes) = NULL;
5,435✔
5543
    return code;
5,435✔
5544
  }
5545

5546
  SOperatorInfo* downstream = pOperator->pDownstream[0];
14,287✔
5547

5548
  if (!pInfo->pUpdated) {
14,287✔
5549
    pInfo->pUpdated = taosArrayInit(4096, POINTER_BYTES);
12,624✔
5550
    QUERY_CHECK_NULL(pInfo->pUpdated, code, lino, _end, terrno);
12,622!
5551
  }
5552

5553
  if (!pInfo->pUpdatedMap) {
14,285✔
5554
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
12,622✔
5555
    pInfo->pUpdatedMap = tSimpleHashInit(4096, hashFn);
12,624✔
5556
    QUERY_CHECK_NULL(pInfo->pUpdatedMap, code, lino, _end, terrno);
12,628!
5557
  }
5558

5559
  while (1) {
698,853✔
5560
    SSDataBlock* pBlock = NULL;
713,144✔
5561
    code = downstream->fpSet.getNextFn(downstream, &pBlock);
713,144✔
5562
    QUERY_CHECK_CODE(code, lino, _end);
713,154!
5563

5564
    if (pBlock == NULL) {
713,154✔
5565
      qDebug("===stream===return data:%s. recv datablock num:%" PRIu64, getStreamOpName(pOperator->operatorType),
12,626✔
5566
             pInfo->numOfDatapack);
5567
      pInfo->numOfDatapack = 0;
12,627✔
5568
      break;
12,627✔
5569
    }
5570

5571
    pInfo->numOfDatapack++;
700,528✔
5572
    printSpecDataBlock(pBlock, getStreamOpName(pOperator->operatorType), "recv", GET_TASKID(pTaskInfo));
700,528✔
5573
    setStreamOperatorState(&pInfo->basic, pBlock->info.type);
700,528✔
5574

5575
    if (pBlock->info.type == STREAM_DELETE_DATA || pBlock->info.type == STREAM_DELETE_RESULT ||
700,525✔
5576
        pBlock->info.type == STREAM_CLEAR) {
700,151✔
5577
      code = doDeleteWindows(pOperator, &pInfo->interval, pBlock, pInfo->pDelWins, pInfo->pUpdatedMap, NULL);
1,041✔
5578
      QUERY_CHECK_CODE(code, lino, _end);
1,040!
5579
      continue;
2,351✔
5580
    } else if (pBlock->info.type == STREAM_GET_ALL) {
699,484✔
5581
      pInfo->recvGetAll = true;
722✔
5582
      code = getAllIntervalWindow(pInfo->aggSup.pResultRowHashTable, pInfo->pUpdatedMap);
722✔
5583
      QUERY_CHECK_CODE(code, lino, _end);
722!
5584
      continue;
722✔
5585
    } else if (pBlock->info.type == STREAM_CREATE_CHILD_TABLE) {
698,762✔
5586
      printDataBlock(pBlock, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
1,663✔
5587
      (*ppRes) = pBlock;
1,663✔
5588
      return code;
1,663✔
5589
    } else if (pBlock->info.type == STREAM_DROP_CHILD_TABLE) {
697,099!
UNCOV
5590
      doDeleteWindowByGroupId(pOperator, pBlock);
×
5591
      printDataBlock(pBlock, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
5592
      (*ppRes) = pBlock;
×
5593
      return code;
×
5594
    } else if (pBlock->info.type == STREAM_CHECKPOINT) {
697,099✔
5595
      pAPI->stateStore.streamStateCommit(pInfo->pState);
589✔
5596
      doStreamIntervalSaveCheckpoint(pOperator);
589✔
5597
      pInfo->reCkBlock = true;
589✔
5598
      code = copyDataBlock(pInfo->pCheckpointRes, pBlock);
589✔
5599
      QUERY_CHECK_CODE(code, lino, _end);
589!
5600

5601
      continue;
589✔
5602
    } else {
5603
      if (pBlock->info.type != STREAM_NORMAL && pBlock->info.type != STREAM_INVALID) {
696,510!
UNCOV
5604
        qDebug("===stream===%s ignore recv block. type:%d", GET_TASKID(pTaskInfo), pBlock->info.type);
×
5605
        continue;
×
5606
      }
5607
    }
5608

5609
    if (pBlock->info.type == STREAM_NORMAL && pBlock->info.version != 0) {
696,510✔
5610
      // set input version
5611
      pTaskInfo->version = pBlock->info.version;
66,419✔
5612
    }
5613

5614
    if (pInfo->scalarSupp.pExprInfo != NULL) {
696,510✔
5615
      SExprSupp* pExprSup = &pInfo->scalarSupp;
13✔
5616
      code = projectApplyFunctions(pExprSup->pExprInfo, pBlock, pBlock, pExprSup->pCtx, pExprSup->numOfExprs, NULL);
13✔
5617
      QUERY_CHECK_CODE(code, lino, _end);
13!
5618
    }
5619

5620
    // The timewindow that overlaps the timestamps of the input pBlock need to be recalculated and return to the
5621
    // caller. Note that all the time window are not close till now.
5622
    // the pDataBlock are always the same one, no need to call this again
5623
    code = setInputDataBlock(pSup, pBlock, TSDB_ORDER_ASC, MAIN_SCAN, true);
696,510✔
5624
    QUERY_CHECK_CODE(code, lino, _end);
696,504!
5625
#ifdef BUILD_NO_CALL
5626
    if (pInfo->invertible) {
5627
      setInverFunction(pSup->pCtx, pOperator->exprSupp.numOfExprs, pBlock->info.type);
5628
    }
5629
#endif
5630

5631
    code = doStreamIntervalAggImpl(pOperator, pBlock, pBlock->info.id.groupId, pInfo->pUpdatedMap, pInfo->pDeletedMap);
696,504✔
5632
    if (code == TSDB_CODE_STREAM_INTERNAL_ERROR) {
696,502!
UNCOV
5633
      pOperator->status = OP_RES_TO_RETURN;
×
5634
      code = TSDB_CODE_SUCCESS;
×
5635
      break;
×
5636
    }
5637
    QUERY_CHECK_CODE(code, lino, _end);
696,502!
5638
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.window.ekey);
696,502✔
5639
    pInfo->twAggSup.minTs = TMIN(pInfo->twAggSup.minTs, pBlock->info.window.skey);
696,502✔
5640
  }
5641
  pOperator->status = OP_RES_TO_RETURN;
12,627✔
5642
  if (!pInfo->destHasPrimaryKey) {
12,627✔
5643
    removeDeleteResults(pInfo->pUpdatedMap, pInfo->pDelWins);
12,608✔
5644
  }
5645
  code = closeStreamIntervalWindow(pInfo->aggSup.pResultRowHashTable, &pInfo->twAggSup, &pInfo->interval, NULL,
12,626✔
5646
                                   pInfo->pUpdatedMap, pInfo->pDelWins, pOperator);
5647
  QUERY_CHECK_CODE(code, lino, _end);
12,625!
5648

5649
  if (pInfo->destHasPrimaryKey && IS_NORMAL_INTERVAL_OP(pOperator)) {
12,625!
5650
    code = copyIntervalDeleteKey(pInfo->pDeletedMap, pInfo->pDelWins);
16✔
5651
    QUERY_CHECK_CODE(code, lino, _end);
16!
5652
  }
5653

5654
  void*   pIte = NULL;
12,625✔
5655
  int32_t iter = 0;
12,625✔
5656
  while ((pIte = tSimpleHashIterate(pInfo->pUpdatedMap, pIte, &iter)) != NULL) {
9,680,846✔
5657
    void* tmp = taosArrayPush(pInfo->pUpdated, pIte);
9,668,221✔
5658
    if (!tmp) {
9,668,221!
UNCOV
5659
      code = terrno;
×
5660
      QUERY_CHECK_CODE(code, lino, _end);
×
5661
    }
5662
  }
5663
  taosArraySort(pInfo->pUpdated, winPosCmprImpl);
12,624✔
5664

5665
  initMultiResInfoFromArrayList(&pInfo->groupResInfo, pInfo->pUpdated);
12,628✔
5666
  pInfo->pUpdated = NULL;
12,629✔
5667
  code = blockDataEnsureCapacity(pInfo->binfo.pRes, pOperator->resultInfo.capacity);
12,629✔
5668
  QUERY_CHECK_CODE(code, lino, _end);
12,629!
5669

5670
  tSimpleHashCleanup(pInfo->pUpdatedMap);
12,629✔
5671
  pInfo->pUpdatedMap = NULL;
12,628✔
5672

5673
  code = buildIntervalResult(pOperator, ppRes);
12,628✔
5674
  QUERY_CHECK_CODE(code, lino, _end);
12,628!
5675

5676
  return code;
12,628✔
5677

UNCOV
5678
_end:
×
5679
  if (code != TSDB_CODE_SUCCESS) {
×
5680
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
5681
    pTaskInfo->code = code;
×
5682
    T_LONG_JMP(pTaskInfo->env, code);
×
5683
  }
UNCOV
5684
  setStreamOperatorCompleted(pOperator);
×
5685
  (*ppRes) = NULL;
×
5686
  return code;
×
5687
}
5688

5689
int32_t createStreamSingleIntervalOperatorInfo(SOperatorInfo* downstream, SPhysiNode* pPhyNode,
2,026✔
5690
                                               SExecTaskInfo* pTaskInfo, SReadHandle* pHandle,
5691
                                               SOperatorInfo** pOptrInfo) {
5692
  QRY_PARAM_CHECK(pOptrInfo);
2,026!
5693

5694
  int32_t code = TSDB_CODE_SUCCESS;
2,026✔
5695
  int32_t lino = 0;
2,026✔
5696
  int32_t numOfCols = 0;
2,026✔
5697

5698
  SStreamIntervalOperatorInfo* pInfo = taosMemoryCalloc(1, sizeof(SStreamIntervalOperatorInfo));
2,026!
5699
  SOperatorInfo*               pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo));
2,026!
5700
  if (pInfo == NULL || pOperator == NULL) {
2,026!
UNCOV
5701
    code = terrno;
×
5702
    QUERY_CHECK_CODE(code, lino, _error);
×
5703
  }
5704

5705
  SStreamIntervalPhysiNode* pIntervalPhyNode = (SStreamIntervalPhysiNode*)pPhyNode;
2,026✔
5706

5707
  SSDataBlock* pResBlock = createDataBlockFromDescNode(pPhyNode->pOutputDataBlockDesc);
2,026✔
5708
  QUERY_CHECK_NULL(pResBlock, code, lino, _error, terrno);
2,026!
5709
  initBasicInfo(&pInfo->binfo, pResBlock);
2,026✔
5710

5711
  pInfo->interval = (SInterval){
2,026✔
5712
      .interval = pIntervalPhyNode->interval,
2,026✔
5713
      .sliding = pIntervalPhyNode->sliding,
2,026✔
5714
      .intervalUnit = pIntervalPhyNode->intervalUnit,
2,026✔
5715
      .slidingUnit = pIntervalPhyNode->slidingUnit,
2,026✔
5716
      .offset = pIntervalPhyNode->offset,
2,026✔
5717
      .precision = ((SColumnNode*)pIntervalPhyNode->window.pTspk)->node.resType.precision,
2,026✔
5718
      .timeRange = pIntervalPhyNode->timeRange,
2,026✔
5719
  };
5720
  calcIntervalAutoOffset(&pInfo->interval);
2,026✔
5721

5722
  pInfo->twAggSup =
2,026✔
5723
      (STimeWindowAggSupp){.waterMark = pIntervalPhyNode->window.watermark,
2,026✔
5724
                           .calTrigger = pIntervalPhyNode->window.triggerType,
2,026✔
5725
                           .maxTs = INT64_MIN,
5726
                           .minTs = INT64_MAX,
5727
                           .deleteMark = getDeleteMark(&pIntervalPhyNode->window, pIntervalPhyNode->interval)};
2,026✔
5728

5729
  pOperator->pTaskInfo = pTaskInfo;
2,026✔
5730
  SStorageAPI* pAPI = &pOperator->pTaskInfo->storageAPI;
2,026✔
5731

5732
  pInfo->ignoreExpiredData = pIntervalPhyNode->window.igExpired;
2,026✔
5733
  pInfo->ignoreExpiredDataSaved = false;
2,026✔
5734

5735
  SExprSupp* pSup = &pOperator->exprSupp;
2,026✔
5736
  pSup->hasWindowOrGroup = true;
2,026✔
5737

5738
  code = initExecTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &pTaskInfo->window);
2,026✔
5739
  QUERY_CHECK_CODE(code, lino, _error);
2,026!
5740

5741
  pInfo->primaryTsIndex = ((SColumnNode*)pIntervalPhyNode->window.pTspk)->slotId;
2,026✔
5742
  initResultSizeInfo(&pOperator->resultInfo, 4096);
2,026✔
5743

5744
  pInfo->pState = taosMemoryCalloc(1, sizeof(SStreamState));
2,026!
5745
  QUERY_CHECK_NULL(pInfo->pState, code, lino, _error, terrno);
2,026!
5746
  *(pInfo->pState) = *(pTaskInfo->streamInfo.pState);
2,026✔
5747
  pAPI->stateStore.streamStateSetNumber(pInfo->pState, -1, pInfo->primaryTsIndex);
2,026✔
5748

5749
  size_t     keyBufSize = sizeof(int64_t) + sizeof(int64_t) + POINTER_BYTES;
2,026✔
5750
  SExprInfo* pExprInfo = NULL;
2,026✔
5751
  code = createExprInfo(pIntervalPhyNode->window.pFuncs, NULL, &pExprInfo, &numOfCols);
2,026✔
5752
  QUERY_CHECK_CODE(code, lino, _error);
2,026!
5753
  code = initAggSup(pSup, &pInfo->aggSup, pExprInfo, numOfCols, keyBufSize, pTaskInfo->id.str, pInfo->pState,
2,026✔
5754
                    &pTaskInfo->storageAPI.functionStore);
5755
  QUERY_CHECK_CODE(code, lino, _error);
2,026!
5756

5757
  if (pIntervalPhyNode->window.pExprs != NULL) {
2,026✔
5758
    int32_t    numOfScalar = 0;
1✔
5759
    SExprInfo* pScalarExprInfo = NULL;
1✔
5760

5761
    code = createExprInfo(pIntervalPhyNode->window.pExprs, NULL, &pScalarExprInfo, &numOfScalar);
1✔
5762
    QUERY_CHECK_CODE(code, lino, _error);
1!
5763

5764
    code = initExprSupp(&pInfo->scalarSupp, pScalarExprInfo, numOfScalar, &pTaskInfo->storageAPI.functionStore);
1✔
5765
    QUERY_CHECK_CODE(code, lino, _error);
1!
5766
  }
5767

5768
  pInfo->invertible = false;
2,026✔
5769
  pInfo->pDelWins = taosArrayInit(4, sizeof(SWinKey));
2,026✔
5770
  QUERY_CHECK_NULL(pInfo->pDelWins, code, lino, _error, terrno);
2,026!
5771
  pInfo->delIndex = 0;
2,026✔
5772

5773
  code = createSpecialDataBlock(STREAM_DELETE_RESULT, &pInfo->pDelRes);
2,026✔
5774
  QUERY_CHECK_CODE(code, lino, _error);
2,025!
5775

5776
  initResultRowInfo(&pInfo->binfo.resultRowInfo);
2,025✔
5777

5778
  pInfo->pPhyNode = NULL;  // create new child
2,025✔
5779
  pInfo->pPullDataMap = NULL;
2,025✔
5780
  pInfo->pFinalPullDataMap = NULL;
2,025✔
5781
  pInfo->pPullWins = NULL;  // SPullWindowInfo
2,025✔
5782
  pInfo->pullIndex = 0;
2,025✔
5783
  pInfo->pPullDataRes = NULL;
2,025✔
5784
  pInfo->numOfChild = 0;
2,025✔
5785
  pInfo->delKey.ts = INT64_MAX;
2,025✔
5786
  pInfo->delKey.groupId = 0;
2,025✔
5787
  pInfo->numOfDatapack = 0;
2,025✔
5788
  pInfo->pUpdated = NULL;
2,025✔
5789
  pInfo->pUpdatedMap = NULL;
2,025✔
5790
  int32_t funResSize = getMaxFunResSize(pSup, numOfCols);
2,025✔
5791

5792
  pInfo->stateStore = pTaskInfo->storageAPI.stateStore;
2,026✔
5793
  pInfo->pState->pFileState = NULL;
2,026✔
5794

5795
  // used for backward compatibility of function's result info
5796
  pInfo->pState->pResultRowStore.resultRowGet = getResultRowFromBuf;
2,026✔
5797
  pInfo->pState->pResultRowStore.resultRowPut = putResultRowToBuf;
2,026✔
5798
  pInfo->pState->pExprSupp = &pOperator->exprSupp;
2,026✔
5799

5800
  code = pTaskInfo->storageAPI.stateStore.streamFileStateInit(
2,026✔
5801
      tsStreamBufferSize, sizeof(SWinKey), pInfo->aggSup.resultRowSize, funResSize, compareTs, pInfo->pState,
2,026✔
5802
      pInfo->twAggSup.deleteMark, GET_TASKID(pTaskInfo), pHandle->checkpointId, STREAM_STATE_BUFF_HASH,
2,026✔
5803
      &pInfo->pState->pFileState);
2,026✔
5804
  QUERY_CHECK_CODE(code, lino, _error);
2,026!
5805

5806
  pInfo->pOperator = pOperator;
2,026✔
5807
  setOperatorInfo(pOperator, "StreamIntervalOperator", QUERY_NODE_PHYSICAL_PLAN_STREAM_INTERVAL, true, OP_NOT_OPENED,
2,026✔
5808
                  pInfo, pTaskInfo);
5809
  pOperator->fpSet =
5810
      createOperatorFpSet(optrDummyOpenFn, doStreamIntervalAggNext, NULL, destroyStreamFinalIntervalOperatorInfo,
2,026✔
5811
                          optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
5812
  setOperatorStreamStateFn(pOperator, streamIntervalReleaseState, streamIntervalReloadState);
2,026✔
5813

5814
  code = initStreamBasicInfo(&pInfo->basic, pOperator);
2,026✔
5815
  QUERY_CHECK_CODE(code, lino, _error);
2,026!
5816

5817
  pInfo->recvGetAll = false;
2,026✔
5818

5819
  code = createSpecialDataBlock(STREAM_CHECKPOINT, &pInfo->pCheckpointRes);
2,026✔
5820
  QUERY_CHECK_CODE(code, lino, _error);
2,026!
5821

5822
  _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
2,026✔
5823
  pInfo->pDeletedMap = tSimpleHashInit(4096, hashFn);
2,026✔
5824
  QUERY_CHECK_NULL(pInfo->pDeletedMap, code, lino, _error, terrno);
2,026!
5825
  pInfo->destHasPrimaryKey = pIntervalPhyNode->window.destHasPrimaryKey;
2,026✔
5826

5827
  // for stream
5828
  void*   buff = NULL;
2,026✔
5829
  int32_t len = 0;
2,026✔
5830
  int32_t res = pAPI->stateStore.streamStateGetInfo(pInfo->pState, STREAM_INTERVAL_OP_CHECKPOINT_NAME,
2,026✔
5831
                                                    strlen(STREAM_INTERVAL_OP_CHECKPOINT_NAME), &buff, &len);
5832
  if (res == TSDB_CODE_SUCCESS) {
2,026✔
5833
    doStreamIntervalDecodeOpState(buff, len, pOperator);
4✔
5834
    taosMemoryFree(buff);
4!
5835
  }
5836

5837
  pInfo->basic.primaryPkIndex = -1;
2,026✔
5838
  code = initIntervalDownStream(downstream, pPhyNode->type, pInfo, &pInfo->basic);
2,026✔
5839
  QUERY_CHECK_CODE(code, lino, _error);
2,026!
5840

5841
  code = appendDownstream(pOperator, &downstream, 1);
2,026✔
5842
  QUERY_CHECK_CODE(code, lino, _error);
2,026!
5843

5844
  *pOptrInfo = pOperator;
2,026✔
5845
  return TSDB_CODE_SUCCESS;
2,026✔
5846

UNCOV
5847
_error:
×
5848
  if (pInfo != NULL) destroyStreamFinalIntervalOperatorInfo(pInfo);
×
5849
  destroyOperatorAndDownstreams(pOperator, &downstream, 1);
×
5850
  pTaskInfo->code = code;
×
5851
  return code;
×
5852
}
5853

5854
static void doStreamMidIntervalAggImpl(SOperatorInfo* pOperator, SSDataBlock* pSDataBlock, SSHashObj* pUpdatedMap) {
40✔
5855
  int32_t                      code = TSDB_CODE_SUCCESS;
40✔
5856
  int32_t                      lino = 0;
40✔
5857
  SStreamIntervalOperatorInfo* pInfo = (SStreamIntervalOperatorInfo*)pOperator->info;
40✔
5858
  pInfo->dataVersion = TMAX(pInfo->dataVersion, pSDataBlock->info.version);
40✔
5859

5860
  SResultRowInfo*  pResultRowInfo = &(pInfo->binfo.resultRowInfo);
40✔
5861
  SExecTaskInfo*   pTaskInfo = pOperator->pTaskInfo;
40✔
5862
  SExprSupp*       pSup = &pOperator->exprSupp;
40✔
5863
  int32_t          numOfOutput = pSup->numOfExprs;
40✔
5864
  int32_t          step = 1;
40✔
5865
  SRowBuffPos*     pResPos = NULL;
40✔
5866
  SResultRow*      pResult = NULL;
40✔
5867
  int32_t          forwardRows = 1;
40✔
5868
  uint64_t         groupId = pSDataBlock->info.id.groupId;
40✔
5869
  SColumnInfoData* pColDataInfo = taosArrayGet(pSDataBlock->pDataBlock, pInfo->primaryTsIndex);
40✔
5870
  TSKEY*           tsCol = (int64_t*)pColDataInfo->pData;
40✔
5871

5872
  int32_t     startPos = 0;
40✔
5873
  TSKEY       ts = getStartTsKey(&pSDataBlock->info.window, tsCol);
40✔
5874
  STimeWindow nextWin = getFinalTimeWindow(ts, &pInfo->interval);
40✔
5875

5876
  while (1) {
1,272✔
5877
    SWinKey key = {
1,312✔
5878
        .ts = nextWin.skey,
1,312✔
5879
        .groupId = groupId,
5880
    };
5881
    void*   chIds = taosHashGet(pInfo->pPullDataMap, &key, sizeof(SWinKey));
1,312✔
5882
    int32_t index = -1;
1,313✔
5883
    SArray* chArray = NULL;
1,313✔
5884
    int32_t chId = 0;
1,313✔
5885
    if (chIds) {
1,313✔
5886
      chArray = *(void**)chIds;
4✔
5887
      chId = getChildIndex(pSDataBlock);
4✔
5888
      index = taosArraySearchIdx(chArray, &chId, compareInt32Val, TD_EQ);
4✔
5889
    }
5890
    if (!(index == -1 || pSDataBlock->info.type == STREAM_PULL_DATA)) {
1,313!
UNCOV
5891
      startPos = getNextQualifiedFinalWindow(&pInfo->interval, &nextWin, &pSDataBlock->info, tsCol, startPos);
×
5892
      if (startPos < 0) {
×
5893
        break;
40✔
5894
      }
UNCOV
5895
      continue;
×
5896
    }
5897

5898
    if (!inSlidingWindow(&pInfo->interval, &nextWin, &pSDataBlock->info)) {
1,313!
UNCOV
5899
      startPos = getNexWindowPos(&pInfo->interval, &pSDataBlock->info, tsCol, startPos, nextWin.ekey, &nextWin);
×
5900
      if (startPos < 0) {
×
5901
        break;
×
5902
      }
UNCOV
5903
      continue;
×
5904
    }
5905

5906
    int32_t winCode = TSDB_CODE_SUCCESS;
1,313✔
5907
    code = setIntervalOutputBuf(pInfo->pState, &nextWin, &pResPos, groupId, pSup->pCtx, numOfOutput,
1,313✔
5908
                                pSup->rowEntryInfoOffset, &pInfo->aggSup, &pInfo->stateStore, &winCode);
5909
    QUERY_CHECK_CODE(code, lino, _end);
1,314!
5910

5911
    pResult = (SResultRow*)pResPos->pRowBuff;
1,314✔
5912

5913
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_AT_ONCE) {
1,314!
5914
      code = saveWinResult(&key, pResPos, pUpdatedMap);
1,314✔
5915
      QUERY_CHECK_CODE(code, lino, _end);
1,314!
5916
    }
5917

5918
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_WINDOW_CLOSE) {
1,314!
UNCOV
5919
      code = tSimpleHashPut(pInfo->aggSup.pResultRowHashTable, &key, sizeof(SWinKey), &pResPos, POINTER_BYTES);
×
5920
      QUERY_CHECK_CODE(code, lino, _end);
×
5921
    }
5922

5923
    updateTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &nextWin, 1);
1,314✔
5924
    code = applyAggFunctionOnPartialTuples(pTaskInfo, pSup->pCtx, &pInfo->twAggSup.timeWindowData, startPos,
1,314✔
5925
                                           forwardRows, pSDataBlock->info.rows, numOfOutput);
1,314✔
5926
    QUERY_CHECK_CODE(code, lino, _end);
1,312!
5927
    key.ts = nextWin.skey;
1,312✔
5928

5929
    if (pInfo->delKey.ts > key.ts) {
1,312✔
5930
      pInfo->delKey = key;
10✔
5931
    }
5932
    int32_t prevEndPos = (forwardRows - 1) * step + startPos;
1,312✔
5933
    if (pSDataBlock->info.window.skey <= 0 || pSDataBlock->info.window.ekey <= 0) {
1,312!
UNCOV
5934
      qError("table uid %" PRIu64 " data block timestamp range may not be calculated! minKey %" PRId64
×
5935
             ",maxKey %" PRId64,
5936
             pSDataBlock->info.id.uid, pSDataBlock->info.window.skey, pSDataBlock->info.window.ekey);
UNCOV
5937
      code = blockDataUpdateTsWindow(pSDataBlock, 0);
×
5938
      QUERY_CHECK_CODE(code, lino, _end);
×
5939

5940
      // timestamp of the data is incorrect
UNCOV
5941
      if (pSDataBlock->info.window.skey <= 0 || pSDataBlock->info.window.ekey <= 0) {
×
5942
        qError("table uid %" PRIu64 " data block timestamp is out of range! minKey %" PRId64 ",maxKey %" PRId64,
×
5943
               pSDataBlock->info.id.uid, pSDataBlock->info.window.skey, pSDataBlock->info.window.ekey);
5944
      }
5945
    }
5946
    startPos = getNextQualifiedFinalWindow(&pInfo->interval, &nextWin, &pSDataBlock->info, tsCol, prevEndPos);
1,312✔
5947
    if (startPos < 0) {
1,312✔
5948
      break;
40✔
5949
    }
5950
  }
5951

5952
_end:
40✔
5953
  if (code != TSDB_CODE_SUCCESS) {
40!
UNCOV
5954
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
5955
  }
5956
}
40✔
5957

5958
static int32_t addMidRetriveWindow(SArray* wins, SHashObj* pMidPullMap, int32_t numOfChild) {
12✔
5959
  int32_t code = TSDB_CODE_SUCCESS;
12✔
5960
  int32_t lino = 0;
12✔
5961
  int32_t size = taosArrayGetSize(wins);
12✔
5962
  for (int32_t i = 0; i < size; i++) {
18✔
5963
    SWinKey* winKey = taosArrayGet(wins, i);
6✔
5964
    void*    chIds = taosHashGet(pMidPullMap, winKey, sizeof(SWinKey));
6✔
5965
    if (!chIds) {
6!
5966
      code = addPullWindow(pMidPullMap, winKey, numOfChild);
6✔
5967
      qDebug("===stream===prepare mid operator retrive for delete %" PRId64 ", size:%d", winKey->ts, numOfChild);
6!
5968
      QUERY_CHECK_CODE(code, lino, _end);
6!
5969
    }
5970
  }
5971
_end:
12✔
5972
  if (code != TSDB_CODE_SUCCESS) {
12!
UNCOV
5973
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
5974
  }
5975
  return code;
12✔
5976
}
5977

5978
static SSDataBlock* buildMidIntervalResult(SOperatorInfo* pOperator) {
102✔
5979
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
102✔
5980
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
102✔
5981
  uint16_t                     opType = pOperator->operatorType;
102✔
5982

5983
  if (pInfo->recvPullover) {
102✔
5984
    pInfo->recvPullover = false;
6✔
5985
    printDataBlock(pInfo->pMidPulloverRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
6✔
5986
    return pInfo->pMidPulloverRes;
6✔
5987
  }
5988

5989
  qDebug("===stream=== build mid interval result");
96!
5990
  doBuildDeleteResult(pTaskInfo, pInfo->pMidPullDatas, &pInfo->midDelIndex, pInfo->pDelRes);
96✔
5991
  if (pInfo->pDelRes->info.rows != 0) {
96!
5992
    // process the rest of the data
UNCOV
5993
    printDataBlock(pInfo->pDelRes, getStreamOpName(opType), GET_TASKID(pTaskInfo));
×
5994
    return pInfo->pDelRes;
×
5995
  }
5996

5997
  if (pInfo->recvRetrive) {
96✔
5998
    pInfo->recvRetrive = false;
12✔
5999
    printDataBlock(pInfo->pMidRetriveRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
12✔
6000
    return pInfo->pMidRetriveRes;
12✔
6001
  }
6002

6003
  return NULL;
84✔
6004
}
6005

6006
static int32_t doStreamMidIntervalAggNext(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
104✔
6007
  int32_t                      code = TSDB_CODE_SUCCESS;
104✔
6008
  int32_t                      lino = 0;
104✔
6009
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
104✔
6010
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
104✔
6011
  SStorageAPI*                 pAPI = &pOperator->pTaskInfo->storageAPI;
104✔
6012
  SOperatorInfo*               downstream = pOperator->pDownstream[0];
104✔
6013
  SExprSupp*                   pSup = &pOperator->exprSupp;
104✔
6014

6015
  qDebug("stask:%s  %s status: %d", GET_TASKID(pTaskInfo), getStreamOpName(pOperator->operatorType), pOperator->status);
104!
6016

6017
  if (pOperator->status == OP_EXEC_DONE) {
104!
UNCOV
6018
    (*ppRes) = NULL;
×
6019
    return code;
×
6020
  } else if (pOperator->status == OP_RES_TO_RETURN) {
104✔
6021
    SSDataBlock* resBlock = NULL;
37✔
6022
    code = buildIntervalResult(pOperator, &resBlock);
37✔
6023
    QUERY_CHECK_CODE(code, lino, _end);
37!
6024
    if (resBlock != NULL) {
37✔
6025
      (*ppRes) = resBlock;
12✔
6026
      return code;
37✔
6027
    }
6028

6029
    setOperatorCompleted(pOperator);
25✔
6030
    clearFunctionContext(&pOperator->exprSupp);
25✔
6031
    clearStreamIntervalOperator(pInfo);
25✔
6032
    qDebug("stask:%s  ===stream===%s clear", GET_TASKID(pTaskInfo), getStreamOpName(pOperator->operatorType));
25!
6033
    (*ppRes) = NULL;
25✔
6034
    return code;
25✔
6035
  } else {
6036
    SSDataBlock* resBlock = NULL;
67✔
6037
    code = buildIntervalResult(pOperator, &resBlock);
67✔
6038
    QUERY_CHECK_CODE(code, lino, _end);
67!
6039
    if (resBlock != NULL) {
67!
UNCOV
6040
      (*ppRes) = resBlock;
×
6041
      return code;
2✔
6042
    }
6043

6044
    resBlock = buildMidIntervalResult(pOperator);
67✔
6045
    if (resBlock != NULL) {
67✔
6046
      (*ppRes) = resBlock;
2✔
6047
      return code;
2✔
6048
    }
6049

6050
    if (pInfo->clearState) {
65✔
6051
      pInfo->clearState = false;
18✔
6052
      clearFunctionContext(&pOperator->exprSupp);
18✔
6053
      clearStreamIntervalOperator(pInfo);
18✔
6054
    }
6055
  }
6056

6057
  if (!pInfo->pUpdated) {
65✔
6058
    pInfo->pUpdated = taosArrayInit(4096, POINTER_BYTES);
62✔
6059
    QUERY_CHECK_NULL(pInfo->pUpdated, code, lino, _end, terrno);
62!
6060
  }
6061
  if (!pInfo->pUpdatedMap) {
65✔
6062
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
62✔
6063
    pInfo->pUpdatedMap = tSimpleHashInit(4096, hashFn);
62✔
6064
    QUERY_CHECK_NULL(pInfo->pUpdatedMap, code, lino, _end, terrno);
62!
6065
  }
6066

6067
  while (1) {
56✔
6068
    if (isTaskKilled(pTaskInfo)) {
121!
UNCOV
6069
      qInfo("===stream=== %s task is killed, code %s", GET_TASKID(pTaskInfo), tstrerror(pTaskInfo->code));
×
6070
      (*ppRes) = NULL;
×
6071
      return code;
3✔
6072
    }
6073

6074
    SSDataBlock* pBlock = NULL;
121✔
6075
    code = downstream->fpSet.getNextFn(downstream, &pBlock);
121✔
6076
    QUERY_CHECK_CODE(code, lino, _end);
121!
6077

6078
    if (pBlock == NULL) {
121✔
6079
      pOperator->status = OP_RES_TO_RETURN;
44✔
6080
      qDebug("===stream===return data:%s. recv datablock num:%" PRIu64, getStreamOpName(pOperator->operatorType),
44!
6081
             pInfo->numOfDatapack);
6082
      pInfo->numOfDatapack = 0;
44✔
6083
      break;
44✔
6084
    }
6085
    pInfo->numOfDatapack++;
77✔
6086
    printSpecDataBlock(pBlock, getStreamOpName(pOperator->operatorType), "recv", GET_TASKID(pTaskInfo));
77✔
6087
    setStreamOperatorState(&pInfo->basic, pBlock->info.type);
77✔
6088

6089
    if (pBlock->info.type == STREAM_NORMAL || pBlock->info.type == STREAM_PULL_DATA) {
77✔
6090
      pInfo->binfo.pRes->info.type = pBlock->info.type;
8✔
6091
    } else if (pBlock->info.type == STREAM_DELETE_DATA || pBlock->info.type == STREAM_DELETE_RESULT ||
69!
6092
               pBlock->info.type == STREAM_CLEAR) {
67✔
6093
      SArray* delWins = taosArrayInit(8, sizeof(SWinKey));
3✔
6094
      if (!delWins) {
3!
UNCOV
6095
        code = terrno;
×
6096
        QUERY_CHECK_CODE(code, lino, _end);
×
6097
      }
6098
      code =
6099
          doDeleteWindows(pOperator, &pInfo->interval, pBlock, delWins, pInfo->pUpdatedMap, pInfo->pFinalPullDataMap);
3✔
6100
      QUERY_CHECK_CODE(code, lino, _end);
3!
6101

6102
      removeResults(delWins, pInfo->pUpdatedMap);
3✔
6103
      void* tmp = taosArrayAddAll(pInfo->pDelWins, delWins);
3✔
6104
      if (!tmp && taosArrayGetSize(delWins) > 0) {
3!
UNCOV
6105
        code = TSDB_CODE_OUT_OF_MEMORY;
×
6106
        QUERY_CHECK_CODE(code, lino, _end);
×
6107
      }
6108
      taosArrayDestroy(delWins);
3✔
6109

6110
      doBuildDeleteResult(pTaskInfo, pInfo->pDelWins, &pInfo->delIndex, pInfo->pDelRes);
3✔
6111
      if (pInfo->pDelRes->info.rows != 0) {
3!
6112
        // process the rest of the data
6113
        printDataBlock(pInfo->pDelRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
3✔
6114
        if (pBlock->info.type == STREAM_CLEAR) {
3✔
6115
          pInfo->pDelRes->info.type = STREAM_CLEAR;
1✔
6116
        } else {
6117
          pInfo->pDelRes->info.type = STREAM_DELETE_RESULT;
2✔
6118
        }
6119
        (*ppRes) = pInfo->pDelRes;
3✔
6120
        return code;
3✔
6121
      }
6122
      continue;
16✔
6123
    } else if (pBlock->info.type == STREAM_CREATE_CHILD_TABLE) {
66!
UNCOV
6124
      (*ppRes) = pBlock;
×
6125
      return code;
×
6126
    } else if (pBlock->info.type == STREAM_PULL_OVER) {
66✔
6127
      code = processPullOver(pBlock, pInfo->pPullDataMap, pInfo->pFinalPullDataMap, &pInfo->interval, pInfo->pPullWins,
12✔
6128
                             pInfo->numOfChild, pOperator, &pInfo->recvPullover);
6129
      QUERY_CHECK_CODE(code, lino, _end);
12!
6130

6131
      if (pInfo->recvPullover) {
12✔
6132
        code = copyDataBlock(pInfo->pMidPulloverRes, pBlock);
6✔
6133
        QUERY_CHECK_CODE(code, lino, _end);
6!
6134

6135
        pInfo->clearState = true;
6✔
6136
        break;
6✔
6137
      }
6138
      continue;
6✔
6139
    } else if (pBlock->info.type == STREAM_CHECKPOINT) {
54✔
6140
      pAPI->stateStore.streamStateCommit(pInfo->pState);
10✔
6141
      doStreamIntervalSaveCheckpoint(pOperator);
10✔
6142
      code = copyDataBlock(pInfo->pCheckpointRes, pBlock);
10✔
6143
      QUERY_CHECK_CODE(code, lino, _end);
10!
6144

6145
      continue;
10✔
6146
    } else if (pBlock->info.type == STREAM_MID_RETRIEVE) {
44✔
6147
      SArray* delWins = taosArrayInit(8, sizeof(SWinKey));
12✔
6148
      if (!delWins) {
12!
UNCOV
6149
        code = terrno;
×
6150
        QUERY_CHECK_CODE(code, lino, _end);
×
6151
      }
6152
      code = doDeleteWindows(pOperator, &pInfo->interval, pBlock, delWins, pInfo->pUpdatedMap, NULL);
12✔
6153
      QUERY_CHECK_CODE(code, lino, _end);
12!
6154

6155
      code = addMidRetriveWindow(delWins, pInfo->pPullDataMap, pInfo->numOfChild);
12✔
6156
      QUERY_CHECK_CODE(code, lino, _end);
12!
6157

6158
      taosArrayDestroy(delWins);
12✔
6159
      pInfo->recvRetrive = true;
12✔
6160
      code = copyDataBlock(pInfo->pMidRetriveRes, pBlock);
12✔
6161
      QUERY_CHECK_CODE(code, lino, _end);
12!
6162

6163
      pInfo->pMidRetriveRes->info.type = STREAM_MID_RETRIEVE;
12✔
6164
      pInfo->clearState = true;
12✔
6165
      break;
12✔
6166
    } else {
6167
      if (pBlock->info.type != STREAM_INVALID) {
32!
UNCOV
6168
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
6169
        QUERY_CHECK_CODE(code, lino, _end);
×
6170
      }
6171
    }
6172

6173
    if (pInfo->scalarSupp.pExprInfo != NULL) {
40!
UNCOV
6174
      SExprSupp* pExprSup = &pInfo->scalarSupp;
×
6175
      code = projectApplyFunctions(pExprSup->pExprInfo, pBlock, pBlock, pExprSup->pCtx, pExprSup->numOfExprs, NULL);
×
6176
      QUERY_CHECK_CODE(code, lino, _end);
×
6177
    }
6178
    code = setInputDataBlock(pSup, pBlock, TSDB_ORDER_ASC, MAIN_SCAN, true);
40✔
6179
    QUERY_CHECK_CODE(code, lino, _end);
40!
6180
    doStreamMidIntervalAggImpl(pOperator, pBlock, pInfo->pUpdatedMap);
40✔
6181
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.window.ekey);
40✔
6182
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.watermark);
40✔
6183
    pInfo->twAggSup.minTs = TMIN(pInfo->twAggSup.minTs, pBlock->info.window.skey);
40✔
6184
  }
6185

6186
  removeDeleteResults(pInfo->pUpdatedMap, pInfo->pDelWins);
62✔
6187
  pInfo->binfo.pRes->info.watermark = pInfo->twAggSup.maxTs;
62✔
6188

6189
  void*   pIte = NULL;
62✔
6190
  int32_t iter = 0;
62✔
6191
  while ((pIte = tSimpleHashIterate(pInfo->pUpdatedMap, pIte, &iter)) != NULL) {
1,276✔
6192
    void* tmp = taosArrayPush(pInfo->pUpdated, pIte);
1,214✔
6193
    if (!tmp) {
1,214!
UNCOV
6194
      code = terrno;
×
6195
      QUERY_CHECK_CODE(code, lino, _end);
×
6196
    }
6197
  }
6198

6199
  tSimpleHashCleanup(pInfo->pUpdatedMap);
62✔
6200
  pInfo->pUpdatedMap = NULL;
62✔
6201
  taosArraySort(pInfo->pUpdated, winPosCmprImpl);
62✔
6202

6203
  initMultiResInfoFromArrayList(&pInfo->groupResInfo, pInfo->pUpdated);
62✔
6204
  pInfo->pUpdated = NULL;
62✔
6205
  code = blockDataEnsureCapacity(pInfo->binfo.pRes, pOperator->resultInfo.capacity);
62✔
6206
  QUERY_CHECK_CODE(code, lino, _end);
62!
6207

6208
  SSDataBlock* resBlock = NULL;
62✔
6209
  code = buildIntervalResult(pOperator, &resBlock);
62✔
6210
  QUERY_CHECK_CODE(code, lino, _end);
62!
6211
  if (resBlock != NULL) {
62✔
6212
    (*ppRes) = resBlock;
27✔
6213
    return code;
27✔
6214
  }
6215

6216
  resBlock = buildMidIntervalResult(pOperator);
35✔
6217
  if (resBlock != NULL) {
35✔
6218
    (*ppRes) = resBlock;
16✔
6219
    return code;
16✔
6220
  }
6221

6222
  if (pInfo->clearState) {
19!
UNCOV
6223
    pInfo->clearState = false;
×
6224
    clearFunctionContext(&pOperator->exprSupp);
×
6225
    clearStreamIntervalOperator(pInfo);
×
6226
  }
6227

6228
_end:
19✔
6229
  if (code != TSDB_CODE_SUCCESS) {
19!
UNCOV
6230
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
6231
    pTaskInfo->code = code;
×
6232
    T_LONG_JMP(pTaskInfo->env, code);
×
6233
  }
6234
  (*ppRes) = NULL;
19✔
6235
  return code;
19✔
6236
}
6237

UNCOV
6238
static SSDataBlock* doStreamMidIntervalAgg(SOperatorInfo* pOperator) {
×
6239
  SSDataBlock* pRes = NULL;
×
6240
  int32_t      code = doStreamMidIntervalAggNext(pOperator, &pRes);
×
6241
  return pRes;
×
6242
}
6243

6244
void setStreamOperatorCompleted(SOperatorInfo* pOperator) {
26,461✔
6245
  qDebug("stask:%s  %s status: %d. set completed", GET_TASKID(pOperator->pTaskInfo),
26,461✔
6246
         getStreamOpName(pOperator->operatorType), pOperator->status);
6247
  setOperatorCompleted(pOperator);
26,461✔
6248
}
26,466✔
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