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

taosdata / TDengine / #3660

15 Mar 2025 09:06AM UTC coverage: 62.039% (-1.3%) from 63.314%
#3660

push

travis-ci

web-flow
feat(stream): support stream processing for virtual tables (#30144)

* enh: add client processing

* enh: add mnode vtables processing

* enh: add mnode vtable processing

* enh: add normal child vtable support

* fix: compile issues

* fix: compile issues

* fix: create stream issues

* fix: multi stream scan issue

* fix: remove debug info

* fix: agg task and task level issues

* fix: correct task output type

* fix: split vtablescan from agg

* fix: memory leak issues

* fix: add limitations

* Update 09-error-code.md

* Update 09-error-code.md

* fix: remove usless case

* feat(stream): extract original table data in source scan task

Implemented functionality in the source task to extract data
corresponding to the virtual table from the original table using WAL.
The extracted data is then sent to the downstream merge task for further
processing.

* feat(stream): multi-way merge using loser tree in virtual merge task

Implemented multi-way merge in the merge task using a loser tree to
combine data from multiple original table into a single virtual table.
The merged virtual table data is then pushed downstream for further
processing.  Introduced memory limit handling during the merge process
with configurable behavior when the memory limit is reached.

* fix(test): remove useless cases

---------

Co-authored-by: dapan1121 <wpan@taosdata.com>
Co-authored-by: Pan Wei <72057773+dapan1121@users.noreply.github.com>

154078 of 317582 branches covered (48.52%)

Branch coverage included in aggregate %.

313 of 2391 new or added lines in 34 files covered. (13.09%)

26134 existing lines in 205 files now uncovered.

240261 of 318051 relevant lines covered (75.54%)

16655189.27 hits per line

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

71.35
/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,634✔
51
  int firstPos = 0, lastPos = num - 1, midPos = -1;
1,634✔
52
  int numOfRows = 0;
1,634✔
53

54
  if (num <= 0) return -1;
1,634✔
55
  if (order == TSDB_ORDER_DESC) {
1,411!
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,556✔
59
      if (comparefn(pKey, keyList, firstPos) == 0) return firstPos;
448✔
60
      if (comparefn(pKey, keyList, firstPos) < 0) return firstPos - 1;
308✔
61

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

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

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

UNCOV
80
      if (comparefn(pKey, keyList, lastPos) > 0) {
×
UNCOV
81
        lastPos = lastPos + 1;
×
UNCOV
82
        if (lastPos >= num)
×
UNCOV
83
          return -1;
×
84
        else
UNCOV
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;
81✔
102
}
103

104
static int32_t comparePullWinKey(void* pKey, void* data, int32_t index) {
189✔
105
  SArray*          res = (SArray*)data;
189✔
106
  SPullWindowInfo* pos = taosArrayGet(res, index);
189✔
107
  SPullWindowInfo* pData = (SPullWindowInfo*)pKey;
189✔
108
  if (pData->groupId > pos->groupId) {
189✔
109
    return 1;
67✔
110
  } else if (pData->groupId < pos->groupId) {
122✔
111
    return -1;
67✔
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;
175✔
127
  } else {
128
    int32_t code = comparePullWinKey(pPullInfo, pPullWins, index);
49✔
129
    if (code == 0) {
49✔
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) {
46!
137
      index++;
46✔
138
    }
139
  }
140
  if (taosArrayInsert(pPullWins, index, pPullInfo) == NULL) {
221!
UNCOV
141
    return terrno;
×
142
  }
143
  return TSDB_CODE_SUCCESS;
221✔
144
}
145

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

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

163
static int32_t saveWinResultInfo(TSKEY ts, uint64_t groupId, SRowBuffPos* pPos, SSHashObj* pUpdatedMap) {
306✔
164
  SWinKey key = {.ts = ts, .groupId = groupId};
306✔
165
  return saveWinResult(&key, pPos, pUpdatedMap);
306✔
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!
UNCOV
174
      void* value = *(void**)tmp;
×
UNCOV
175
      taosMemoryFree(value);
×
UNCOV
176
      int32_t tmpRes = tSimpleHashRemove(pUpdatedMap, pW, sizeof(SWinKey));
×
UNCOV
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) {
3,807✔
183
  void* pDataPos = taosArrayGet((SArray*)data, index);
3,807✔
184
  return winKeyCmprImpl(pKey, pDataPos);
3,809✔
185
}
186

187
void removeDeleteResults(SSHashObj* pUpdatedMap, SArray* pDelWins) {
28,647✔
188
  taosArraySort(pDelWins, winKeyCmprImpl);
28,647✔
189
  taosArrayRemoveDuplicate(pDelWins, winKeyCmprImpl, NULL);
28,643✔
190
  int32_t delSize = taosArrayGetSize(pDelWins);
28,640✔
191
  if (tSimpleHashGetSize(pUpdatedMap) == 0 || delSize == 0) {
28,639✔
192
    return;
28,042✔
193
  }
194
  void*   pIte = NULL;
594✔
195
  int32_t iter = 0;
594✔
196
  while ((pIte = tSimpleHashIterate(pUpdatedMap, pIte, &iter)) != NULL) {
1,762✔
197
    SWinKey* pResKey = tSimpleHashGetKey(pIte, NULL);
1,168✔
198
    int32_t  index = binarySearchCom(pDelWins, delSize, pResKey, TSDB_ORDER_DESC, compareWinKey);
1,168✔
199
    if (index >= 0 && 0 == compareWinKey(pResKey, pDelWins, index)) {
1,168✔
200
      taosArrayRemove(pDelWins, index);
909✔
201
      delSize = taosArrayGetSize(pDelWins);
909✔
202
    }
203
  }
204
}
205

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

210
bool isCloseWindow(STimeWindow* pWin, STimeWindowAggSupp* pTwSup) { return isOverdue(pWin->ekey, pTwSup); }
41,690,395✔
211

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

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

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

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

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

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

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

267
    STimeWindow win = {0};
2,717✔
268
    if (IS_FINAL_INTERVAL_OP(pOperator) || IS_MID_INTERVAL_OP(pOperator)) {
2,717✔
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,456✔
273
    }
274

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

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

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

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

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

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

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

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

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

410
void doBuildDeleteResultImpl(SStateStore* pAPI, SStreamState* pState, SArray* pWins, int32_t* index,
156,045✔
411
                             SSDataBlock* pBlock) {
412
  int32_t code = TSDB_CODE_SUCCESS;
156,045✔
413
  int32_t lino = 0;
156,045✔
414
  blockDataCleanup(pBlock);
156,045✔
415
  int32_t size = taosArrayGetSize(pWins);
156,047✔
416
  if (*index == size) {
156,049✔
417
    *index = 0;
155,339✔
418
    taosArrayClear(pWins);
155,339✔
419
    goto _end;
155,335✔
420
  }
421
  code = blockDataEnsureCapacity(pBlock, size - *index);
710✔
422
  QUERY_CHECK_CODE(code, lino, _end);
710!
423

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

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

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

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

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

465
void clearGroupResInfo(SGroupResInfo* pGroupResInfo) {
6,595✔
466
  int32_t size = taosArrayGetSize(pGroupResInfo->pRows);
6,595✔
467
  if (pGroupResInfo->index >= 0 && pGroupResInfo->index < size) {
6,596!
468
    for (int32_t i = pGroupResInfo->index; i < size; i++) {
875,794✔
469
      void* pPos = taosArrayGetP(pGroupResInfo->pRows, i);
875,792✔
470
      destroyFlusedPos(pPos);
875,792✔
471
    }
472
  }
473
  pGroupResInfo->freeItem = false;
6,596✔
474
  taosArrayDestroy(pGroupResInfo->pRows);
6,596✔
475
  pGroupResInfo->pRows = NULL;
6,596✔
476
  pGroupResInfo->index = 0;
6,596✔
477
  pGroupResInfo->delIndex = 0;
6,596✔
478
}
6,596✔
479

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

492
  destroyStreamBasicInfo(&pInfo->basic);
4,000✔
493
  cleanupAggSup(&pInfo->aggSup);
3,999✔
494
  clearGroupResInfo(&pInfo->groupResInfo);
4,000✔
495
  taosArrayDestroyP(pInfo->pUpdated, destroyFlusedPos);
4,000✔
496
  pInfo->pUpdated = NULL;
4,000✔
497

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

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

523
  if (pInfo->pState != NULL && pInfo->pState->dump == 1) {
4,000!
524
    taosMemoryFreeClear(pInfo->pState->pTdbState->pOwner);
929!
525
    taosMemoryFreeClear(pInfo->pState->pTdbState);
929!
526
  }
527
  taosMemoryFreeClear(pInfo->pState);
4,000!
528

529
  nodesDestroyNode((SNode*)pInfo->pPhyNode);
4,000✔
530
  colDataDestroy(&pInfo->twAggSup.timeWindowData);
3,999✔
531
  cleanupExprSupp(&pInfo->scalarSupp);
4,000✔
532
  tSimpleHashCleanup(pInfo->pDeletedMap);
4,000✔
533

534
  blockDataDestroy(pInfo->pCheckpointRes);
4,000✔
535

536
  taosMemoryFreeClear(param);
4,000!
537
}
538

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

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

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

558
  SStreamScanInfo* pScanInfo = downstream->info;
1,287✔
559
  pInfo->pUpdateInfo = pScanInfo->pUpdateInfo;
1,287✔
560
}
561

562
bool hasSrcPrimaryKeyCol(SSteamOpBasicInfo* pInfo) { return pInfo->primaryPkIndex != -1; }
11,545,894✔
563

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

571
  if (downstream->operatorType == QUERY_NODE_PHYSICAL_PLAN_STREAM_PARTITION) {
4,040✔
572
    SStreamPartitionOperatorInfo* pScanInfo = downstream->info;
264✔
573
    pBasic->primaryPkIndex = pScanInfo->basic.primaryPkIndex;
264✔
574
  }
575

576
  if (downstream->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_SCAN) {
4,040✔
577
    return initIntervalDownStream(downstream->pDownstream[0], type, pInfo, pBasic);
264✔
578
  }
579

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

589
  pScanInfo->interval = pInfo->interval;
3,776✔
590
  pScanInfo->twAggSup = pInfo->twAggSup;
3,776✔
591
  pScanInfo->pState = pInfo->pState;
3,776✔
592
  pInfo->pUpdateInfo = pScanInfo->pUpdateInfo;
3,776✔
593
  if (!hasSrcPrimaryKeyCol(pBasic)) {
3,776✔
594
    pBasic->primaryPkIndex = pScanInfo->basic.primaryPkIndex;
3,774✔
595
  }
596

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

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

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

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

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

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

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

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

659
  code = pStore->streamStateAddIfNotExist(pState, &key, (void**)&value, &size, pWinCode);
10,378,284✔
660
  QUERY_CHECK_CODE(code, lino, _end);
10,378,945!
661

662
  *pResult = (SRowBuffPos*)value;
10,378,945✔
663
  SResultRow* res = (SResultRow*)((*pResult)->pRowBuff);
10,378,945✔
664

665
  // set time window for current result
666
  res->win = (*win);
10,378,945✔
667
  code = setResultRowInitCtx(res, pCtx, numOfOutput, rowEntryInfoOffset);
10,378,945✔
668
  QUERY_CHECK_CODE(code, lino, _end);
10,377,103!
669

670
_end:
10,377,103✔
671
  if (code != TSDB_CODE_SUCCESS) {
10,377,103!
UNCOV
672
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
673
  }
674
  return code;
10,377,439✔
675
}
676

677
bool isDeletedStreamWindow(STimeWindow* pWin, uint64_t groupId, void* pState, STimeWindowAggSupp* pTwSup,
31,103,995✔
678
                           SStateStore* pStore) {
679
  if (pTwSup->maxTs != INT64_MIN && pWin->ekey < pTwSup->maxTs - pTwSup->deleteMark) {
31,103,995✔
680
    SWinKey key = {.ts = pWin->skey, .groupId = groupId};
26✔
681
    if (!hasIntervalWindow(pState, &key, pStore)) {
26✔
682
      return true;
15✔
683
    }
684
    return false;
11✔
685
  }
686
  return false;
31,103,969✔
687
}
688

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

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

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

726
static void clearSpecialDataBlock(SSDataBlock* pBlock) {
4,414✔
727
  if (pBlock->info.rows <= 0) {
4,414✔
728
    return;
4,256✔
729
  }
730
  blockDataCleanup(pBlock);
158✔
731
}
732

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

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

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

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

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

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

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

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

785
_end:
158✔
786
  if (code != TSDB_CODE_SUCCESS) {
4,414!
UNCOV
787
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
788
  }
789
}
4,414✔
790

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

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

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

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

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

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

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

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

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

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

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

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

940
  int32_t numOfRows = getNumOfTotalRes(pGroupResInfo);
115,279✔
941

942
  for (int32_t i = pGroupResInfo->index; i < numOfRows; i += 1) {
9,143,712✔
943
    SRowBuffPos* pPos = *(SRowBuffPos**)taosArrayGet(pGroupResInfo->pRows, i);
9,126,336✔
944
    SResultRow*  pRow = NULL;
9,126,320✔
945
    code = getOutputBuf(pState, pPos, &pRow, &pAPI->stateStore);
9,126,320✔
946
    QUERY_CHECK_CODE(code, lino, _end);
9,126,311!
947
    uint64_t groupId = ((SWinKey*)pPos->pKey)->groupId;
9,126,311✔
948
    doUpdateNumOfRows(pCtx, pRow, numOfExprs, rowEntryOffset);
9,126,311✔
949
    // no results, continue to check the next one
950
    if (pRow->numOfRows == 0) {
9,126,304!
UNCOV
951
      pGroupResInfo->index += 1;
×
UNCOV
952
      continue;
×
953
    }
954
    if (pBlock->info.id.groupId == 0) {
9,126,304✔
955
      pBlock->info.id.groupId = groupId;
593,245✔
956
      void*   tbname = NULL;
593,245✔
957
      int32_t winCode = TSDB_CODE_SUCCESS;
593,245✔
958
      code = pAPI->stateStore.streamStateGetParName(pTaskInfo->streamInfo.pState, pBlock->info.id.groupId, &tbname,
593,245✔
959
                                                    false, &winCode);
960
      QUERY_CHECK_CODE(code, lino, _end);
593,244!
961
      if (winCode != TSDB_CODE_SUCCESS) {
593,244✔
962
        pBlock->info.parTbName[0] = 0;
587,061✔
963
      } else {
964
        memcpy(pBlock->info.parTbName, tbname, TSDB_TABLE_NAME_LEN);
6,183✔
965
      }
966
      pAPI->stateStore.streamStateFreeVal(tbname);
593,244✔
967
    } else {
968
      // current value belongs to different group, it can't be packed into one datablock
969
      if (pBlock->info.id.groupId != groupId) {
8,533,059✔
970
        break;
97,846✔
971
      }
972
    }
973

974
    if (pBlock->info.rows + pRow->numOfRows > pBlock->info.capacity) {
9,029,653✔
975
      break;
1,194✔
976
    }
977
    pGroupResInfo->index += 1;
9,028,459✔
978

979
    for (int32_t j = 0; j < numOfExprs; ++j) {
70,633,965✔
980
      int32_t slotId = pExprInfo[j].base.resSchema.slotId;
61,605,533✔
981

982
      pCtx[j].resultInfo = getResultEntryInfo(pRow, j, rowEntryOffset);
61,605,533✔
983

984
      if (pCtx[j].fpSet.finalize) {
61,605,497✔
985
        int32_t tmpRes = pCtx[j].fpSet.finalize(&pCtx[j], pBlock);
40,895,758✔
986
        if (TAOS_FAILED(tmpRes)) {
40,895,739!
UNCOV
987
          qError("%s build result data block error, code %s", GET_TASKID(pTaskInfo), tstrerror(tmpRes));
×
988
          QUERY_CHECK_CODE(code, lino, _end);
12!
989
        }
990
      } else if (strcmp(pCtx[j].pExpr->pExpr->_function.functionName, "_select_value") == 0) {
20,709,739✔
991
        // do nothing, todo refactor
992
      } else {
993
        // expand the result into multiple rows. E.g., _wstart, top(k, 20)
994
        // the _wstart needs to copy to 20 following rows, since the results of top-k expands to 20 different rows.
995
        SColumnInfoData* pColInfoData = taosArrayGet(pBlock->pDataBlock, slotId);
20,636,416✔
996
        char*            in = GET_ROWCELL_INTERBUF(pCtx[j].resultInfo);
20,636,415✔
997
        for (int32_t k = 0; k < pRow->numOfRows; ++k) {
41,272,847✔
998
          code = colDataSetVal(pColInfoData, pBlock->info.rows + k, in, pCtx[j].resultInfo->isNullRes);
20,636,415✔
999
          QUERY_CHECK_CODE(code, lino, _end);
20,636,432!
1000
        }
1001
      }
1002
    }
1003

1004
    if (pSessionKeys) {
9,028,432!
UNCOV
1005
      SSessionKey key = {.groupId = groupId, .win = pRow->win};
×
UNCOV
1006
      for (int32_t j = 0; j < pRow->numOfRows; ++j) {
×
UNCOV
1007
        const void* px = taosArrayPush(pSessionKeys, &key);
×
UNCOV
1008
        QUERY_CHECK_NULL(px, code, lino, _end, terrno);
×
1009
      }
1010
    }
1011

1012
    pBlock->info.rows += pRow->numOfRows;
9,028,432✔
1013
  }
1014

1015
  pBlock->info.dataLoad = 1;
115,222✔
1016
  code = blockDataUpdateTsWindow(pBlock, 0);
115,222✔
1017
  QUERY_CHECK_CODE(code, lino, _end);
115,276!
1018

1019
_end:
115,276✔
1020
  if (code != TSDB_CODE_SUCCESS) {
115,276!
UNCOV
1021
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
1022
  }
1023
}
115,276✔
1024

1025
void doBuildStreamIntervalResult(SOperatorInfo* pOperator, void* pState, SSDataBlock* pBlock,
155,366✔
1026
                                 SGroupResInfo* pGroupResInfo, SArray* pSessionKeys) {
1027
  SExecTaskInfo* pTaskInfo = pOperator->pTaskInfo;
155,366✔
1028
  // set output datablock version
1029
  pBlock->info.version = pTaskInfo->version;
155,366✔
1030

1031
  blockDataCleanup(pBlock);
155,366✔
1032
  taosArrayClear(pSessionKeys);
155,368✔
1033
  if (!hasRemainResults(pGroupResInfo)) {
155,368✔
1034
    return;
40,090✔
1035
  }
1036

1037
  // clear the existed group id
1038
  pBlock->info.id.groupId = 0;
115,280✔
1039
  buildDataBlockFromGroupRes(pOperator, pState, pBlock, &pOperator->exprSupp, pGroupResInfo, pSessionKeys);
115,280✔
1040
}
1041

1042
int32_t getNextQualifiedFinalWindow(SInterval* pInterval, STimeWindow* pNext, SDataBlockInfo* pDataBlockInfo,
246,606✔
1043
                                    TSKEY* primaryKeys, int32_t prevPosition) {
1044
  int32_t startPos = prevPosition + 1;
246,606✔
1045
  if (startPos == pDataBlockInfo->rows) {
246,606✔
1046
    startPos = -1;
2,697✔
1047
  } else {
1048
    *pNext = getFinalTimeWindow(primaryKeys[startPos], pInterval);
243,909✔
1049
  }
1050
  return startPos;
246,606✔
1051
}
1052

1053
static int32_t doStreamIntervalAggImpl(SOperatorInfo* pOperator, SSDataBlock* pSDataBlock, uint64_t groupId,
1,154,315✔
1054
                                       SSHashObj* pUpdatedMap, SSHashObj* pDeletedMap) {
1055
  int32_t                      code = TSDB_CODE_SUCCESS;
1,154,315✔
1056
  int32_t                      lino = 0;
1,154,315✔
1057
  SStreamIntervalOperatorInfo* pInfo = (SStreamIntervalOperatorInfo*)pOperator->info;
1,154,315✔
1058
  pInfo->dataVersion = TMAX(pInfo->dataVersion, pSDataBlock->info.version);
1,154,315✔
1059

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

1071
  SColumnInfoData* pColDataInfo = taosArrayGet(pSDataBlock->pDataBlock, pInfo->primaryTsIndex);
1,154,315✔
1072
  tsCols = (int64_t*)pColDataInfo->pData;
1,154,316✔
1073

1074
  void*            pPkVal = NULL;
1,154,316✔
1075
  int32_t          pkLen = 0;
1,154,316✔
1076
  SColumnInfoData* pPkColDataInfo = NULL;
1,154,316✔
1077
  if (hasSrcPrimaryKeyCol(&pInfo->basic)) {
1,154,316✔
1078
    pPkColDataInfo = taosArrayGet(pSDataBlock->pDataBlock, pInfo->basic.primaryPkIndex);
389,751✔
1079
  }
1080

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

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

1094
  int32_t     startPos = 0;
1,154,311✔
1095
  TSKEY       ts = getStartTsKey(&pSDataBlock->info.window, tsCols);
1,154,311✔
1096
  STimeWindow nextWin = {0};
1,154,306✔
1097
  if (IS_FINAL_INTERVAL_OP(pOperator)) {
1,154,306✔
1098
    nextWin = getFinalTimeWindow(ts, &pInfo->interval);
2,643✔
1099
  } else {
1100
    nextWin = getActiveTimeWindow(pInfo->aggSup.pResultBuf, pResultRowInfo, ts, &pInfo->interval, TSDB_ORDER_ASC);
1,151,663✔
1101
  }
1102
  while (1) {
9,222,384✔
1103
    bool isClosed = isCloseWindow(&nextWin, &pInfo->twAggSup);
10,376,679✔
1104
    if (hasSrcPrimaryKeyCol(&pInfo->basic) && !IS_FINAL_INTERVAL_OP(pOperator) && pInfo->ignoreExpiredData &&
10,376,664!
UNCOV
1105
        pSDataBlock->info.type != STREAM_PULL_DATA) {
×
UNCOV
1106
      pPkVal = colDataGetData(pPkColDataInfo, startPos);
×
UNCOV
1107
      pkLen = colDataGetRowLength(pPkColDataInfo, startPos);
×
1108
    }
1109

1110
    if ((!IS_FINAL_INTERVAL_OP(pOperator) && pInfo->ignoreExpiredData && pSDataBlock->info.type != STREAM_PULL_DATA &&
10,377,835!
1111
         checkExpiredData(&pInfo->stateStore, pInfo->pUpdateInfo, &pInfo->twAggSup, pSDataBlock->info.id.uid,
1,185✔
1112
                          nextWin.ekey, pPkVal, pkLen)) ||
10,376,354✔
1113
        !inSlidingWindow(&pInfo->interval, &nextWin, &pSDataBlock->info)) {
10,376,627✔
1114
      startPos = getNexWindowPos(&pInfo->interval, &pSDataBlock->info, tsCols, startPos, nextWin.ekey, &nextWin);
32✔
1115
      if (startPos < 0) {
42✔
1116
        break;
1,154,317✔
1117
      }
1118
      qDebug("===stream===ignore expired data, window end ts:%" PRId64 ", maxts - wartermak:%" PRId64, nextWin.ekey,
19!
1119
             pInfo->twAggSup.maxTs - pInfo->twAggSup.waterMark);
1120
      continue;
57✔
1121
    }
1122

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

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

1158
      if (ignore) {
245,276✔
1159
        startPos = getNextQualifiedFinalWindow(&pInfo->interval, &nextWin, &pSDataBlock->info, tsCols, startPos);
130✔
1160
        if (startPos < 0) {
130✔
1161
          break;
92✔
1162
        }
1163
        continue;
38✔
1164
      }
1165
    }
1166

1167
    int32_t winCode = TSDB_CODE_SUCCESS;
10,376,215✔
1168
    code = setIntervalOutputBuf(pInfo->pState, &nextWin, &pResPos, groupId, pSup->pCtx, numOfOutput,
10,376,215✔
1169
                                pSup->rowEntryInfoOffset, &pInfo->aggSup, &pInfo->stateStore, &winCode);
1170
    QUERY_CHECK_CODE(code, lino, _end);
10,376,137!
1171

1172
    if (winCode != TSDB_CODE_SUCCESS && IS_NORMAL_INTERVAL_OP(pOperator) &&
10,376,137✔
1173
        BIT_FLAG_TEST_MASK(pTaskInfo->streamInfo.eventTypes, SNOTIFY_EVENT_WINDOW_OPEN)) {
9,449,297!
UNCOV
1174
      SSessionKey key = {.win = nextWin, .groupId = groupId};
×
UNCOV
1175
      code = addIntervalAggNotifyEvent(SNOTIFY_EVENT_WINDOW_OPEN, &key, &pInfo->basic.notifyEventSup,
×
1176
                                       pTaskInfo->streamInfo.pNotifyEventStat);
UNCOV
1177
      QUERY_CHECK_CODE(code, lino, _end);
×
1178
    }
1179

1180
    pResult = (SResultRow*)pResPos->pRowBuff;
10,376,137✔
1181

1182
    if (IS_FINAL_INTERVAL_OP(pOperator)) {
10,376,137✔
1183
      forwardRows = 1;
245,146✔
1184
    } else {
1185
      forwardRows = getNumOfRowsInTimeWindow(&pSDataBlock->info, tsCols, startPos, nextWin.ekey, binarySearchForKey,
10,130,991✔
1186
                                             NULL, TSDB_ORDER_ASC);
1187
    }
1188

1189
    SWinKey key = {
10,377,830✔
1190
        .ts = pResult->win.skey,
10,377,830✔
1191
        .groupId = groupId,
1192
    };
1193

1194
    if (pInfo->destHasPrimaryKey && winCode == TSDB_CODE_SUCCESS && IS_NORMAL_INTERVAL_OP(pOperator)) {
10,377,830!
1195
      code = tSimpleHashPut(pDeletedMap, &key, sizeof(SWinKey), NULL, 0);
6✔
1196
      QUERY_CHECK_CODE(code, lino, _end);
6!
1197
    }
1198

1199
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_AT_ONCE && pUpdatedMap) {
10,377,830!
1200
      code = saveWinResult(&key, pResPos, pUpdatedMap);
10,368,063✔
1201
      QUERY_CHECK_CODE(code, lino, _end);
10,369,082!
1202
    }
1203

1204
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_WINDOW_CLOSE) {
10,378,849✔
1205
      pResPos->beUpdated = true;
8,441✔
1206
      code = tSimpleHashPut(pInfo->aggSup.pResultRowHashTable, &key, sizeof(SWinKey), &pResPos, POINTER_BYTES);
8,441✔
1207
      QUERY_CHECK_CODE(code, lino, _end);
8,444!
1208
    }
1209

1210
    updateTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &nextWin, 1);
10,378,852✔
1211
    code = applyAggFunctionOnPartialTuples(pTaskInfo, pSup->pCtx, &pInfo->twAggSup.timeWindowData, startPos,
10,377,474✔
1212
                                           forwardRows, pSDataBlock->info.rows, numOfOutput);
10,377,474✔
1213
    QUERY_CHECK_CODE(code, lino, _end);
10,377,818!
1214
    key.ts = nextWin.skey;
10,377,818✔
1215

1216
    if (pInfo->delKey.ts > key.ts) {
10,377,818✔
1217
      pInfo->delKey = key;
2,078✔
1218
    }
1219
    int32_t prevEndPos = (forwardRows - 1) * step + startPos;
10,377,818✔
1220
    if (IS_FINAL_INTERVAL_OP(pOperator)) {
10,377,818✔
1221
      startPos = getNextQualifiedFinalWindow(&pInfo->interval, &nextWin, &pSDataBlock->info, tsCols, prevEndPos);
245,146✔
1222
    } else {
1223
      startPos =
1224
          getNextQualifiedWindow(&pInfo->interval, &nextWin, &pSDataBlock->info, tsCols, prevEndPos, TSDB_ORDER_ASC);
10,132,672✔
1225
    }
1226
    if (startPos < 0) {
10,376,529✔
1227
      break;
1,154,202✔
1228
    }
1229
  }
1230
_end:
1,154,317✔
1231
  if (code != TSDB_CODE_SUCCESS) {
1,154,317!
UNCOV
1232
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
1233
  }
1234
  return code;
1,154,305✔
1235
}
1236

1237
int winPosCmprImpl(const void* pKey1, const void* pKey2) {
141,151,504✔
1238
  SRowBuffPos* pos1 = *(SRowBuffPos**)pKey1;
141,151,504✔
1239
  SRowBuffPos* pos2 = *(SRowBuffPos**)pKey2;
141,151,504✔
1240
  SWinKey*     pWin1 = (SWinKey*)pos1->pKey;
141,151,504✔
1241
  SWinKey*     pWin2 = (SWinKey*)pos2->pKey;
141,151,504✔
1242

1243
  if (pWin1->groupId > pWin2->groupId) {
141,151,504✔
1244
    return 1;
26,187,315✔
1245
  } else if (pWin1->groupId < pWin2->groupId) {
114,964,189✔
1246
    return -1;
24,696,689✔
1247
  }
1248

1249
  if (pWin1->ts > pWin2->ts) {
90,267,500✔
1250
    return 1;
45,446,570✔
1251
  } else if (pWin1->ts < pWin2->ts) {
44,820,930!
1252
    return -1;
44,822,382✔
1253
  }
1254

UNCOV
1255
  return 0;
×
1256
}
1257

1258
static void resetUnCloseWinInfo(SSHashObj* winMap) {
258✔
1259
  void*   pIte = NULL;
258✔
1260
  int32_t iter = 0;
258✔
1261
  while ((pIte = tSimpleHashIterate(winMap, pIte, &iter)) != NULL) {
575✔
1262
    SRowBuffPos* pPos = *(SRowBuffPos**)pIte;
317✔
1263
    pPos->beUsed = true;
317✔
1264
  }
1265
}
258✔
1266

1267
int32_t encodeSWinKey(void** buf, SWinKey* key) {
34✔
1268
  int32_t tlen = 0;
34✔
1269
  tlen += taosEncodeFixedI64(buf, key->ts);
34✔
1270
  tlen += taosEncodeFixedU64(buf, key->groupId);
34✔
1271
  return tlen;
34✔
1272
}
1273

1274
void* decodeSWinKey(void* buf, SWinKey* key) {
2✔
1275
  buf = taosDecodeFixedI64(buf, &key->ts);
2!
1276
  buf = taosDecodeFixedU64(buf, &key->groupId);
2!
1277
  return buf;
2✔
1278
}
1279

1280
int32_t encodeSTimeWindowAggSupp(void** buf, STimeWindowAggSupp* pTwAggSup) {
211✔
1281
  int32_t tlen = 0;
211✔
1282
  tlen += taosEncodeFixedI64(buf, pTwAggSup->minTs);
211✔
1283
  tlen += taosEncodeFixedI64(buf, pTwAggSup->maxTs);
211✔
1284
  return tlen;
211✔
1285
}
1286

1287
void* decodeSTimeWindowAggSupp(void* buf, STimeWindowAggSupp* pTwAggSup) {
68✔
1288
  buf = taosDecodeFixedI64(buf, &pTwAggSup->minTs);
68!
1289
  buf = taosDecodeFixedI64(buf, &pTwAggSup->maxTs);
68!
1290
  return buf;
68✔
1291
}
1292

1293
int32_t encodeSTimeWindow(void** buf, STimeWindow* pWin) {
8✔
1294
  int32_t tlen = 0;
8✔
1295
  tlen += taosEncodeFixedI64(buf, pWin->skey);
8✔
1296
  tlen += taosEncodeFixedI64(buf, pWin->ekey);
8✔
1297
  return tlen;
8✔
1298
}
1299

1300
void* decodeSTimeWindow(void* buf, STimeWindow* pWin) {
2✔
1301
  buf = taosDecodeFixedI64(buf, &pWin->skey);
2!
1302
  buf = taosDecodeFixedI64(buf, &pWin->ekey);
2!
1303
  return buf;
2✔
1304
}
1305

UNCOV
1306
int32_t encodeSPullWindowInfo(void** buf, SPullWindowInfo* pPullInfo) {
×
UNCOV
1307
  int32_t tlen = 0;
×
UNCOV
1308
  tlen += encodeSTimeWindow(buf, &pPullInfo->calWin);
×
UNCOV
1309
  tlen += taosEncodeFixedU64(buf, pPullInfo->groupId);
×
UNCOV
1310
  tlen += encodeSTimeWindow(buf, &pPullInfo->window);
×
UNCOV
1311
  return tlen;
×
1312
}
1313

UNCOV
1314
void* decodeSPullWindowInfo(void* buf, SPullWindowInfo* pPullInfo) {
×
UNCOV
1315
  buf = decodeSTimeWindow(buf, &pPullInfo->calWin);
×
UNCOV
1316
  buf = taosDecodeFixedU64(buf, &pPullInfo->groupId);
×
1317
  buf = decodeSTimeWindow(buf, &pPullInfo->window);
×
1318
  return buf;
×
1319
}
1320

1321
int32_t encodeSPullWindowInfoArray(void** buf, SArray* pPullInfos) {
78✔
1322
  int32_t tlen = 0;
78✔
1323
  int32_t size = taosArrayGetSize(pPullInfos);
78✔
1324
  tlen += taosEncodeFixedI32(buf, size);
78✔
1325
  for (int32_t i = 0; i < size; i++) {
78!
1326
    void* pItem = taosArrayGet(pPullInfos, i);
×
1327
    tlen += encodeSPullWindowInfo(buf, pItem);
×
1328
  }
1329
  return tlen;
78✔
1330
}
1331

1332
int32_t decodeSPullWindowInfoArray(void* buf, SArray* pPullInfos, void** ppBuf) {
31✔
1333
  int32_t code = TSDB_CODE_SUCCESS;
31✔
1334
  int32_t lino = 0;
31✔
1335
  int32_t size = 0;
31!
1336
  buf = taosDecodeFixedI32(buf, &size);
31✔
1337
  for (int32_t i = 0; i < size; i++) {
31!
1338
    SPullWindowInfo item = {0};
×
UNCOV
1339
    buf = decodeSPullWindowInfo(buf, &item);
×
UNCOV
1340
    void* tmp = taosArrayPush(pPullInfos, &item);
×
UNCOV
1341
    if (!tmp) {
×
UNCOV
1342
      code = terrno;
×
UNCOV
1343
      QUERY_CHECK_CODE(code, lino, _end);
×
1344
    }
1345
  }
1346
  (*ppBuf) = buf;
31✔
1347

1348
_end:
31✔
1349
  if (code != TSDB_CODE_SUCCESS) {
31!
1350
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
1351
  }
1352
  return code;
31✔
1353
}
1354

1355
int32_t doStreamIntervalEncodeOpState(void** buf, int32_t len, SOperatorInfo* pOperator) {
78✔
1356
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
78✔
1357
  if (!pInfo) {
78!
UNCOV
1358
    return 0;
×
1359
  }
1360

1361
  void* pData = (buf == NULL) ? NULL : *buf;
78✔
1362

1363
  // 1.pResultRowHashTable
1364
  int32_t tlen = 0;
78✔
1365
  int32_t mapSize = tSimpleHashGetSize(pInfo->aggSup.pResultRowHashTable);
78✔
1366
  tlen += taosEncodeFixedI32(buf, mapSize);
78✔
1367
  void*   pIte = NULL;
78✔
1368
  size_t  keyLen = 0;
78✔
1369
  int32_t iter = 0;
78✔
1370
  while ((pIte = tSimpleHashIterate(pInfo->aggSup.pResultRowHashTable, pIte, &iter)) != NULL) {
112✔
1371
    void* key = tSimpleHashGetKey(pIte, &keyLen);
34✔
1372
    tlen += encodeSWinKey(buf, key);
34✔
1373
  }
1374

1375
  // 2.twAggSup
1376
  tlen += encodeSTimeWindowAggSupp(buf, &pInfo->twAggSup);
78✔
1377

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

1395
  // 4.pPullWins
1396
  tlen += encodeSPullWindowInfoArray(buf, pInfo->pPullWins);
78✔
1397

1398
  // 5.dataVersion
1399
  tlen += taosEncodeFixedI64(buf, pInfo->dataVersion);
78✔
1400

1401
  // 6.basicInfo
1402
  tlen += encodeStreamBasicInfo(buf, &pInfo->basic);
78✔
1403

1404
  // 7.checksum
1405
  if (buf) {
78✔
1406
    uint32_t cksum = taosCalcChecksum(0, pData, len - sizeof(uint32_t));
78!
1407
    tlen += taosEncodeFixedU32(buf, cksum);
39✔
1408
  } else {
1409
    tlen += sizeof(uint32_t);
39✔
1410
  }
1411

1412
  return tlen;
78✔
1413
}
1414

1415
void doStreamIntervalDecodeOpState(void* buf, int32_t len, SOperatorInfo* pOperator) {
31✔
1416
  int32_t                      code = TSDB_CODE_SUCCESS;
31✔
1417
  int32_t                      lino = 0;
31✔
1418
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
31✔
1419
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
31✔
1420
  void*                        pDataEnd = POINTER_SHIFT(buf, len);
31✔
1421
  if (!pInfo) {
31!
UNCOV
1422
    code = TSDB_CODE_FAILED;
×
UNCOV
1423
    QUERY_CHECK_CODE(code, lino, _end);
×
1424
  }
1425

1426
  // 7.checksum
1427
  int32_t dataLen = len - sizeof(uint32_t);
31✔
1428
  void*   pCksum = POINTER_SHIFT(buf, dataLen);
31✔
1429
  if (taosCheckChecksum(buf, dataLen, *(uint32_t*)pCksum) != TSDB_CODE_SUCCESS) {
62!
UNCOV
1430
    code = TSDB_CODE_FAILED;
×
UNCOV
1431
    QUERY_CHECK_CODE(code, lino, _end);
×
1432
  }
1433
  pDataEnd = pCksum;
31✔
1434

1435
  // 1.pResultRowHashTable
1436
  int32_t mapSize = 0;
31✔
1437
  buf = taosDecodeFixedI32(buf, &mapSize);
31!
1438
  for (int32_t i = 0; i < mapSize; i++) {
33✔
1439
    SWinKey key = {0};
2✔
1440
    buf = decodeSWinKey(buf, &key);
2✔
1441
    SRowBuffPos* pPos = NULL;
2✔
1442
    int32_t      resSize = pInfo->aggSup.resultRowSize;
2✔
1443
    int32_t      winCode = TSDB_CODE_SUCCESS;
2✔
1444
    code = pInfo->stateStore.streamStateAddIfNotExist(pInfo->pState, &key, (void**)&pPos, &resSize, &winCode);
2✔
1445
    QUERY_CHECK_CODE(code, lino, _end);
2!
1446
    QUERY_CHECK_CONDITION((winCode == TSDB_CODE_SUCCESS), code, lino, _end, TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR);
2!
1447

1448
    code = tSimpleHashPut(pInfo->aggSup.pResultRowHashTable, &key, sizeof(SWinKey), &pPos, POINTER_BYTES);
2✔
1449
    QUERY_CHECK_CODE(code, lino, _end);
2!
1450
  }
1451

1452
  // 2.twAggSup
1453
  buf = decodeSTimeWindowAggSupp(buf, &pInfo->twAggSup);
31✔
1454

1455
  // 3.pPullDataMap
1456
  int32_t size = 0;
31✔
1457
  buf = taosDecodeFixedI32(buf, &size);
31!
1458
  for (int32_t i = 0; i < size; i++) {
31!
UNCOV
1459
    SWinKey key = {0};
×
UNCOV
1460
    SArray* pArray = taosArrayInit(0, sizeof(int32_t));
×
UNCOV
1461
    if (!pArray) {
×
UNCOV
1462
      code = terrno;
×
UNCOV
1463
      QUERY_CHECK_CODE(code, lino, _end);
×
1464
    }
1465

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

1482
  // 4.pPullWins
1483
  code = decodeSPullWindowInfoArray(buf, pInfo->pPullWins, &buf);
31✔
1484
  QUERY_CHECK_CODE(code, lino, _end);
31!
1485

1486
  // 5.dataVersion
1487
  buf = taosDecodeFixedI64(buf, &pInfo->dataVersion);
31!
1488

1489
  // 6.basicInfo
1490
  if (buf < pDataEnd) {
31!
1491
    code = decodeStreamBasicInfo(&buf, &pInfo->basic);
31✔
1492
    QUERY_CHECK_CODE(code, lino, _end);
31!
1493
  }
1494

1495
_end:
31✔
1496
  if (code != TSDB_CODE_SUCCESS) {
31!
UNCOV
1497
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
1498
  }
1499
}
31✔
1500

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

1519
int32_t copyIntervalDeleteKey(SSHashObj* pMap, SArray* pWins) {
61✔
1520
  int32_t code = TSDB_CODE_SUCCESS;
61✔
1521
  int32_t lino = 0;
61✔
1522
  void*   pIte = NULL;
61✔
1523
  int32_t iter = 0;
61✔
1524
  while ((pIte = tSimpleHashIterate(pMap, pIte, &iter)) != NULL) {
82✔
1525
    void* pKey = tSimpleHashGetKey(pIte, NULL);
21✔
1526
    void* tmp = taosArrayPush(pWins, pKey);
21✔
1527
    if (!tmp) {
21!
UNCOV
1528
      code = terrno;
×
UNCOV
1529
      QUERY_CHECK_CODE(code, lino, _end);
×
1530
    }
1531
  }
1532
  tSimpleHashClear(pMap);
61✔
1533

1534
_end:
61✔
1535
  if (code != TSDB_CODE_SUCCESS) {
61!
UNCOV
1536
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
1537
  }
1538
  return code;
61✔
1539
}
1540

1541
static int32_t buildIntervalResult(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
154,000✔
1542
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
154,000✔
1543
  int32_t                      code = TSDB_CODE_SUCCESS;
154,000✔
1544
  int32_t                      lino = 0;
154,000✔
1545
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
154,000✔
1546
  uint16_t                     opType = pOperator->operatorType;
154,000✔
1547
  SStreamNotifyEventSupp*      pNotifySup = &pInfo->basic.notifyEventSup;
154,000✔
1548
  STaskNotifyEventStat*        pNotifyEventStat = pTaskInfo->streamInfo.pNotifyEventStat;
154,000✔
1549
  bool                         addNotifyEvent = false;
154,000✔
1550

1551
  // check if query task is closed or not
1552
  if (isTaskKilled(pTaskInfo)) {
154,000✔
1553
    (*ppRes) = NULL;
2✔
1554
    return code;
2✔
1555
  }
1556

1557
  addNotifyEvent = IS_NORMAL_INTERVAL_OP(pOperator) &&
294,071✔
1558
                   BIT_FLAG_TEST_MASK(pTaskInfo->streamInfo.eventTypes, SNOTIFY_EVENT_WINDOW_CLOSE);
140,080!
1559
  if (IS_FINAL_INTERVAL_OP(pOperator)) {
153,991✔
1560
    doBuildPullDataBlock(pInfo->pPullWins, &pInfo->pullIndex, pInfo->pPullDataRes);
4,355✔
1561
    if (pInfo->pPullDataRes->info.rows != 0) {
4,355✔
1562
      // process the rest of the data
1563
      printDataBlock(pInfo->pPullDataRes, getStreamOpName(opType), GET_TASKID(pTaskInfo));
158✔
1564
      (*ppRes) = pInfo->pPullDataRes;
158✔
1565
      return code;
158✔
1566
    }
1567
  }
1568

1569
  doBuildDeleteResult(pTaskInfo, pInfo->pDelWins, &pInfo->delIndex, pInfo->pDelRes);
153,833✔
1570
  if (pInfo->pDelRes->info.rows != 0) {
153,833✔
1571
    // process the rest of the data
1572
    printDataBlock(pInfo->pDelRes, getStreamOpName(opType), GET_TASKID(pTaskInfo));
498✔
1573
    if (addNotifyEvent) {
502!
UNCOV
1574
      code = addAggDeleteNotifyEvent(pInfo->pDelRes, pNotifySup, pNotifyEventStat);
×
UNCOV
1575
      QUERY_CHECK_CODE(code, lino, _end);
×
1576
    }
1577
    (*ppRes) = pInfo->pDelRes;
502✔
1578
    return code;
502✔
1579
  }
1580

1581
  doBuildStreamIntervalResult(pOperator, pInfo->pState, pInfo->binfo.pRes, &pInfo->groupResInfo,
153,335!
1582
                              addNotifyEvent ? pNotifySup->pSessionKeys : NULL);
1583
  if (pInfo->binfo.pRes->info.rows != 0) {
153,338✔
1584
    printDataBlock(pInfo->binfo.pRes, getStreamOpName(opType), GET_TASKID(pTaskInfo));
115,037✔
1585
    if (addNotifyEvent) {
115,036!
1586
      code = addAggResultNotifyEvent(pInfo->binfo.pRes, pNotifySup->pSessionKeys,
×
UNCOV
1587
                                     pTaskInfo->streamInfo.notifyResultSchema, pNotifySup, pNotifyEventStat);
×
UNCOV
1588
      QUERY_CHECK_CODE(code, lino, _end);
×
1589
    }
1590
    (*ppRes) = pInfo->binfo.pRes;
115,036✔
1591
    return code;
115,036✔
1592
  }
1593

1594
  code = buildNotifyEventBlock(pTaskInfo, pNotifySup, pNotifyEventStat);
38,301✔
1595
  QUERY_CHECK_CODE(code, lino, _end);
38,304!
1596
  if (pNotifySup->pEventBlock && pNotifySup->pEventBlock->info.rows > 0) {
38,304!
1597
    printDataBlock(pNotifySup->pEventBlock, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
1598
    (*ppRes) = pNotifySup->pEventBlock;
×
1599
    return code;
×
1600
  }
1601

1602
  code = removeOutdatedNotifyEvents(&pInfo->twAggSup, pNotifySup, pNotifyEventStat);
38,304✔
1603
  QUERY_CHECK_CODE(code, lino, _end);
38,306!
1604

1605
_end:
38,306✔
1606
  if (code != TSDB_CODE_SUCCESS) {
38,306!
UNCOV
1607
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
1608
  }
1609
  (*ppRes) = NULL;
38,307✔
1610
  return code;
38,307✔
1611
}
1612

1613
int32_t copyUpdateResult(SSHashObj** ppWinUpdated, SArray* pUpdated, __compar_fn_t compar) {
19,215✔
1614
  int32_t code = TSDB_CODE_SUCCESS;
19,215✔
1615
  int32_t lino = 0;
19,215✔
1616
  void*   pIte = NULL;
19,215✔
1617
  int32_t iter = 0;
19,215✔
1618
  while ((pIte = tSimpleHashIterate(*ppWinUpdated, pIte, &iter)) != NULL) {
516,197✔
1619
    void* tmp = taosArrayPush(pUpdated, pIte);
496,982✔
1620
    if (!tmp) {
496,982!
UNCOV
1621
      code = terrno;
×
UNCOV
1622
      QUERY_CHECK_CODE(code, lino, _end);
×
1623
    }
1624
  }
1625
  taosArraySort(pUpdated, compar);
19,218✔
1626
  tSimpleHashCleanup(*ppWinUpdated);
19,195✔
1627
  *ppWinUpdated = NULL;
19,212✔
1628

1629
_end:
19,212✔
1630
  if (code != TSDB_CODE_SUCCESS) {
19,212!
UNCOV
1631
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
1632
  }
1633
  return code;
19,210✔
1634
}
1635

1636
static int32_t doStreamFinalIntervalAggNext(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
14,803✔
1637
  int32_t                      code = TSDB_CODE_SUCCESS;
14,803✔
1638
  int32_t                      lino = 0;
14,803✔
1639
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
14,803✔
1640
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
14,803✔
1641
  SStorageAPI*                 pAPI = &pOperator->pTaskInfo->storageAPI;
14,803✔
1642

1643
  SOperatorInfo* downstream = pOperator->pDownstream[0];
14,803✔
1644
  SExprSupp*     pSup = &pOperator->exprSupp;
14,803✔
1645

1646
  qDebug("stask:%s  %s status: %d", GET_TASKID(pTaskInfo), getStreamOpName(pOperator->operatorType), pOperator->status);
14,803✔
1647

1648
  if (pOperator->status == OP_EXEC_DONE) {
14,803!
UNCOV
1649
    (*ppRes) = NULL;
×
UNCOV
1650
    return code;
×
1651
  } else if (pOperator->status == OP_RES_TO_RETURN) {
14,803✔
1652
    SSDataBlock* resBlock = NULL;
5,140✔
1653
    code = buildIntervalResult(pOperator, &resBlock);
5,140✔
1654
    QUERY_CHECK_CODE(code, lino, _end);
5,137!
1655
    if (resBlock != NULL) {
5,137✔
1656
      (*ppRes) = resBlock;
1,784✔
1657
      return code;
5,137✔
1658
    }
1659

1660
    if (pInfo->recvGetAll) {
3,353✔
1661
      pInfo->recvGetAll = false;
81✔
1662
      resetUnCloseWinInfo(pInfo->aggSup.pResultRowHashTable);
81✔
1663
    }
1664

1665
    if (pInfo->reCkBlock) {
3,353!
UNCOV
1666
      pInfo->reCkBlock = false;
×
UNCOV
1667
      printDataBlock(pInfo->pCheckpointRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
UNCOV
1668
      (*ppRes) = pInfo->pCheckpointRes;
×
UNCOV
1669
      return code;
×
1670
    }
1671

1672
    setStreamOperatorCompleted(pOperator);
3,353✔
1673
    if (!IS_FINAL_INTERVAL_OP(pOperator)) {
3,353✔
1674
      clearFunctionContext(&pOperator->exprSupp);
1,850✔
1675
      // semi interval operator clear disk buffer
1676
      clearStreamIntervalOperator(pInfo);
1,850✔
1677
      qDebug("===stream===clear semi operator");
1,850✔
1678
    }
1679
    (*ppRes) = NULL;
3,353✔
1680
    return code;
3,353✔
1681
  } else {
1682
    if (!IS_FINAL_INTERVAL_OP(pOperator)) {
9,663✔
1683
      SSDataBlock* resBlock = NULL;
6,331✔
1684
      code = buildIntervalResult(pOperator, &resBlock);
6,331✔
1685
      QUERY_CHECK_CODE(code, lino, _end);
6,332!
1686
      if (resBlock != NULL) {
6,332!
UNCOV
1687
        (*ppRes) = resBlock;
×
UNCOV
1688
        return code;
×
1689
      }
1690

1691
      if (pInfo->recvRetrive) {
6,332!
UNCOV
1692
        pInfo->recvRetrive = false;
×
UNCOV
1693
        printDataBlock(pInfo->pMidRetriveRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
UNCOV
1694
        (*ppRes) = pInfo->pMidRetriveRes;
×
UNCOV
1695
        return code;
×
1696
      }
1697
    }
1698
  }
1699

1700
  if (!pInfo->pUpdated) {
9,664✔
1701
    pInfo->pUpdated = taosArrayInit(4096, POINTER_BYTES);
6,633✔
1702
    QUERY_CHECK_NULL(pInfo->pUpdated, code, lino, _end, terrno);
6,632!
1703
  }
1704
  if (!pInfo->pUpdatedMap) {
9,663✔
1705
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
6,632✔
1706
    pInfo->pUpdatedMap = tSimpleHashInit(4096, hashFn);
6,632✔
1707
    QUERY_CHECK_NULL(pInfo->pUpdatedMap, code, lino, _end, terrno);
6,635!
1708
  }
1709

1710
  while (1) {
24,718✔
1711
    if (isTaskKilled(pTaskInfo)) {
34,384✔
1712
      qInfo("===stream=== %s task is killed, code %s", GET_TASKID(pTaskInfo), tstrerror(pTaskInfo->code));
3!
1713
      (*ppRes) = NULL;
3✔
1714
      return code;
3,037✔
1715
    }
1716

1717
    SSDataBlock* pBlock = NULL;
34,381✔
1718
    code = downstream->fpSet.getNextFn(downstream, &pBlock);
34,381✔
1719
    QUERY_CHECK_CODE(code, lino, _end);
34,379!
1720

1721
    if (pBlock == NULL) {
34,379✔
1722
      pOperator->status = OP_RES_TO_RETURN;
6,102✔
1723
      qDebug("===stream===return data:%s. recv datablock num:%" PRIu64, getStreamOpName(pOperator->operatorType),
6,102✔
1724
             pInfo->numOfDatapack);
1725
      pInfo->numOfDatapack = 0;
6,102✔
1726
      break;
6,102✔
1727
    }
1728

1729
    pInfo->numOfDatapack++;
28,277✔
1730
    printSpecDataBlock(pBlock, getStreamOpName(pOperator->operatorType), "recv", GET_TASKID(pTaskInfo));
28,277✔
1731
    setStreamOperatorState(&pInfo->basic, pBlock->info.type);
28,278✔
1732

1733
    if (pBlock->info.type == STREAM_NORMAL || pBlock->info.type == STREAM_PULL_DATA) {
28,280✔
1734
      pInfo->binfo.pRes->info.type = pBlock->info.type;
21,798✔
1735
    } else if (pBlock->info.type == STREAM_DELETE_DATA || pBlock->info.type == STREAM_DELETE_RESULT ||
6,482✔
1736
               pBlock->info.type == STREAM_CLEAR) {
6,250✔
1737
      SArray* delWins = taosArrayInit(8, sizeof(SWinKey));
409✔
1738
      QUERY_CHECK_NULL(delWins, code, lino, _end, terrno);
408!
1739
      SHashObj* finalMap = IS_FINAL_INTERVAL_OP(pOperator) ? pInfo->pFinalPullDataMap : NULL;
408✔
1740
      code = doDeleteWindows(pOperator, &pInfo->interval, pBlock, delWins, pInfo->pUpdatedMap, finalMap);
408✔
1741
      QUERY_CHECK_CODE(code, lino, _end);
408!
1742

1743
      if (IS_FINAL_INTERVAL_OP(pOperator)) {
408✔
1744
        int32_t chId = getChildIndex(pBlock);
204✔
1745
        code = addRetriveWindow(delWins, pInfo, chId);
204✔
1746
        QUERY_CHECK_CODE(code, lino, _end);
204!
1747

1748
        if (pBlock->info.type != STREAM_CLEAR) {
204✔
1749
          void* tmp = taosArrayAddAll(pInfo->pDelWins, delWins);
116✔
1750
          if (!tmp && taosArrayGetSize(delWins) > 0) {
116!
UNCOV
1751
            code = TSDB_CODE_OUT_OF_MEMORY;
×
UNCOV
1752
            QUERY_CHECK_CODE(code, lino, _end);
×
1753
          }
1754
        }
1755
        taosArrayDestroy(delWins);
204✔
1756
        continue;
2,166✔
1757
      }
1758
      removeResults(delWins, pInfo->pUpdatedMap);
204✔
1759
      void* tmp = taosArrayAddAll(pInfo->pDelWins, delWins);
204✔
1760
      if (!tmp && taosArrayGetSize(delWins) > 0) {
204!
UNCOV
1761
        code = TSDB_CODE_OUT_OF_MEMORY;
×
1762
        QUERY_CHECK_CODE(code, lino, _end);
×
1763
      }
1764
      taosArrayDestroy(delWins);
204✔
1765

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

UNCOV
1779
      break;
×
1780
    } else if (pBlock->info.type == STREAM_GET_ALL && IS_FINAL_INTERVAL_OP(pOperator)) {
6,073!
1781
      pInfo->recvGetAll = true;
81✔
1782
      code = getAllIntervalWindow(pInfo->aggSup.pResultRowHashTable, pInfo->pUpdatedMap);
81✔
1783
      QUERY_CHECK_CODE(code, lino, _end);
81!
1784
      continue;
81✔
1785
    } else if (pBlock->info.type == STREAM_RETRIEVE) {
5,992✔
1786
      if (!IS_FINAL_INTERVAL_OP(pOperator)) {
528!
1787
        pInfo->recvRetrive = true;
528✔
1788
        code = copyDataBlock(pInfo->pMidRetriveRes, pBlock);
528✔
1789
        QUERY_CHECK_CODE(code, lino, _end);
528!
1790

1791
        pInfo->pMidRetriveRes->info.type = STREAM_MID_RETRIEVE;
528✔
1792
        code = doDeleteWindows(pOperator, &pInfo->interval, pBlock, NULL, pInfo->pUpdatedMap, NULL);
528✔
1793
        QUERY_CHECK_CODE(code, lino, _end);
528!
1794
        break;
528✔
1795
      }
UNCOV
1796
      continue;
×
1797
    } else if (pBlock->info.type == STREAM_PULL_OVER && IS_FINAL_INTERVAL_OP(pOperator)) {
5,464!
1798
      code = processPullOver(pBlock, pInfo->pPullDataMap, pInfo->pFinalPullDataMap, &pInfo->interval, pInfo->pPullWins,
522✔
1799
                             pInfo->numOfChild, pOperator, NULL);
1800
      QUERY_CHECK_CODE(code, lino, _end);
522!
1801
      continue;
522✔
1802
    } else if (pBlock->info.type == STREAM_CREATE_CHILD_TABLE) {
4,942✔
1803
      (*ppRes) = pBlock;
2,830✔
1804
      return code;
2,830✔
1805
    } else if (pBlock->info.type == STREAM_CHECKPOINT) {
2,112✔
1806
      pAPI->stateStore.streamStateCommit(pInfo->pState);
831✔
1807
      doStreamIntervalSaveCheckpoint(pOperator);
831✔
1808
      code = copyDataBlock(pInfo->pCheckpointRes, pBlock);
831✔
1809
      QUERY_CHECK_CODE(code, lino, _end);
831!
1810

1811
      continue;
831✔
1812
    } else if (IS_FINAL_INTERVAL_OP(pOperator) && pBlock->info.type == STREAM_MID_RETRIEVE) {
1,281✔
1813
      continue;
528✔
1814
    } else {
1815
      if (pBlock->info.type != STREAM_INVALID) {
753!
UNCOV
1816
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
UNCOV
1817
        QUERY_CHECK_CODE(code, lino, _end);
×
1818
      }
1819
    }
1820

1821
    if (pInfo->scalarSupp.pExprInfo != NULL) {
22,551!
UNCOV
1822
      SExprSupp* pExprSup = &pInfo->scalarSupp;
×
UNCOV
1823
      code = projectApplyFunctions(pExprSup->pExprInfo, pBlock, pBlock, pExprSup->pCtx, pExprSup->numOfExprs, NULL);
×
UNCOV
1824
      QUERY_CHECK_CODE(code, lino, _end);
×
1825
    }
1826
    code = setInputDataBlock(pSup, pBlock, TSDB_ORDER_ASC, MAIN_SCAN, true);
22,551✔
1827
    QUERY_CHECK_CODE(code, lino, _end);
22,553!
1828

1829
    code = doStreamIntervalAggImpl(pOperator, pBlock, pBlock->info.id.groupId, pInfo->pUpdatedMap, pInfo->pDeletedMap);
22,553✔
1830
    if (code == TSDB_CODE_STREAM_INTERNAL_ERROR) {
22,552!
UNCOV
1831
      code = TSDB_CODE_SUCCESS;
×
UNCOV
1832
      pOperator->status = OP_RES_TO_RETURN;
×
1833
      break;
×
1834
    }
1835
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.window.ekey);
22,552✔
1836
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.watermark);
22,552✔
1837
    pInfo->twAggSup.minTs = TMIN(pInfo->twAggSup.minTs, pBlock->info.window.skey);
22,552✔
1838
  }
1839

1840
  if (IS_FINAL_INTERVAL_OP(pOperator) && !pInfo->destHasPrimaryKey) {
6,630✔
1841
    removeDeleteResults(pInfo->pUpdatedMap, pInfo->pDelWins);
1,917✔
1842
  }
1843
  if (IS_FINAL_INTERVAL_OP(pOperator)) {
6,630✔
1844
    code = closeStreamIntervalWindow(pInfo->aggSup.pResultRowHashTable, &pInfo->twAggSup, &pInfo->interval,
1,919✔
1845
                                     pInfo->pPullDataMap, pInfo->pUpdatedMap, pInfo->pDelWins, pOperator);
1846
    QUERY_CHECK_CODE(code, lino, _end);
1,919!
1847

1848
    if (pInfo->destHasPrimaryKey) {
1,919✔
1849
      code = copyIntervalDeleteKey(pInfo->pDeletedMap, pInfo->pDelWins);
2✔
1850
      QUERY_CHECK_CODE(code, lino, _end);
2!
1851
    }
1852
  }
1853
  pInfo->binfo.pRes->info.watermark = pInfo->twAggSup.maxTs;
6,630✔
1854

1855
  code = copyUpdateResult(&pInfo->pUpdatedMap, pInfo->pUpdated, winPosCmprImpl);
6,630✔
1856
  QUERY_CHECK_CODE(code, lino, _end);
6,630!
1857

1858
  initMultiResInfoFromArrayList(&pInfo->groupResInfo, pInfo->pUpdated);
6,630✔
1859
  pInfo->pUpdated = NULL;
6,630✔
1860
  code = blockDataEnsureCapacity(pInfo->binfo.pRes, pOperator->resultInfo.capacity);
6,630✔
1861
  QUERY_CHECK_CODE(code, lino, _end);
6,630!
1862

1863
  SSDataBlock* resBlock = NULL;
6,630✔
1864
  code = buildIntervalResult(pOperator, &resBlock);
6,630✔
1865
  QUERY_CHECK_CODE(code, lino, _end);
6,630!
1866
  if (resBlock != NULL) {
6,630✔
1867
    (*ppRes) = resBlock;
3,353✔
1868
    return code;
3,353✔
1869
  }
1870

1871
  if (pInfo->recvRetrive) {
3,277✔
1872
    pInfo->recvRetrive = false;
528✔
1873
    printDataBlock(pInfo->pMidRetriveRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
528✔
1874
    (*ppRes) = pInfo->pMidRetriveRes;
527✔
1875
    return code;
527✔
1876
  }
1877

1878
_end:
2,749✔
1879
  if (code != TSDB_CODE_SUCCESS) {
2,749!
UNCOV
1880
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
UNCOV
1881
    pTaskInfo->code = code;
×
UNCOV
1882
    T_LONG_JMP(pTaskInfo->env, code);
×
1883
  }
1884
  setStreamOperatorCompleted(pOperator);
2,749✔
1885
  (*ppRes) = NULL;
2,749✔
1886
  return code;
2,749✔
1887
}
1888

1889
int64_t getDeleteMark(SWindowPhysiNode* pWinPhyNode, int64_t interval) {
5,917✔
1890
  if (pWinPhyNode->deleteMark <= 0) {
5,917✔
1891
    return DEAULT_DELETE_MARK;
3,981✔
1892
  }
1893
  int64_t deleteMark = TMAX(pWinPhyNode->deleteMark, pWinPhyNode->watermark);
1,936✔
1894
  deleteMark = TMAX(deleteMark, interval);
1,936✔
1895
  return deleteMark;
1,936✔
1896
}
1897

1898
int64_t getDeleteMarkFromOption(SStreamNodeOption* pOption) {
221✔
1899
  if (pOption->deleteMark <= 0) {
221!
1900
    return DEAULT_DELETE_MARK;
221✔
1901
  }
UNCOV
1902
  int64_t deleteMark = TMAX(pOption->deleteMark, pOption->watermark);
×
UNCOV
1903
  return deleteMark;
×
1904
}
1905

1906
TSKEY compareTs(void* pKey) {
33,226,227✔
1907
  SWinKey* pWinKey = (SWinKey*)pKey;
33,226,227✔
1908
  return pWinKey->ts;
33,226,227✔
1909
}
1910

1911
static int32_t getSelectivityBufSize(SqlFunctionCtx* pCtx) {
227,072✔
1912
  if (pCtx->subsidiaries.rowLen == 0) {
227,072!
1913
    int32_t rowLen = 0;
227,078✔
1914
    for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
227,481✔
1915
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
403✔
1916
      rowLen += pc->pExpr->base.resSchema.bytes;
403✔
1917
    }
1918

1919
    return rowLen + pCtx->subsidiaries.num * sizeof(bool);
227,078✔
1920
  } else {
UNCOV
1921
    return pCtx->subsidiaries.rowLen;
×
1922
  }
1923
}
1924

1925
static int32_t getMaxFunResSize(SExprSupp* pSup, int32_t numOfCols) {
6,142✔
1926
  int32_t size = 0;
6,142✔
1927
  for (int32_t i = 0; i < numOfCols; ++i) {
233,214✔
1928
    int32_t resSize = getSelectivityBufSize(pSup->pCtx + i);
227,065✔
1929
    size = TMAX(size, resSize);
227,072✔
1930
  }
1931
  return size;
6,149✔
1932
}
1933

1934
static void streamIntervalReleaseState(SOperatorInfo* pOperator) {
1,287✔
1935
  if (pOperator->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_SEMI_INTERVAL &&
1,287✔
1936
      pOperator->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_MID_INTERVAL) {
1,153✔
1937
    SStreamIntervalOperatorInfo* pInfo = pOperator->info;
1,143✔
1938
    int32_t                      resSize = sizeof(TSKEY);
1,143✔
1939
    pInfo->stateStore.streamStateSaveInfo(pInfo->pState, STREAM_INTERVAL_OP_STATE_NAME,
1,143✔
1940
                                          strlen(STREAM_INTERVAL_OP_STATE_NAME), &pInfo->twAggSup.maxTs, resSize);
1,143✔
1941
  }
1942
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
1,287✔
1943
  SStorageAPI*                 pAPI = &pOperator->pTaskInfo->storageAPI;
1,287✔
1944
  pAPI->stateStore.streamStateCommit(pInfo->pState);
1,287✔
1945
  SOperatorInfo* downstream = pOperator->pDownstream[0];
1,287✔
1946
  if (downstream->fpSet.releaseStreamStateFn) {
1,287!
1947
    downstream->fpSet.releaseStreamStateFn(downstream);
1,287✔
1948
  }
1949
}
1,287✔
1950

1951
void streamIntervalReloadState(SOperatorInfo* pOperator) {
1,287✔
1952
  int32_t                      code = TSDB_CODE_SUCCESS;
1,287✔
1953
  int32_t                      lino = 0;
1,287✔
1954
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
1,287✔
1955
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
1,287✔
1956
  if (pOperator->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_SEMI_INTERVAL &&
1,287✔
1957
      pOperator->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_MID_INTERVAL) {
1,153✔
1958
    int32_t size = 0;
1,143✔
1959
    void*   pBuf = NULL;
1,143✔
1960
    code = pInfo->stateStore.streamStateGetInfo(pInfo->pState, STREAM_INTERVAL_OP_STATE_NAME,
1,143✔
1961
                                                strlen(STREAM_INTERVAL_OP_STATE_NAME), &pBuf, &size);
1962
    QUERY_CHECK_CODE(code, lino, _end);
1,143!
1963

1964
    TSKEY ts = *(TSKEY*)pBuf;
1,143✔
1965
    taosMemoryFree(pBuf);
1,143!
1966
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, ts);
1,143✔
1967
    pInfo->stateStore.streamStateReloadInfo(pInfo->pState, ts);
1,143✔
1968
  }
1969
  SOperatorInfo* downstream = pOperator->pDownstream[0];
1,287✔
1970
  if (downstream->fpSet.reloadStreamStateFn) {
1,287!
1971
    downstream->fpSet.reloadStreamStateFn(downstream);
1,287✔
1972
  }
1973
  reloadFromDownStream(downstream, pInfo);
1,287✔
1974

1975
_end:
1,287✔
1976
  if (code != TSDB_CODE_SUCCESS) {
1,287!
UNCOV
1977
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
1978
  }
1979
}
1,287✔
1980

1981
int32_t createStreamFinalIntervalOperatorInfo(SOperatorInfo* downstream, SPhysiNode* pPhyNode, SExecTaskInfo* pTaskInfo,
928✔
1982
                                              int32_t numOfChild, SReadHandle* pHandle, SOperatorInfo** pOptrInfo) {
1983
  QRY_PARAM_CHECK(pOptrInfo);
928!
1984

1985
  int32_t                      code = TSDB_CODE_SUCCESS;
928✔
1986
  int32_t                      lino = 0;
928✔
1987
  SIntervalPhysiNode*          pIntervalPhyNode = (SIntervalPhysiNode*)pPhyNode;
928✔
1988
  SStreamIntervalOperatorInfo* pInfo = taosMemoryCalloc(1, sizeof(SStreamIntervalOperatorInfo));
928!
1989
  SOperatorInfo*               pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo));
929!
1990
  if (pInfo == NULL || pOperator == NULL) {
929!
UNCOV
1991
    code = terrno;
×
UNCOV
1992
    QUERY_CHECK_CODE(code, lino, _error);
×
1993
  }
1994

1995
  pOperator->exprSupp.hasWindowOrGroup = true;
929✔
1996
  pOperator->pTaskInfo = pTaskInfo;
929✔
1997
  SStorageAPI* pAPI = &pTaskInfo->storageAPI;
929✔
1998

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

UNCOV
2023
    code = createExprInfo(pIntervalPhyNode->window.pExprs, NULL, &pScalarExprInfo, &numOfScalar);
×
UNCOV
2024
    QUERY_CHECK_CODE(code, lino, _error);
×
2025

UNCOV
2026
    code = initExprSupp(&pInfo->scalarSupp, pScalarExprInfo, numOfScalar, &pTaskInfo->storageAPI.functionStore);
×
UNCOV
2027
    QUERY_CHECK_CODE(code, lino, _error);
×
2028
  }
2029

2030
  SSDataBlock* pResBlock = createDataBlockFromDescNode(pPhyNode->pOutputDataBlockDesc);
929✔
2031
  QUERY_CHECK_NULL(pResBlock, code, lino, _error, terrno);
929!
2032
  initBasicInfo(&pInfo->binfo, pResBlock);
929✔
2033

2034
  pInfo->pState = taosMemoryCalloc(1, sizeof(SStreamState));
929!
2035
  QUERY_CHECK_NULL(pInfo->pState, code, lino, _error, terrno);
929!
2036
  qInfo("open state %p", pInfo->pState);
929!
2037
  pAPI->stateStore.streamStateCopyBackend(pTaskInfo->streamInfo.pState, pInfo->pState);
929✔
2038
  //*(pInfo->pState) = *(pTaskInfo->streamInfo.pState);
2039

2040
  qInfo("copy state %p to %p", pTaskInfo->streamInfo.pState, pInfo->pState);
929!
2041

2042
  pAPI->stateStore.streamStateSetNumber(pInfo->pState, -1, pInfo->primaryTsIndex);
929✔
2043

2044
  int32_t    numOfCols = 0;
929✔
2045
  SExprInfo* pExprInfo = NULL;
929✔
2046
  code = createExprInfo(pIntervalPhyNode->window.pFuncs, NULL, &pExprInfo, &numOfCols);
929✔
2047
  QUERY_CHECK_CODE(code, lino, _error);
929!
2048

2049
  code = initAggSup(&pOperator->exprSupp, &pInfo->aggSup, pExprInfo, numOfCols, keyBufSize, pTaskInfo->id.str,
929✔
2050
                    pInfo->pState, &pTaskInfo->storageAPI.functionStore);
929✔
2051
  QUERY_CHECK_CODE(code, lino, _error);
929!
2052

2053
  code = initExecTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &pTaskInfo->window);
929✔
2054
  QUERY_CHECK_CODE(code, lino, _error);
929!
2055
  initResultRowInfo(&pInfo->binfo.resultRowInfo);
929✔
2056

2057
  pInfo->numOfChild = numOfChild;
929✔
2058
  pInfo->pPhyNode = NULL;
929✔
2059
  code = nodesCloneNode((SNode*)pPhyNode, (SNode**)&pInfo->pPhyNode);
929✔
2060
  if (TSDB_CODE_SUCCESS != code) {
929!
UNCOV
2061
    goto _error;
×
2062
  }
2063

2064
  pInfo->pPullWins = taosArrayInit(8, sizeof(SPullWindowInfo));
929✔
2065
  QUERY_CHECK_NULL(pInfo->pPullWins, code, lino, _error, terrno);
929!
2066
  pInfo->pullIndex = 0;
929✔
2067
  _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
929✔
2068
  pInfo->pPullDataMap = taosHashInit(64, hashFn, true, HASH_NO_LOCK);
929✔
2069
  pInfo->pFinalPullDataMap = taosHashInit(64, hashFn, true, HASH_NO_LOCK);
929✔
2070

2071
  code = createSpecialDataBlock(STREAM_RETRIEVE, &pInfo->pPullDataRes);
929✔
2072
  QUERY_CHECK_CODE(code, lino, _error);
929!
2073

2074
  pInfo->ignoreExpiredData = pIntervalPhyNode->window.igExpired;
929✔
2075
  pInfo->ignoreExpiredDataSaved = false;
929✔
2076
  code = createSpecialDataBlock(STREAM_DELETE_RESULT, &pInfo->pDelRes);
929✔
2077
  QUERY_CHECK_CODE(code, lino, _error);
929!
2078

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

2091
  // used for backward compatibility of function's result info
2092
  pInfo->pState->pResultRowStore.resultRowGet = getResultRowFromBuf;
929✔
2093
  pInfo->pState->pResultRowStore.resultRowPut = putResultRowToBuf;
929✔
2094
  pInfo->pState->pExprSupp = &pOperator->exprSupp;
929✔
2095

2096
  code =
2097
      pAPI->stateStore.streamFileStateInit(tsStreamBufferSize, sizeof(SWinKey), pInfo->aggSup.resultRowSize, funResSize,
929✔
2098
                                           compareTs, pInfo->pState, pInfo->twAggSup.deleteMark, GET_TASKID(pTaskInfo),
929✔
2099
                                           pHandle->checkpointId, STREAM_STATE_BUFF_HASH, &pInfo->pState->pFileState);
929✔
2100
  QUERY_CHECK_CODE(code, lino, _error);
929!
2101

2102
  pInfo->dataVersion = 0;
929✔
2103
  pInfo->recvGetAll = false;
929✔
2104
  pInfo->recvPullover = false;
929✔
2105
  pInfo->recvRetrive = false;
929✔
2106

2107
  code = createSpecialDataBlock(STREAM_CHECKPOINT, &pInfo->pCheckpointRes);
929✔
2108
  QUERY_CHECK_CODE(code, lino, _error);
929!
2109
  code = createSpecialDataBlock(STREAM_MID_RETRIEVE, &pInfo->pMidRetriveRes);
929✔
2110
  QUERY_CHECK_CODE(code, lino, _error);
929!
2111
  code = createSpecialDataBlock(STREAM_MID_RETRIEVE, &pInfo->pMidPulloverRes);
929✔
2112
  QUERY_CHECK_CODE(code, lino, _error);
929!
2113

2114
  pInfo->clearState = false;
929✔
2115
  pInfo->pMidPullDatas = taosArrayInit(4, sizeof(SWinKey));
929✔
2116
  QUERY_CHECK_NULL(pInfo->pMidPullDatas, code, lino, _error, terrno);
929!
2117
  pInfo->pDeletedMap = tSimpleHashInit(4096, hashFn);
929✔
2118
  QUERY_CHECK_NULL(pInfo->pDeletedMap, code, lino, _error, terrno);
929!
2119
  pInfo->destHasPrimaryKey = pIntervalPhyNode->window.destHasPrimaryKey;
929✔
2120
  pInfo->pOperator = pOperator;
929✔
2121

2122
  pOperator->operatorType = pPhyNode->type;
929✔
2123
  if (!IS_FINAL_INTERVAL_OP(pOperator) || numOfChild == 0) {
929!
2124
    pInfo->twAggSup.calTrigger = STREAM_TRIGGER_AT_ONCE;
707✔
2125
  }
2126
  pOperator->name = getStreamOpName(pOperator->operatorType);
929✔
2127
  pOperator->blocking = true;
929✔
2128
  pOperator->status = OP_NOT_OPENED;
929✔
2129
  pOperator->info = pInfo;
929✔
2130

2131
  if (pPhyNode->type == QUERY_NODE_PHYSICAL_PLAN_STREAM_MID_INTERVAL) {
929✔
2132
    pOperator->fpSet =
2133
        createOperatorFpSet(NULL, doStreamMidIntervalAggNext, NULL, destroyStreamFinalIntervalOperatorInfo,
22✔
2134
                            optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
2135
  } else {
2136
    pOperator->fpSet =
2137
        createOperatorFpSet(NULL, doStreamFinalIntervalAggNext, NULL, destroyStreamFinalIntervalOperatorInfo,
907✔
2138
                            optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
2139
  }
2140
  setOperatorStreamStateFn(pOperator, streamIntervalReleaseState, streamIntervalReloadState);
929✔
2141

2142
  code = initStreamBasicInfo(&pInfo->basic, pOperator);
929✔
2143
  QUERY_CHECK_CODE(code, lino, _error);
929!
2144

2145
  if (pPhyNode->type == QUERY_NODE_PHYSICAL_PLAN_STREAM_SEMI_INTERVAL ||
929✔
2146
      pPhyNode->type == QUERY_NODE_PHYSICAL_PLAN_STREAM_MID_INTERVAL) {
244✔
2147
    pInfo->basic.primaryPkIndex = -1;
707✔
2148
    code = initIntervalDownStream(downstream, pPhyNode->type, pInfo, &pInfo->basic);
707✔
2149
    QUERY_CHECK_CODE(code, lino, _error);
707!
2150
  }
2151
  code = appendDownstream(pOperator, &downstream, 1);
929✔
2152
  QUERY_CHECK_CODE(code, lino, _error);
929!
2153

2154
  // for stream
2155
  void*   buff = NULL;
929✔
2156
  int32_t len = 0;
929✔
2157
  int32_t res = pAPI->stateStore.streamStateGetInfo(pInfo->pState, STREAM_INTERVAL_OP_CHECKPOINT_NAME,
929✔
2158
                                                    strlen(STREAM_INTERVAL_OP_CHECKPOINT_NAME), &buff, &len);
2159
  if (res == TSDB_CODE_SUCCESS) {
929✔
2160
    doStreamIntervalDecodeOpState(buff, len, pOperator);
8✔
2161
    taosMemoryFree(buff);
8!
2162
  }
2163

2164
  *pOptrInfo = pOperator;
929✔
2165
  return TSDB_CODE_SUCCESS;
929✔
2166

UNCOV
2167
_error:
×
UNCOV
2168
  if (pInfo != NULL) destroyStreamFinalIntervalOperatorInfo(pInfo);
×
UNCOV
2169
  destroyOperatorAndDownstreams(pOperator, &downstream, 1);
×
UNCOV
2170
  pTaskInfo->code = code;
×
UNCOV
2171
  return code;
×
2172
}
2173

2174
void destroyStreamAggSupporter(SStreamAggSupporter* pSup) {
2,145✔
2175
  tSimpleHashCleanup(pSup->pResultRows);
2,145✔
2176
  destroyDiskbasedBuf(pSup->pResultBuf);
2,145✔
2177
  blockDataDestroy(pSup->pScanBlock);
2,145✔
2178
  if (pSup->stateStore.streamFileStateDestroy != NULL) {
2,145!
2179
    pSup->stateStore.streamFileStateDestroy(pSup->pState->pFileState);
2,145✔
2180
  }
2181
  taosMemoryFreeClear(pSup->pState);
2,145!
2182
  taosMemoryFreeClear(pSup->pDummyCtx);
2,145!
2183
}
2,145✔
2184

2185
void destroyStreamSessionAggOperatorInfo(void* param) {
904✔
2186
  if (param == NULL) {
904!
UNCOV
2187
    return;
×
2188
  }
2189
  SStreamSessionAggOperatorInfo* pInfo = (SStreamSessionAggOperatorInfo*)param;
904✔
2190
  cleanupBasicInfo(&pInfo->binfo);
904✔
2191
  if (pInfo->pOperator) {
904!
2192
    cleanupResultInfoInStream(pInfo->pOperator->pTaskInfo, pInfo->streamAggSup.pState, &pInfo->pOperator->exprSupp,
904✔
2193
                              &pInfo->groupResInfo);
2194
    pInfo->pOperator = NULL;
904✔
2195
  }
2196

2197
  destroyStreamBasicInfo(&pInfo->basic);
904✔
2198
  cleanupExprSupp(&pInfo->scalarSupp);
904✔
2199
  clearGroupResInfo(&pInfo->groupResInfo);
904✔
2200
  taosArrayDestroyP(pInfo->pUpdated, destroyFlusedPos);
904✔
2201
  pInfo->pUpdated = NULL;
904✔
2202
  destroyStreamAggSupporter(&pInfo->streamAggSup);
904✔
2203

2204
  if (pInfo->pChildren != NULL) {
904✔
2205
    int32_t size = taosArrayGetSize(pInfo->pChildren);
38✔
2206
    for (int32_t i = 0; i < size; i++) {
163✔
2207
      SOperatorInfo* pChild = taosArrayGetP(pInfo->pChildren, i);
125✔
2208
      destroyOperator(pChild);
125✔
2209
    }
2210
    taosArrayDestroy(pInfo->pChildren);
38✔
2211
  }
2212

2213
  colDataDestroy(&pInfo->twAggSup.timeWindowData);
904✔
2214
  blockDataDestroy(pInfo->pDelRes);
904✔
2215
  blockDataDestroy(pInfo->pWinBlock);
904✔
2216
  tSimpleHashCleanup(pInfo->pStUpdated);
904✔
2217
  tSimpleHashCleanup(pInfo->pStDeleted);
904✔
2218
  cleanupGroupResInfo(&pInfo->groupResInfo);
904✔
2219

2220
  taosArrayDestroy(pInfo->historyWins);
904✔
2221
  blockDataDestroy(pInfo->pCheckpointRes);
904✔
2222
  tSimpleHashCleanup(pInfo->pPkDeleted);
904✔
2223
  destroyNonBlockAggSupptor(&pInfo->nbSup);
904✔
2224

2225
  taosMemoryFreeClear(param);
904!
2226
}
2227

2228
int32_t initBasicInfoEx(SOptrBasicInfo* pBasicInfo, SExprSupp* pSup, SExprInfo* pExprInfo, int32_t numOfCols,
1,796✔
2229
                        SSDataBlock* pResultBlock, SFunctionStateStore* pStore) {
2230
  initBasicInfo(pBasicInfo, pResultBlock);
1,796✔
2231
  int32_t code = initExprSupp(pSup, pExprInfo, numOfCols, pStore);
1,796✔
2232
  if (code != TSDB_CODE_SUCCESS) {
1,797!
UNCOV
2233
    return code;
×
2234
  }
2235

2236
  for (int32_t i = 0; i < numOfCols; ++i) {
28,615✔
2237
    pSup->pCtx[i].saveHandle.pBuf = NULL;
26,818✔
2238
  }
2239

2240
  return TSDB_CODE_SUCCESS;
1,797✔
2241
}
2242

2243
void initDummyFunction(SqlFunctionCtx* pDummy, SqlFunctionCtx* pCtx, int32_t nums) {
2,143✔
2244
  for (int i = 0; i < nums; i++) {
30,453✔
2245
    pDummy[i].functionId = pCtx[i].functionId;
28,310✔
2246
    pDummy[i].isNotNullFunc = pCtx[i].isNotNullFunc;
28,310✔
2247
    pDummy[i].isPseudoFunc = pCtx[i].isPseudoFunc;
28,310✔
2248
    pDummy[i].fpSet.init = pCtx[i].fpSet.init;
28,310✔
2249
  }
2250
}
2,143✔
2251

2252
int32_t initDownStream(SOperatorInfo* downstream, SStreamAggSupporter* pAggSup, uint16_t type, int32_t tsColIndex,
2,314✔
2253
                       STimeWindowAggSupp* pTwSup, struct SSteamOpBasicInfo* pBasic, int64_t recalculateInterval) {
2254
  SExecTaskInfo* pTaskInfo = downstream->pTaskInfo;
2,314✔
2255
  int32_t        code = TSDB_CODE_SUCCESS;
2,314✔
2256
  int32_t        lino = 0;
2,314✔
2257
  if (downstream->operatorType == QUERY_NODE_PHYSICAL_PLAN_STREAM_PARTITION) {
2,314✔
2258
    SStreamPartitionOperatorInfo* pScanInfo = downstream->info;
642✔
2259
    pScanInfo->tsColIndex = tsColIndex;
642✔
2260
    pBasic->primaryPkIndex = pScanInfo->basic.primaryPkIndex;
642✔
2261
  }
2262

2263
  if (downstream->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_SCAN) {
2,314✔
2264
    code = initDownStream(downstream->pDownstream[0], pAggSup, type, tsColIndex, pTwSup, pBasic, recalculateInterval);
642✔
2265
    return code;
642✔
2266
  }
2267
  SStreamScanInfo* pScanInfo = downstream->info;
1,672✔
2268
  pScanInfo->windowSup = (SWindowSupporter){.pStreamAggSup = pAggSup, .gap = pAggSup->gap, .parentType = type};
1,672✔
2269
  pScanInfo->pState = pAggSup->pState;
1,672✔
2270
  if (!pScanInfo->pUpdateInfo) {
1,672✔
2271
    code = pAggSup->stateStore.updateInfoInit(60000, TSDB_TIME_PRECISION_MILLI, pTwSup->waterMark,
1,030✔
2272
                                              pScanInfo->igCheckUpdate, pScanInfo->pkColType, pScanInfo->pkColLen,
1,030✔
2273
                                              &pScanInfo->pUpdateInfo);
1,030✔
2274
    QUERY_CHECK_CODE(code, lino, _end);
1,030!
2275
  }
2276
  pScanInfo->twAggSup = *pTwSup;
1,672✔
2277
  pAggSup->pUpdateInfo = pScanInfo->pUpdateInfo;
1,672✔
2278
  if (!hasSrcPrimaryKeyCol(pBasic)) {
1,672✔
2279
    pBasic->primaryPkIndex = pScanInfo->basic.primaryPkIndex;
1,668✔
2280
  }
2281

2282
  pBasic->pTsDataState = pScanInfo->basic.pTsDataState;
1,672✔
2283

2284
  if (type == QUERY_NODE_PHYSICAL_PLAN_STREAM_CONTINUE_SEMI_SESSION) {
1,672!
UNCOV
2285
    pScanInfo->scanAllTables = true;
×
2286
  }
2287
  pScanInfo->recalculateInterval = recalculateInterval;
1,672✔
2288
  pScanInfo->windowSup.parentType = type;
1,672✔
2289
  pScanInfo->recParam.gap = pAggSup->gap;
1,672✔
2290

2291
_end:
1,672✔
2292
  if (code != TSDB_CODE_SUCCESS) {
1,672!
UNCOV
2293
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
2294
  }
2295
  return code;
1,672✔
2296
}
2297

2298
static TSKEY sesionTs(void* pKey) {
6,018✔
2299
  SSessionKey* pWinKey = (SSessionKey*)pKey;
6,018✔
2300
  return pWinKey->win.skey;
6,018✔
2301
}
2302

2303
int32_t initStreamAggSupporter(SStreamAggSupporter* pSup, SExprSupp* pExpSup, int32_t numOfOutput, int64_t gap,
2,142✔
2304
                               SStreamState* pState, int32_t keySize, int16_t keyType, SStateStore* pStore,
2305
                               SReadHandle* pHandle, STimeWindowAggSupp* pTwAggSup, const char* taskIdStr,
2306
                               SStorageAPI* pApi, int32_t tsIndex, int8_t stateType, int32_t ratio) {
2307
  pSup->resultRowSize = (keySize + getResultRowSize(pExpSup->pCtx, numOfOutput)) * ratio;
2,142✔
2308
  int32_t lino = 0;
2,145✔
2309
  int32_t code = createSpecialDataBlock(STREAM_CLEAR, &pSup->pScanBlock);
2,145✔
2310
  QUERY_CHECK_CODE(code, lino, _end);
2,145!
2311

2312
  pSup->gap = gap;
2,145✔
2313
  pSup->stateKeySize = keySize;
2,145✔
2314
  pSup->stateKeyType = keyType;
2,145✔
2315
  pSup->pDummyCtx = (SqlFunctionCtx*)taosMemoryCalloc(numOfOutput, sizeof(SqlFunctionCtx));
2,145!
2316
  QUERY_CHECK_NULL(pSup->pDummyCtx, code, lino, _end, terrno);
2,143!
2317

2318
  pSup->stateStore = *pStore;
2,143✔
2319
  pSup->pSessionAPI = pApi;
2,143✔
2320

2321
  initDummyFunction(pSup->pDummyCtx, pExpSup->pCtx, numOfOutput);
2,143✔
2322
  pSup->pState = taosMemoryCalloc(1, sizeof(SStreamState));
2,144!
2323
  QUERY_CHECK_NULL(pSup->pState, code, lino, _end, terrno);
2,145!
2324

2325
  *(pSup->pState) = *pState;
2,145✔
2326
  pSup->stateStore.streamStateSetNumber(pSup->pState, -1, tsIndex);
2,145✔
2327
  int32_t funResSize = getMaxFunResSize(pExpSup, numOfOutput);
2,142✔
2328
  if (stateType != STREAM_STATE_BUFF_HASH_SORT) {
2,145✔
2329
    // used for backward compatibility of function's result info
2330
    pSup->pState->pResultRowStore.resultRowGet = getResultRowFromBuf;
1,924✔
2331
    pSup->pState->pResultRowStore.resultRowPut = putResultRowToBuf;
1,924✔
2332
    pSup->pState->pExprSupp = pExpSup;
1,924✔
2333
  }
2334

2335
  if (stateType == STREAM_STATE_BUFF_SORT) {
2,145✔
2336
    pSup->pState->pFileState = NULL;
1,797✔
2337
    code = pSup->stateStore.streamFileStateInit(tsStreamBufferSize, sizeof(SSessionKey), pSup->resultRowSize,
1,797✔
2338
                                                funResSize, sesionTs, pSup->pState, pTwAggSup->deleteMark, taskIdStr,
1,797✔
2339
                                                pHandle->checkpointId, stateType, &pSup->pState->pFileState);
1,797✔
2340
  } else if (stateType == STREAM_STATE_BUFF_HASH_SORT || stateType == STREAM_STATE_BUFF_HASH_SEARCH) {
348!
2341
    pSup->pState->pFileState = NULL;
348✔
2342
    code = pSup->stateStore.streamFileStateInit(tsStreamBufferSize, sizeof(SWinKey), pSup->resultRowSize, funResSize,
348✔
2343
                                                compareTs, pSup->pState, pTwAggSup->deleteMark, taskIdStr,
348✔
2344
                                                pHandle->checkpointId, stateType, &pSup->pState->pFileState);
348✔
2345
  }
2346
  QUERY_CHECK_CODE(code, lino, _end);
2,145!
2347

2348
  _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
2,145✔
2349
  pSup->pResultRows = tSimpleHashInit(32, hashFn);
2,145✔
2350
  QUERY_CHECK_NULL(pSup->pResultRows, code, lino, _end, terrno);
2,145!
2351

2352
  for (int32_t i = 0; i < numOfOutput; ++i) {
30,444✔
2353
    pExpSup->pCtx[i].saveHandle.pState = pSup->pState;
28,299✔
2354
  }
2355

2356
  pSup->pCur = NULL;
2,145✔
2357

2358
_end:
2,145✔
2359
  if (code != TSDB_CODE_SUCCESS) {
2,145!
UNCOV
2360
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
2361
  }
2362
  return code;
2,144✔
2363
}
2364

2365
bool isInTimeWindow(STimeWindow* pWin, TSKEY ts, int64_t gap) {
5,629✔
2366
  if (ts + gap >= pWin->skey && ts - gap <= pWin->ekey) {
5,629✔
2367
    return true;
4,132✔
2368
  }
2369
  return false;
1,497✔
2370
}
2371

2372
bool isInWindow(SResultWindowInfo* pWinInfo, TSKEY ts, int64_t gap) {
4,704✔
2373
  return isInTimeWindow(&pWinInfo->sessionWin.win, ts, gap);
4,704✔
2374
}
2375

2376
void getCurSessionWindow(SStreamAggSupporter* pAggSup, TSKEY startTs, TSKEY endTs, uint64_t groupId,
4,591✔
2377
                         SSessionKey* pKey) {
2378
  pKey->win.skey = startTs;
4,591✔
2379
  pKey->win.ekey = endTs;
4,591✔
2380
  pKey->groupId = groupId;
4,591✔
2381
  int32_t code = pAggSup->stateStore.streamStateSessionGetKeyByRange(pAggSup->pState, pKey, pKey);
4,591✔
2382
  if (code != TSDB_CODE_SUCCESS) {
4,594✔
2383
    SET_SESSION_WIN_KEY_INVALID(pKey);
1,319✔
2384
  }
2385
}
4,594✔
2386

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

2389
bool inWinRange(STimeWindow* range, STimeWindow* cur) {
51,671✔
2390
  if (cur->skey >= range->skey && cur->ekey <= range->ekey) {
51,671!
2391
    return true;
51,679✔
2392
  }
UNCOV
2393
  return false;
×
2394
}
2395

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

2398
int32_t setSessionOutputBuf(SStreamAggSupporter* pAggSup, TSKEY startTs, TSKEY endTs, uint64_t groupId,
3,255✔
2399
                            SResultWindowInfo* pCurWin, int32_t* pWinCode) {
2400
  int32_t code = TSDB_CODE_SUCCESS;
3,255✔
2401
  int32_t lino = 0;
3,255✔
2402
  pCurWin->sessionWin.groupId = groupId;
3,255✔
2403
  pCurWin->sessionWin.win.skey = startTs;
3,255✔
2404
  pCurWin->sessionWin.win.ekey = endTs;
3,255✔
2405
  int32_t size = pAggSup->resultRowSize;
3,255✔
2406
  code = pAggSup->stateStore.streamStateSessionAddIfNotExist(pAggSup->pState, &pCurWin->sessionWin, pAggSup->gap,
3,255✔
2407
                                                             (void**)&pCurWin->pStatePos, &size, pWinCode);
3,255✔
2408
  QUERY_CHECK_CODE(code, lino, _end);
3,254!
2409

2410
  if (*pWinCode == TSDB_CODE_SUCCESS && !inWinRange(&pAggSup->winRange, &pCurWin->sessionWin.win)) {
3,254!
2411
    *pWinCode = TSDB_CODE_FAILED;
×
UNCOV
2412
    clearOutputBuf(pAggSup->pState, pCurWin->pStatePos, &pAggSup->pSessionAPI->stateStore);
×
2413
  }
2414

2415
  if (*pWinCode == TSDB_CODE_SUCCESS) {
3,253✔
2416
    pCurWin->isOutput = true;
921✔
2417
    if (pCurWin->pStatePos->needFree) {
921✔
2418
      pAggSup->stateStore.streamStateSessionDel(pAggSup->pState, &pCurWin->sessionWin);
135✔
2419
    }
2420
  } else {
2421
    pCurWin->sessionWin.win.skey = startTs;
2,332✔
2422
    pCurWin->sessionWin.win.ekey = endTs;
2,332✔
2423
  }
2424
  qDebug("===stream===set session window buff .start:%" PRId64 ",end:%" PRId64 ",groupid:%" PRIu64,
3,254✔
2425
         pCurWin->sessionWin.win.skey, pCurWin->sessionWin.win.ekey, pCurWin->sessionWin.groupId);
2426
_end:
1,764✔
2427
  if (code != TSDB_CODE_SUCCESS) {
3,254!
2428
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
2429
  }
2430
  return code;
3,254✔
2431
}
2432

2433
void getSessionWinBuf(SStreamAggSupporter* pAggSup, SStreamStateCur* pCur, SResultWindowInfo* pWinInfo,
210✔
2434
                      int32_t* pWinCode) {
2435
  int32_t size = 0;
210✔
2436
  (*pWinCode) = pAggSup->stateStore.streamStateSessionGetKVByCur(pCur, &pWinInfo->sessionWin,
420✔
2437
                                                                 (void**)&pWinInfo->pStatePos, &size);
210✔
2438
  if ((*pWinCode) != TSDB_CODE_SUCCESS) {
210✔
2439
    return;
178✔
2440
  }
2441

2442
  pAggSup->stateStore.streamStateCurNext(pAggSup->pState, pCur);
32✔
2443
}
2444

2445
int32_t saveDeleteInfo(SArray* pWins, SSessionKey key) {
1,240✔
2446
  int32_t code = TSDB_CODE_SUCCESS;
1,240✔
2447
  int32_t lino = 0;
1,240✔
2448
  void*   res = taosArrayPush(pWins, &key);
1,238✔
2449
  if (!res) {
1,238!
2450
    code = terrno;
×
2451
    QUERY_CHECK_CODE(code, lino, _end);
×
2452
  }
2453

2454
_end:
1,238✔
2455
  if (code != TSDB_CODE_SUCCESS) {
1,238!
2456
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
2457
  }
2458
  return code;
1,237✔
2459
}
2460

2461
int32_t saveDeleteRes(SSHashObj* pStDelete, SSessionKey key) {
80✔
2462
  key.win.ekey = key.win.skey;
80✔
2463
  return tSimpleHashPut(pStDelete, &key, sizeof(SSessionKey), NULL, 0);
80✔
2464
}
2465

2466
void releaseOutputBuf(void* pState, SRowBuffPos* pPos, SStateStore* pAPI) {
13,064✔
2467
  pAPI->streamStateReleaseBuf(pState, pPos, false);
13,064✔
2468
}
13,065✔
2469

2470
void removeSessionResult(SStreamAggSupporter* pAggSup, SSHashObj* pHashMap, SSHashObj* pResMap, SSessionKey* pKey) {
85✔
2471
  int32_t     code = TSDB_CODE_SUCCESS;
85✔
2472
  int32_t     lino = 0;
85✔
2473
  SSessionKey key = {0};
85✔
2474
  getSessionHashKey(pKey, &key);
85✔
2475
  void* pVal = tSimpleHashGet(pHashMap, &key, sizeof(SSessionKey));
86✔
2476
  if (pVal) {
85✔
2477
    releaseOutputBuf(pAggSup->pState, *(void**)pVal, &pAggSup->pSessionAPI->stateStore);
5✔
2478
    int32_t tmpRes = tSimpleHashRemove(pHashMap, &key, sizeof(SSessionKey));
5✔
2479
    qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
5!
2480
  }
2481
  int32_t tmpRes = tSimpleHashRemove(pResMap, &key, sizeof(SSessionKey));
85✔
2482
  qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
87✔
2483
}
87✔
2484

2485
void getSessionHashKey(const SSessionKey* pKey, SSessionKey* pHashKey) {
13,418✔
2486
  *pHashKey = *pKey;
13,418✔
2487
  pHashKey->win.ekey = pKey->win.skey;
13,418✔
2488
}
13,418✔
2489

2490
void removeSessionDeleteResults(SSHashObj* pHashMap, SArray* pWins) {
10,874✔
2491
  if (tSimpleHashGetSize(pHashMap) == 0) {
10,874✔
2492
    return;
9,829✔
2493
  }
2494
  int32_t size = taosArrayGetSize(pWins);
1,039✔
2495
  for (int32_t i = 0; i < size; i++) {
2,385✔
2496
    SResultWindowInfo* pWin = taosArrayGet(pWins, i);
1,349✔
2497
    if (!pWin) continue;
1,349!
2498
    SSessionKey key = {0};
1,349✔
2499
    getSessionHashKey(&pWin->sessionWin, &key);
1,349✔
2500
    int32_t tmpRes = tSimpleHashRemove(pHashMap, &key, sizeof(SSessionKey));
1,349✔
2501
    qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
1,349✔
2502
  }
2503
}
2504

2505
void removeSessionResults(SStreamAggSupporter* pAggSup, SSHashObj* pHashMap, SArray* pWins) {
1,133✔
2506
  if (tSimpleHashGetSize(pHashMap) == 0) {
1,133✔
2507
    return;
851✔
2508
  }
2509
  int32_t size = taosArrayGetSize(pWins);
281✔
2510
  for (int32_t i = 0; i < size; i++) {
612✔
2511
    SSessionKey* pWin = taosArrayGet(pWins, i);
330✔
2512
    if (!pWin) continue;
330!
2513
    SSessionKey key = {0};
330✔
2514
    getSessionHashKey(pWin, &key);
330✔
2515
    void* pVal = tSimpleHashGet(pHashMap, &key, sizeof(SSessionKey));
330✔
2516
    if (pVal) {
331✔
2517
      releaseOutputBuf(pAggSup->pState, *(void**)pVal, &pAggSup->pSessionAPI->stateStore);
203✔
2518
      int32_t tmpRes = tSimpleHashRemove(pHashMap, &key, sizeof(SSessionKey));
203✔
2519
      qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
203!
2520
    }
2521
  }
2522
}
2523

2524
int32_t updateSessionWindowInfo(SStreamAggSupporter* pAggSup, SResultWindowInfo* pWinInfo, TSKEY* pStartTs,
3,232✔
2525
                                TSKEY* pEndTs, uint64_t groupId, int32_t rows, int32_t start, int64_t gap,
2526
                                SSHashObj* pResultRows, SSHashObj* pStUpdated, SSHashObj* pStDeleted,
2527
                                int32_t* pWinRos) {
2528
  int32_t code = TSDB_CODE_SUCCESS;
3,232✔
2529
  int32_t lino = 0;
3,232✔
2530
  for (int32_t i = start; i < rows; ++i) {
7,296✔
2531
    if (!isInWindow(pWinInfo, pStartTs[i], gap) && (!pEndTs || !isInWindow(pWinInfo, pEndTs[i], gap))) {
4,174!
2532
      (*pWinRos) = i - start;
104✔
2533
      goto _end;
104✔
2534
    }
2535
    if (pWinInfo->sessionWin.win.skey > pStartTs[i]) {
4,063✔
2536
      if (pStDeleted && pWinInfo->isOutput) {
24✔
2537
        code = saveDeleteRes(pStDeleted, pWinInfo->sessionWin);
18✔
2538
        QUERY_CHECK_CODE(code, lino, _end);
19!
2539
      }
2540

2541
      removeSessionResult(pAggSup, pStUpdated, pResultRows, &pWinInfo->sessionWin);
25✔
2542
      pWinInfo->sessionWin.win.skey = pStartTs[i];
25✔
2543
    }
2544
    pWinInfo->sessionWin.win.ekey = TMAX(pWinInfo->sessionWin.win.ekey, pStartTs[i]);
4,064✔
2545
    if (pEndTs) {
4,064!
2546
      pWinInfo->sessionWin.win.ekey = TMAX(pWinInfo->sessionWin.win.ekey, pEndTs[i]);
4,069✔
2547
    }
2548
    memcpy(pWinInfo->pStatePos->pKey, &pWinInfo->sessionWin, sizeof(SSessionKey));
4,064✔
2549
  }
2550
  (*pWinRos) = rows - start;
3,122✔
2551

2552
_end:
3,226✔
2553
  if (code != TSDB_CODE_SUCCESS) {
3,226!
UNCOV
2554
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
2555
  }
2556
  return code;
3,231✔
2557
}
2558

2559
static int32_t initSessionOutputBuf(SResultWindowInfo* pWinInfo, SResultRow** pResult, SqlFunctionCtx* pCtx,
12,506✔
2560
                                    int32_t numOfOutput, int32_t* rowEntryInfoOffset) {
2561
  *pResult = (SResultRow*)pWinInfo->pStatePos->pRowBuff;
12,506✔
2562
  // set time window for current result
2563
  (*pResult)->win = pWinInfo->sessionWin.win;
12,506✔
2564
  return setResultRowInitCtx(*pResult, pCtx, numOfOutput, rowEntryInfoOffset);
12,506✔
2565
}
2566

2567
int32_t doOneWindowAggImpl(SColumnInfoData* pTimeWindowData, SResultWindowInfo* pCurWin, SResultRow** pResult,
12,423✔
2568
                           int32_t startIndex, int32_t winRows, int32_t rows, int32_t numOutput,
2569
                           SOperatorInfo* pOperator, int64_t winDelta) {
2570
  int32_t        code = TSDB_CODE_SUCCESS;
12,423✔
2571
  int32_t        lino = 0;
12,423✔
2572
  SExprSupp*     pSup = &pOperator->exprSupp;
12,423✔
2573
  SExecTaskInfo* pTaskInfo = pOperator->pTaskInfo;
12,423✔
2574
  code = initSessionOutputBuf(pCurWin, pResult, pSup->pCtx, numOutput, pSup->rowEntryInfoOffset);
12,423✔
2575
  QUERY_CHECK_CODE(code, lino, _end);
12,427!
2576

2577
  updateTimeWindowInfo(pTimeWindowData, &pCurWin->sessionWin.win, winDelta);
12,427✔
2578
  code = applyAggFunctionOnPartialTuples(pTaskInfo, pSup->pCtx, pTimeWindowData, startIndex, winRows, rows, numOutput);
12,425✔
2579

2580
_end:
12,431✔
2581
  if (code != TSDB_CODE_SUCCESS) {
12,431!
UNCOV
2582
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
2583
  }
2584
  return code;
12,428✔
2585
}
2586

2587
void doDeleteSessionWindow(SStreamAggSupporter* pAggSup, SSessionKey* pKey) {
1,324✔
2588
  pAggSup->stateStore.streamStateSessionDel(pAggSup->pState, pKey);
1,324✔
2589
  SSessionKey hashKey = {0};
1,323✔
2590
  getSessionHashKey(pKey, &hashKey);
1,323✔
2591
  int32_t tmpRes = tSimpleHashRemove(pAggSup->pResultRows, &hashKey, sizeof(SSessionKey));
1,322✔
2592
  qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
1,324✔
2593
}
1,324✔
2594

2595
void setSessionWinOutputInfo(SSHashObj* pStUpdated, SResultWindowInfo* pWinInfo) {
16,046✔
2596
  void* pVal = tSimpleHashGet(pStUpdated, &pWinInfo->sessionWin, sizeof(SSessionKey));
16,046✔
2597
  if (pVal) {
16,047✔
2598
    SResultWindowInfo* pWin = pVal;
802✔
2599
    pWinInfo->isOutput = pWin->isOutput;
802✔
2600
  }
2601
}
16,047✔
2602

2603
void getNextSessionWinInfo(SStreamAggSupporter* pAggSup, SSHashObj* pStUpdated, SResultWindowInfo* pCurWin,
3,539✔
2604
                           SResultWindowInfo* pNextWin) {
2605
  SStreamStateCur* pCur = pAggSup->stateStore.streamStateSessionSeekKeyNext(pAggSup->pState, &pCurWin->sessionWin);
3,539✔
2606
  pNextWin->isOutput = true;
3,533✔
2607
  setSessionWinOutputInfo(pStUpdated, pNextWin);
3,533✔
2608
  int32_t size = 0;
3,536✔
2609
  pNextWin->sessionWin = pCurWin->sessionWin;
3,536✔
2610
  int32_t code = pAggSup->stateStore.streamStateSessionGetKVByCur(pCur, &pNextWin->sessionWin,
3,536✔
2611
                                                                  (void**)&pNextWin->pStatePos, &size);
3,536✔
2612
  if (code != TSDB_CODE_SUCCESS) {
3,538✔
2613
    SET_SESSION_WIN_INVALID(*pNextWin);
3,107✔
2614
  }
2615
  pAggSup->stateStore.streamStateFreeCur(pCur);
3,538✔
2616
}
3,536✔
2617

2618
int32_t compactTimeWindow(SExprSupp* pSup, SStreamAggSupporter* pAggSup, STimeWindowAggSupp* pTwAggSup,
23✔
2619
                          SExecTaskInfo* pTaskInfo, SResultWindowInfo* pCurWin, SResultWindowInfo* pNextWin,
2620
                          SSHashObj* pStUpdated, SSHashObj* pStDeleted, bool addGap) {
2621
  int32_t     code = TSDB_CODE_SUCCESS;
23✔
2622
  int32_t     lino = 0;
23✔
2623
  SResultRow* pCurResult = NULL;
23✔
2624
  int32_t     numOfOutput = pSup->numOfExprs;
23✔
2625
  code = initSessionOutputBuf(pCurWin, &pCurResult, pSup->pCtx, numOfOutput, pSup->rowEntryInfoOffset);
23✔
2626
  QUERY_CHECK_CODE(code, lino, _end);
23!
2627

2628
  SResultRow* pWinResult = NULL;
23✔
2629
  code = initSessionOutputBuf(pNextWin, &pWinResult, pAggSup->pDummyCtx, numOfOutput, pSup->rowEntryInfoOffset);
23✔
2630
  QUERY_CHECK_CODE(code, lino, _end);
23!
2631

2632
  pCurWin->sessionWin.win.ekey = TMAX(pCurWin->sessionWin.win.ekey, pNextWin->sessionWin.win.ekey);
23✔
2633
  memcpy(pCurWin->pStatePos->pKey, &pCurWin->sessionWin, sizeof(SSessionKey));
23✔
2634

2635
  int64_t winDelta = 0;
23✔
2636
  if (addGap) {
23✔
2637
    winDelta = pAggSup->gap;
19✔
2638
  }
2639
  updateTimeWindowInfo(&pTwAggSup->timeWindowData, &pCurWin->sessionWin.win, winDelta);
23✔
2640
  code = compactFunctions(pSup->pCtx, pAggSup->pDummyCtx, numOfOutput, pTaskInfo, &pTwAggSup->timeWindowData);
23✔
2641
  QUERY_CHECK_CODE(code, lino, _end);
23✔
2642

2643
  int32_t tmpRes = tSimpleHashRemove(pStUpdated, &pNextWin->sessionWin, sizeof(SSessionKey));
21✔
2644
  qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
21✔
2645

2646
  if (pNextWin->isOutput && pStDeleted) {
21!
2647
    qDebug("===stream=== save delete window info %" PRId64 ", %" PRIu64, pNextWin->sessionWin.win.skey,
20!
2648
           pNextWin->sessionWin.groupId);
2649
    code = saveDeleteRes(pStDeleted, pNextWin->sessionWin);
20✔
2650
    QUERY_CHECK_CODE(code, lino, _end);
20!
2651
  }
2652
  removeSessionResult(pAggSup, pStUpdated, pAggSup->pResultRows, &pNextWin->sessionWin);
21✔
2653
  doDeleteSessionWindow(pAggSup, &pNextWin->sessionWin);
21✔
2654
  releaseOutputBuf(pAggSup->pState, pNextWin->pStatePos, &pAggSup->pSessionAPI->stateStore);
21✔
2655

2656
_end:
23✔
2657
  if (code != TSDB_CODE_SUCCESS) {
23✔
2658
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
2!
2659
  }
2660
  return code;
23✔
2661
}
2662

2663
int32_t compactSessionWindow(SOperatorInfo* pOperator, SResultWindowInfo* pCurWin, SSHashObj* pStUpdated,
3,416✔
2664
                             SSHashObj* pStDeleted, bool addGap, int32_t* pWinNum, bool* pIsEnd) {
2665
  int32_t                        code = TSDB_CODE_SUCCESS;
3,416✔
2666
  int32_t                        lino = 0;
3,416✔
2667
  SExprSupp*                     pSup = &pOperator->exprSupp;
3,416✔
2668
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
3,416✔
2669
  SStorageAPI*                   pAPI = &pOperator->pTaskInfo->storageAPI;
3,416✔
2670
  int32_t                        winNum = 0;
3,416✔
2671
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
3,416✔
2672
  SResultRow*                    pCurResult = NULL;
3,416✔
2673
  int32_t                        numOfOutput = pOperator->exprSupp.numOfExprs;
3,416✔
2674
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
3,416✔
2675

2676
  if (pIsEnd != NULL) {
3,416!
UNCOV
2677
    (*pIsEnd) = false;
×
2678
  }
2679
  // Just look for the window behind StartIndex
2680
  while (1) {
17✔
2681
    SResultWindowInfo winInfo = {0};
3,433✔
2682
    getNextSessionWinInfo(pAggSup, pStUpdated, pCurWin, &winInfo);
3,433✔
2683
    if (!IS_VALID_SESSION_WIN(winInfo)) {
3,431✔
2684
      if (pIsEnd != NULL) {
3,004!
UNCOV
2685
        (*pIsEnd) = true;
×
2686
      }
2687
      releaseOutputBuf(pAggSup->pState, winInfo.pStatePos, &pAggSup->pSessionAPI->stateStore);
3,004✔
2688
      break;
3,004✔
2689
    }
2690
    if (!isInWindow(pCurWin, winInfo.sessionWin.win.skey, pAggSup->gap) ||
427✔
2691
        !inWinRange(&pAggSup->winRange, &winInfo.sessionWin.win)) {
19!
2692
      releaseOutputBuf(pAggSup->pState, winInfo.pStatePos, &pAggSup->pSessionAPI->stateStore);
408✔
2693
      break;
408✔
2694
    }
2695
    code =
2696
        compactTimeWindow(pSup, pAggSup, &pInfo->twAggSup, pTaskInfo, pCurWin, &winInfo, pStUpdated, pStDeleted, true);
19✔
2697
    QUERY_CHECK_CODE(code, lino, _end);
19✔
2698
    winNum++;
17✔
2699
  }
2700
  if (pWinNum) {
3,412✔
2701
    (*pWinNum) = winNum;
161✔
2702
  }
2703

2704
_end:
3,251✔
2705
  if (code != TSDB_CODE_SUCCESS) {
3,414✔
2706
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
2!
2707
  }
2708
  return code;
3,407✔
2709
}
2710

2711
static void compactSessionSemiWindow(SOperatorInfo* pOperator, SResultWindowInfo* pCurWin) {
25✔
2712
  SExprSupp*                     pSup = &pOperator->exprSupp;
25✔
2713
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
25✔
2714
  SStorageAPI*                   pAPI = &pOperator->pTaskInfo->storageAPI;
25✔
2715
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
25✔
2716
  SResultRow*                    pCurResult = NULL;
25✔
2717
  int32_t                        numOfOutput = pOperator->exprSupp.numOfExprs;
25✔
2718
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
25✔
2719
  // Just look for the window behind StartIndex
2720
  while (1) {
×
2721
    SResultWindowInfo winInfo = {0};
25✔
2722
    getNextSessionWinInfo(pAggSup, NULL, pCurWin, &winInfo);
25✔
2723
    if (!IS_VALID_SESSION_WIN(winInfo) || !isInWindow(pCurWin, winInfo.sessionWin.win.skey, pAggSup->gap) ||
25!
UNCOV
2724
        !inWinRange(&pAggSup->winRange, &winInfo.sessionWin.win)) {
×
2725
      releaseOutputBuf(pAggSup->pState, winInfo.pStatePos, &pAggSup->pSessionAPI->stateStore);
25✔
2726
      break;
25✔
2727
    }
UNCOV
2728
    pCurWin->sessionWin.win.ekey = TMAX(pCurWin->sessionWin.win.ekey, winInfo.sessionWin.win.ekey);
×
UNCOV
2729
    memcpy(pCurWin->pStatePos->pKey, &pCurWin->sessionWin, sizeof(SSessionKey));
×
UNCOV
2730
    doDeleteSessionWindow(pAggSup, &winInfo.sessionWin);
×
UNCOV
2731
    releaseOutputBuf(pAggSup->pState, winInfo.pStatePos, &pAggSup->pSessionAPI->stateStore);
×
2732
  }
2733
}
25✔
2734

2735
int32_t saveSessionOutputBuf(SStreamAggSupporter* pAggSup, SResultWindowInfo* pWinInfo) {
12,775✔
2736
  qDebug("===stream===try save session result skey:%" PRId64 ", ekey:%" PRId64 ".pos%d", pWinInfo->sessionWin.win.skey,
12,775✔
2737
         pWinInfo->sessionWin.win.ekey, pWinInfo->pStatePos->needFree);
2738
  return pAggSup->stateStore.streamStateSessionPut(pAggSup->pState, &pWinInfo->sessionWin, pWinInfo->pStatePos,
12,775✔
2739
                                                   pAggSup->resultRowSize);
2740
}
2741

2742
static void doStreamSessionAggImpl(SOperatorInfo* pOperator, SSDataBlock* pSDataBlock, SSHashObj* pStUpdated,
3,152✔
2743
                                   SSHashObj* pStDeleted, bool hasEndTs, bool addGap) {
2744
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
3,152✔
2745
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
3,152✔
2746
  int32_t                        numOfOutput = pOperator->exprSupp.numOfExprs;
3,152✔
2747
  uint64_t                       groupId = pSDataBlock->info.id.groupId;
3,152✔
2748
  int32_t                        code = TSDB_CODE_SUCCESS;
3,152✔
2749
  int32_t                        lino = 0;
3,152✔
2750
  SResultRow*                    pResult = NULL;
3,152✔
2751
  int32_t                        rows = pSDataBlock->info.rows;
3,152✔
2752
  int32_t                        winRows = 0;
3,152✔
2753
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
3,152✔
2754

2755
  pInfo->dataVersion = TMAX(pInfo->dataVersion, pSDataBlock->info.version);
3,152✔
2756
  pAggSup->winRange = pTaskInfo->streamInfo.fillHistoryWindow;
3,152✔
2757
  if (pAggSup->winRange.ekey <= 0) {
3,152!
UNCOV
2758
    pAggSup->winRange.ekey = INT64_MAX;
×
2759
  }
2760

2761
  SColumnInfoData* pStartTsCol = taosArrayGet(pSDataBlock->pDataBlock, pInfo->primaryTsIndex);
3,152✔
2762
  TSKEY*           startTsCols = (int64_t*)pStartTsCol->pData;
3,153✔
2763
  SColumnInfoData* pEndTsCol = NULL;
3,153✔
2764
  if (hasEndTs) {
3,153✔
2765
    pEndTsCol = taosArrayGet(pSDataBlock->pDataBlock, pInfo->endTsIndex);
476✔
2766
  } else {
2767
    pEndTsCol = taosArrayGet(pSDataBlock->pDataBlock, pInfo->primaryTsIndex);
2,677✔
2768
  }
2769

2770
  TSKEY* endTsCols = (int64_t*)pEndTsCol->pData;
3,151✔
2771

2772
  void*            pPkVal = NULL;
3,151✔
2773
  int32_t          pkLen = 0;
3,151✔
2774
  SColumnInfoData* pPkColDataInfo = NULL;
3,151✔
2775
  if (hasSrcPrimaryKeyCol(&pInfo->basic)) {
3,151✔
2776
    pPkColDataInfo = taosArrayGet(pSDataBlock->pDataBlock, pInfo->basic.primaryPkIndex);
14✔
2777
  }
2778

2779
  for (int32_t i = 0; i < rows;) {
6,402✔
2780
    if (hasSrcPrimaryKeyCol(&pInfo->basic) && !IS_FINAL_SESSION_OP(pOperator) && pInfo->ignoreExpiredData) {
3,256!
UNCOV
2781
      pPkVal = colDataGetData(pPkColDataInfo, i);
×
UNCOV
2782
      pkLen = colDataGetRowLength(pPkColDataInfo, i);
×
2783
    }
2784
    if (!IS_FINAL_SESSION_OP(pOperator) && pInfo->ignoreExpiredData &&
3,448✔
2785
        checkExpiredData(&pInfo->streamAggSup.stateStore, pInfo->streamAggSup.pUpdateInfo, &pInfo->twAggSup,
193✔
2786
                         pSDataBlock->info.id.uid, endTsCols[i], pPkVal, pkLen)) {
193✔
2787
      i++;
21✔
2788
      continue;
21✔
2789
    }
2790
    SResultWindowInfo winInfo = {0};
3,234✔
2791
    int32_t           winCode = TSDB_CODE_SUCCESS;
3,234✔
2792
    code = setSessionOutputBuf(pAggSup, startTsCols[i], endTsCols[i], groupId, &winInfo, &winCode);
3,234✔
2793
    QUERY_CHECK_CODE(code, lino, _end);
3,235!
2794

2795
    if (winCode != TSDB_CODE_SUCCESS && IS_NORMAL_SESSION_OP(pOperator) &&
3,233✔
2796
        BIT_FLAG_TEST_MASK(pTaskInfo->streamInfo.eventTypes, SNOTIFY_EVENT_WINDOW_OPEN)) {
2,043!
UNCOV
2797
      code = addSessionAggNotifyEvent(SNOTIFY_EVENT_WINDOW_OPEN, &winInfo.sessionWin, &pInfo->basic.notifyEventSup,
×
2798
                                      pTaskInfo->streamInfo.pNotifyEventStat);
UNCOV
2799
      QUERY_CHECK_CODE(code, lino, _end);
×
2800
    }
2801

2802
    // coverity scan error
2803
    if (!winInfo.pStatePos) {
3,233!
UNCOV
2804
      continue;
×
2805
    }
2806
    setSessionWinOutputInfo(pStUpdated, &winInfo);
3,233✔
2807
    code = updateSessionWindowInfo(pAggSup, &winInfo, startTsCols, endTsCols, groupId, rows, i, pAggSup->gap,
3,233✔
2808
                                   pAggSup->pResultRows, pStUpdated, pStDeleted, &winRows);
2809
    QUERY_CHECK_CODE(code, lino, _end);
3,231!
2810

2811
    int64_t winDelta = 0;
3,231✔
2812
    if (addGap) {
3,231✔
2813
      winDelta = pAggSup->gap;
2,587✔
2814
    }
2815
    code = doOneWindowAggImpl(&pInfo->twAggSup.timeWindowData, &winInfo, &pResult, i, winRows, rows, numOfOutput,
3,231✔
2816
                              pOperator, winDelta);
2817
    QUERY_CHECK_CODE(code, lino, _end);
3,233!
2818

2819
    code = compactSessionWindow(pOperator, &winInfo, pStUpdated, pStDeleted, addGap, NULL, NULL);
3,233✔
2820
    QUERY_CHECK_CODE(code, lino, _end);
3,224✔
2821

2822
    code = saveSessionOutputBuf(pAggSup, &winInfo);
3,222✔
2823
    QUERY_CHECK_CODE(code, lino, _end);
3,213!
2824

2825
    if (pInfo->destHasPrimaryKey && winInfo.isOutput && IS_NORMAL_SESSION_OP(pOperator)) {
3,213!
UNCOV
2826
      code = saveDeleteRes(pInfo->pPkDeleted, winInfo.sessionWin);
×
2827
      QUERY_CHECK_CODE(code, lino, _end);
6!
2828
    }
2829
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_AT_ONCE && pStUpdated) {
3,221✔
2830
      code = saveResult(winInfo, pStUpdated);
2,322✔
2831
      QUERY_CHECK_CODE(code, lino, _end);
2,330!
2832
    }
2833
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_WINDOW_CLOSE) {
3,229✔
2834
      winInfo.pStatePos->beUpdated = true;
619✔
2835
      SSessionKey key = {0};
619✔
2836
      getSessionHashKey(&winInfo.sessionWin, &key);
619✔
2837
      code = tSimpleHashPut(pAggSup->pResultRows, &key, sizeof(SSessionKey), &winInfo, sizeof(SResultWindowInfo));
619✔
2838
      QUERY_CHECK_CODE(code, lino, _end);
620!
2839
    }
2840

2841
    i += winRows;
3,230✔
2842
  }
2843

2844
_end:
3,146✔
2845
  if (code != TSDB_CODE_SUCCESS) {
3,148✔
2846
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
2!
2847
  }
2848
}
3,148✔
2849

2850
int32_t doDeleteTimeWindows(SStreamAggSupporter* pAggSup, SSDataBlock* pBlock, SArray* result) {
1,177✔
2851
  int32_t          code = TSDB_CODE_SUCCESS;
1,177✔
2852
  int32_t          lino = 0;
1,177✔
2853
  SColumnInfoData* pStartTsCol = taosArrayGet(pBlock->pDataBlock, START_TS_COLUMN_INDEX);
1,177✔
2854
  TSKEY*           startDatas = (TSKEY*)pStartTsCol->pData;
1,177✔
2855
  SColumnInfoData* pEndTsCol = taosArrayGet(pBlock->pDataBlock, END_TS_COLUMN_INDEX);
1,177✔
2856
  TSKEY*           endDatas = (TSKEY*)pEndTsCol->pData;
1,176✔
2857
  SColumnInfoData* pGroupCol = taosArrayGet(pBlock->pDataBlock, GROUPID_COLUMN_INDEX);
1,176✔
2858
  uint64_t*        gpDatas = (uint64_t*)pGroupCol->pData;
1,176✔
2859
  for (int32_t i = 0; i < pBlock->info.rows; i++) {
2,416✔
2860
    while (1) {
1,257✔
2861
      SSessionKey curWin = {0};
2,495✔
2862
      getCurSessionWindow(pAggSup, startDatas[i], endDatas[i], gpDatas[i], &curWin);
2,495✔
2863
      if (IS_INVALID_SESSION_WIN_KEY(curWin)) {
2,500✔
2864
        break;
1,240✔
2865
      }
2866
      doDeleteSessionWindow(pAggSup, &curWin);
1,260✔
2867
      if (result) {
1,260✔
2868
        code = saveDeleteInfo(result, curWin);
1,216✔
2869
        QUERY_CHECK_CODE(code, lino, _end);
1,213!
2870
      }
2871
    }
2872
  }
2873

2874
_end:
1,178✔
2875
  if (code != TSDB_CODE_SUCCESS) {
1,178!
UNCOV
2876
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
2877
  }
2878
  return code;
1,178✔
2879
}
2880

2881
inline int32_t sessionKeyCompareAsc(const void* pKey1, const void* pKey2) {
6,703✔
2882
  SResultWindowInfo* pWinInfo1 = (SResultWindowInfo*)pKey1;
6,703✔
2883
  SResultWindowInfo* pWinInfo2 = (SResultWindowInfo*)pKey2;
6,703✔
2884
  SSessionKey*       pWin1 = &pWinInfo1->sessionWin;
6,703✔
2885
  SSessionKey*       pWin2 = &pWinInfo2->sessionWin;
6,703✔
2886

2887
  if (pWin1->groupId > pWin2->groupId) {
6,703✔
2888
    return 1;
2,175✔
2889
  } else if (pWin1->groupId < pWin2->groupId) {
4,528✔
2890
    return -1;
1,960✔
2891
  }
2892

2893
  if (pWin1->win.skey > pWin2->win.skey) {
2,568✔
2894
    return 1;
1,413✔
2895
  } else if (pWin1->win.skey < pWin2->win.skey) {
1,155!
2896
    return -1;
1,155✔
2897
  }
2898

UNCOV
2899
  return 0;
×
2900
}
2901

2902
static int32_t appendToDeleteDataBlock(SOperatorInfo* pOp, SSDataBlock *pBlock, SSessionKey *pKey) {
697✔
2903
  int32_t        code = TSDB_CODE_SUCCESS;
697✔
2904
  int32_t        lino = 0;
697✔
2905
  SExecTaskInfo* pTaskInfo = pOp->pTaskInfo;
697✔
2906

2907
  QUERY_CHECK_NULL(pBlock, code, lino, _end, TSDB_CODE_INVALID_PARA);
697!
2908
  QUERY_CHECK_NULL(pKey, code, lino, _end, TSDB_CODE_INVALID_PARA);
697!
2909

2910
  SColumnInfoData* pStartTsCol = taosArrayGet(pBlock->pDataBlock, START_TS_COLUMN_INDEX);
697✔
2911
  code = colDataSetVal(pStartTsCol, pBlock->info.rows, (const char*)&pKey->win.skey, false);
697✔
2912
  QUERY_CHECK_CODE(code, lino, _end);
697!
2913

2914
  SColumnInfoData* pEndTsCol = taosArrayGet(pBlock->pDataBlock, END_TS_COLUMN_INDEX);
697✔
2915
  code = colDataSetVal(pEndTsCol, pBlock->info.rows, (const char*)&pKey->win.skey, false);
697✔
2916
  QUERY_CHECK_CODE(code, lino, _end);
697!
2917

2918
  SColumnInfoData* pUidCol = taosArrayGet(pBlock->pDataBlock, UID_COLUMN_INDEX);
697✔
2919
  colDataSetNULL(pUidCol, pBlock->info.rows);
697!
2920

2921
  SColumnInfoData* pGpCol = taosArrayGet(pBlock->pDataBlock, GROUPID_COLUMN_INDEX);
697✔
2922
  code = colDataSetVal(pGpCol, pBlock->info.rows, (const char*)&pKey->groupId, false);
697✔
2923
  QUERY_CHECK_CODE(code, lino, _end);
697!
2924

2925
  SColumnInfoData* pCalStCol = taosArrayGet(pBlock->pDataBlock, CALCULATE_START_TS_COLUMN_INDEX);
697✔
2926
  colDataSetNULL(pCalStCol, pBlock->info.rows);
697!
2927

2928
  SColumnInfoData* pCalEdCol = taosArrayGet(pBlock->pDataBlock, CALCULATE_END_TS_COLUMN_INDEX);
697✔
2929
  colDataSetNULL(pCalEdCol, pBlock->info.rows);
697!
2930

2931
  SColumnInfoData* pTableCol = taosArrayGet(pBlock->pDataBlock, TABLE_NAME_COLUMN_INDEX);
697✔
2932
  if (!pTableCol) {
697!
UNCOV
2933
    QUERY_CHECK_CODE(code, lino, _end);
×
2934
  }
2935

2936
  void*        tbname = NULL;
697✔
2937
  int32_t      winCode = TSDB_CODE_SUCCESS;
697✔
2938
  SStorageAPI* pAPI = &pOp->pTaskInfo->storageAPI;
697✔
2939
  code =
2940
      pAPI->stateStore.streamStateGetParName(pOp->pTaskInfo->streamInfo.pState, pKey->groupId, &tbname, false, &winCode);
697✔
2941
  QUERY_CHECK_CODE(code, lino, _end);
697!
2942

2943
  if (winCode != TSDB_CODE_SUCCESS) {
697✔
2944
    colDataSetNULL(pTableCol, pBlock->info.rows);
239!
2945
  } else {
2946
    char parTbName[VARSTR_HEADER_SIZE + TSDB_TABLE_NAME_LEN];
2947
    STR_WITH_MAXSIZE_TO_VARSTR(parTbName, tbname, sizeof(parTbName));
458✔
2948
    code = colDataSetVal(pTableCol, pBlock->info.rows, (const char*)parTbName, false);
458✔
2949
    QUERY_CHECK_CODE(code, lino, _end);
458!
2950
    pAPI->stateStore.streamStateFreeVal(tbname);
458✔
2951
  }
2952
  pBlock->info.rows += 1;
697✔
2953

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

2961
void doBuildDeleteDataBlock(SOperatorInfo* pOp, SSHashObj* pStDeleted, SSDataBlock* pBlock, void** Ite,
17,751✔
2962
                            SGroupResInfo* pGroupResInfo) {
2963
  int32_t        code = TSDB_CODE_SUCCESS;
17,751✔
2964
  int32_t        lino = 0;
17,751✔
2965
  SExecTaskInfo* pTaskInfo = pOp->pTaskInfo;
17,751✔
2966
  int64_t        minWindowSize = getMinWindowSize(pOp);
17,751✔
2967
  int32_t        numOfRows = getNumOfTotalRes(pGroupResInfo);
17,740✔
2968

2969
  blockDataCleanup(pBlock);
17,746✔
2970
  int32_t size = tSimpleHashGetSize(pStDeleted);
17,725✔
2971
  if (minWindowSize > 0) {
17,724✔
2972
    // Add the number of windows that are below the minimum width limit.
2973
    for (int32_t i = pGroupResInfo->delIndex; i < numOfRows; ++i) {
248✔
2974
      SResultWindowInfo* pWinInfo = taosArrayGet(pGroupResInfo->pRows, i);
120✔
2975
      SRowBuffPos*       pPos = pWinInfo->pStatePos;
120✔
2976
      SSessionKey*       pKey = (SSessionKey*)pPos->pKey;
120✔
2977
      if (pKey->win.ekey - pKey->win.skey < minWindowSize) {
120✔
2978
        size++;
60✔
2979
      }
2980
    }
2981
  }
2982
  if (size == 0) {
17,724✔
2983
    return;
17,174✔
2984
  }
2985
  code = blockDataEnsureCapacity(pBlock, size);
550✔
2986
  QUERY_CHECK_CODE(code, lino, _end);
550!
2987

2988
  int32_t iter = 0;
550✔
2989
  while (((*Ite) = tSimpleHashIterate(pStDeleted, *Ite, &iter)) != NULL) {
1,187✔
2990
    if (pBlock->info.rows + 1 > pBlock->info.capacity) {
637!
UNCOV
2991
      break;
×
2992
    }
2993
    SSessionKey*     res = tSimpleHashGetKey(*Ite, NULL);
637!
2994
    code = appendToDeleteDataBlock(pOp, pBlock, res);
637✔
2995
    QUERY_CHECK_CODE(code, lino, _end);
637!
2996
  }
2997

2998
  if (minWindowSize > 0) {
550✔
2999
    for (int32_t i = pGroupResInfo->delIndex; i < numOfRows; ++i) {
138✔
3000
      SResultWindowInfo* pWinInfo = taosArrayGet(pGroupResInfo->pRows, i);
120✔
3001
      SRowBuffPos*       pPos = pWinInfo->pStatePos;
120✔
3002
      SSessionKey*       pKey = (SSessionKey*)pPos->pKey;
120✔
3003
      if (pKey->win.ekey - pKey->win.skey < minWindowSize) {
120✔
3004
        code = appendToDeleteDataBlock(pOp, pBlock, pKey);
60✔
3005
        QUERY_CHECK_CODE(code, lino, _end);
60!
3006
      }
3007
    }
3008
    pGroupResInfo->delIndex = numOfRows;
18✔
3009
  }
3010

3011
_end:
532✔
3012
  if ((*Ite) == NULL) {
550!
3013
    tSimpleHashClear(pStDeleted);
550✔
3014
  }
3015

3016
  if (code != TSDB_CODE_SUCCESS) {
550!
UNCOV
3017
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
3018
  }
3019
}
3020

3021
static int32_t rebuildSessionWindow(SOperatorInfo* pOperator, SArray* pWinArray, SSHashObj* pStUpdated) {
56✔
3022
  int32_t        winCode = TSDB_CODE_SUCCESS;
56✔
3023
  int32_t        code = TSDB_CODE_SUCCESS;
56✔
3024
  int32_t        lino = 0;
56✔
3025
  SExprSupp*     pSup = &pOperator->exprSupp;
56✔
3026
  SExecTaskInfo* pTaskInfo = pOperator->pTaskInfo;
56✔
3027
  SStorageAPI*   pAPI = &pOperator->pTaskInfo->storageAPI;
56✔
3028

3029
  int32_t                        size = taosArrayGetSize(pWinArray);
56✔
3030
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
56✔
3031
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
56✔
3032
  int32_t                        numOfOutput = pSup->numOfExprs;
56✔
3033
  int32_t                        numOfChild = taosArrayGetSize(pInfo->pChildren);
56✔
3034

3035
  for (int32_t i = 0; i < size; i++) {
110✔
3036
    SSessionKey*      pWinKey = taosArrayGet(pWinArray, i);
54✔
3037
    int32_t           num = 0;
54✔
3038
    SResultWindowInfo parentWin = {0};
54✔
3039
    for (int32_t j = 0; j < numOfChild; j++) {
244✔
3040
      SOperatorInfo*                 pChild = taosArrayGetP(pInfo->pChildren, j);
190✔
3041
      SStreamSessionAggOperatorInfo* pChInfo = pChild->info;
190✔
3042
      SStreamAggSupporter*           pChAggSup = &pChInfo->streamAggSup;
190✔
3043
      SSessionKey                    chWinKey = {0};
190✔
3044
      getSessionHashKey(pWinKey, &chWinKey);
190✔
3045
      SStreamStateCur* pCur = pAggSup->stateStore.streamStateSessionSeekKeyCurrentNext(pChAggSup->pState, &chWinKey);
190✔
3046
      SResultRow*      pResult = NULL;
190✔
3047
      SResultRow*      pChResult = NULL;
190✔
3048
      while (1) {
20✔
3049
        SResultWindowInfo childWin = {0};
210✔
3050
        childWin.sessionWin = *pWinKey;
210✔
3051
        getSessionWinBuf(pChAggSup, pCur, &childWin, &winCode);
210✔
3052

3053
        if (winCode == TSDB_CODE_SUCCESS && !inWinRange(&pAggSup->winRange, &childWin.sessionWin.win)) {
210!
UNCOV
3054
          releaseOutputBuf(pAggSup->pState, childWin.pStatePos, &pAggSup->stateStore);
×
UNCOV
3055
          continue;
×
3056
        }
3057

3058
        if (winCode == TSDB_CODE_SUCCESS && inWinRange(&pWinKey->win, &childWin.sessionWin.win)) {
210✔
3059
          if (num == 0) {
20!
3060
            code = setSessionOutputBuf(pAggSup, pWinKey->win.skey, pWinKey->win.ekey, pWinKey->groupId, &parentWin,
20✔
3061
                                       &winCode);
3062
            QUERY_CHECK_CODE(code, lino, _end);
20!
3063

3064
            parentWin.sessionWin = childWin.sessionWin;
20✔
3065
            memcpy(parentWin.pStatePos->pKey, &parentWin.sessionWin, sizeof(SSessionKey));
20✔
3066
            code = initSessionOutputBuf(&parentWin, &pResult, pSup->pCtx, numOfOutput, pSup->rowEntryInfoOffset);
20✔
3067
            QUERY_CHECK_CODE(code, lino, _end);
20!
3068
          }
3069
          num++;
20✔
3070
          parentWin.sessionWin.win.skey = TMIN(parentWin.sessionWin.win.skey, childWin.sessionWin.win.skey);
20✔
3071
          parentWin.sessionWin.win.ekey = TMAX(parentWin.sessionWin.win.ekey, childWin.sessionWin.win.ekey);
20✔
3072
          memcpy(parentWin.pStatePos->pKey, &parentWin.sessionWin, sizeof(SSessionKey));
20✔
3073

3074
          updateTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &parentWin.sessionWin.win, pAggSup->gap);
20✔
3075
          code = initSessionOutputBuf(&childWin, &pChResult, pChild->exprSupp.pCtx, numOfOutput,
20✔
3076
                                      pChild->exprSupp.rowEntryInfoOffset);
3077
          QUERY_CHECK_CODE(code, lino, _end);
20!
3078

3079
          code = compactFunctions(pSup->pCtx, pChild->exprSupp.pCtx, numOfOutput, pTaskInfo,
20✔
3080
                                  &pInfo->twAggSup.timeWindowData);
3081
          QUERY_CHECK_CODE(code, lino, _end);
20!
3082

3083
          code = compactSessionWindow(pOperator, &parentWin, pStUpdated, NULL, true, NULL, NULL);
20✔
3084
          QUERY_CHECK_CODE(code, lino, _end);
20!
3085

3086
          releaseOutputBuf(pAggSup->pState, childWin.pStatePos, &pAggSup->stateStore);
20✔
3087
        } else {
3088
          releaseOutputBuf(pAggSup->pState, childWin.pStatePos, &pAggSup->stateStore);
190✔
3089
          break;
190✔
3090
        }
3091
      }
3092
      pAPI->stateStore.streamStateFreeCur(pCur);
190✔
3093
    }
3094
    if (num > 0) {
54✔
3095
      code = saveResult(parentWin, pStUpdated);
20✔
3096
      QUERY_CHECK_CODE(code, lino, _end);
20!
3097

3098
      code = saveSessionOutputBuf(pAggSup, &parentWin);
20✔
3099
      QUERY_CHECK_CODE(code, lino, _end);
20!
3100
    }
3101
  }
3102

3103
_end:
56✔
3104
  if (code != TSDB_CODE_SUCCESS) {
56!
UNCOV
3105
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
3106
  }
3107
  return code;
56✔
3108
}
3109

3110
int32_t closeSessionWindow(SSHashObj* pHashMap, STimeWindowAggSupp* pTwSup, SSHashObj* pClosed) {
10,950✔
3111
  int32_t code = TSDB_CODE_SUCCESS;
10,950✔
3112
  int32_t lino = 0;
10,950✔
3113
  void*   pIte = NULL;
10,950✔
3114
  int32_t iter = 0;
10,950✔
3115
  while ((pIte = tSimpleHashIterate(pHashMap, pIte, &iter)) != NULL) {
12,814✔
3116
    SResultWindowInfo* pWinInfo = pIte;
1,864✔
3117
    if (isCloseWindow(&pWinInfo->sessionWin.win, pTwSup)) {
1,864✔
3118
      if (pTwSup->calTrigger == STREAM_TRIGGER_WINDOW_CLOSE && pClosed) {
607!
3119
        code = saveResult(*pWinInfo, pClosed);
607✔
3120
        QUERY_CHECK_CODE(code, lino, _end);
607!
3121
      }
3122
      SSessionKey* pKey = tSimpleHashGetKey(pIte, NULL);
607!
3123
      code = tSimpleHashIterateRemove(pHashMap, pKey, sizeof(SSessionKey), &pIte, &iter);
607✔
3124
      QUERY_CHECK_CODE(code, lino, _end);
607!
3125
    }
3126
  }
3127
_end:
10,955✔
3128
  if (code != TSDB_CODE_SUCCESS) {
10,955!
UNCOV
3129
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
3130
  }
3131
  return code;
10,955✔
3132
}
3133

3134
static int32_t closeChildSessionWindow(SArray* pChildren, TSKEY maxTs) {
3,750✔
3135
  int32_t code = TSDB_CODE_SUCCESS;
3,750✔
3136
  int32_t lino = 0;
3,750✔
3137

3138
  int32_t size = taosArrayGetSize(pChildren);
3,750✔
3139
  for (int32_t i = 0; i < size; i++) {
4,311✔
3140
    SOperatorInfo*                 pChildOp = taosArrayGetP(pChildren, i);
563✔
3141
    SStreamSessionAggOperatorInfo* pChInfo = pChildOp->info;
563✔
3142
    pChInfo->twAggSup.maxTs = TMAX(pChInfo->twAggSup.maxTs, maxTs);
563✔
3143
    code = closeSessionWindow(pChInfo->streamAggSup.pResultRows, &pChInfo->twAggSup, NULL);
563✔
3144
    QUERY_CHECK_CODE(code, lino, _end);
563!
3145
  }
3146
_end:
3,748✔
3147
  if (code != TSDB_CODE_SUCCESS) {
3,748!
UNCOV
3148
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
3149
  }
3150
  return code;
3,741✔
3151
}
3152

3153
int32_t getAllSessionWindow(SSHashObj* pHashMap, SSHashObj* pStUpdated) {
268✔
3154
  int32_t code = TSDB_CODE_SUCCESS;
268✔
3155
  int32_t lino = 0;
268✔
3156
  void*   pIte = NULL;
268✔
3157
  int32_t iter = 0;
268✔
3158
  while ((pIte = tSimpleHashIterate(pHashMap, pIte, &iter)) != NULL) {
381✔
3159
    SResultWindowInfo* pWinInfo = pIte;
113✔
3160
    if (!pWinInfo->pStatePos->beUpdated) {
113✔
3161
      continue;
5✔
3162
    }
3163
    pWinInfo->pStatePos->beUpdated = false;
108✔
3164
    code = saveResult(*pWinInfo, pStUpdated);
108✔
3165
    QUERY_CHECK_CODE(code, lino, _end);
108!
3166
  }
3167

3168
_end:
268✔
3169
  if (code != TSDB_CODE_SUCCESS) {
268!
UNCOV
3170
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
3171
  }
3172
  return code;
268✔
3173
}
3174

3175
int32_t copyDeleteWindowInfo(SArray* pResWins, SSHashObj* pStDeleted) {
1,133✔
3176
  int32_t code = TSDB_CODE_SUCCESS;
1,133✔
3177
  int32_t lino = 0;
1,133✔
3178
  int32_t size = taosArrayGetSize(pResWins);
1,133✔
3179
  for (int32_t i = 0; i < size; i++) {
2,378✔
3180
    SSessionKey* pWinKey = taosArrayGet(pResWins, i);
1,243✔
3181
    if (!pWinKey) continue;
1,244!
3182
    SSessionKey winInfo = {0};
1,244✔
3183
    getSessionHashKey(pWinKey, &winInfo);
1,244✔
3184
    code = tSimpleHashPut(pStDeleted, &winInfo, sizeof(SSessionKey), NULL, 0);
1,243✔
3185
    QUERY_CHECK_CODE(code, lino, _end);
1,245!
3186
  }
3187

3188
_end:
1,135✔
3189
  if (code != TSDB_CODE_SUCCESS) {
1,135!
UNCOV
3190
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
3191
  }
3192
  return code;
1,135✔
3193
}
3194

3195
// the allocated memory comes from outer function.
3196
void initGroupResInfoFromArrayList(SGroupResInfo* pGroupResInfo, SArray* pArrayList) {
10,889✔
3197
  pGroupResInfo->pRows = pArrayList;
10,889✔
3198
  pGroupResInfo->index = 0;
10,889✔
3199
  pGroupResInfo->pBuf = NULL;
10,889✔
3200
  pGroupResInfo->freeItem = false;
10,889✔
3201
  pGroupResInfo->delIndex = 0;
10,889✔
3202
}
10,889✔
3203

3204
int32_t buildSessionResultDataBlock(SOperatorInfo* pOperator, void* pState, SSDataBlock* pBlock, SExprSupp* pSup,
5,642✔
3205
                                    SGroupResInfo* pGroupResInfo, SArray* pSessionKeys) {
3206
  int32_t         code = TSDB_CODE_SUCCESS;
5,642✔
3207
  int32_t         lino = 0;
5,642✔
3208
  SExecTaskInfo*  pTaskInfo = pOperator->pTaskInfo;
5,642✔
3209
  SStorageAPI*    pAPI = &pTaskInfo->storageAPI;
5,642✔
3210
  SExprInfo*      pExprInfo = pSup->pExprInfo;
5,642✔
3211
  int32_t         numOfExprs = pSup->numOfExprs;
5,642✔
3212
  int32_t*        rowEntryOffset = pSup->rowEntryInfoOffset;
5,642✔
3213
  SqlFunctionCtx* pCtx = pSup->pCtx;
5,642✔
3214
  int64_t         minWindowSize = getMinWindowSize(pOperator);
5,642✔
3215

3216
  int32_t numOfRows = getNumOfTotalRes(pGroupResInfo);
5,643✔
3217

3218
  for (int32_t i = pGroupResInfo->index; i < numOfRows; i += 1) {
12,571✔
3219
    SResultWindowInfo* pWinInfo = taosArrayGet(pGroupResInfo->pRows, i);
8,730✔
3220
    SRowBuffPos*       pPos = pWinInfo->pStatePos;
8,730✔
3221
    SResultRow*        pRow = NULL;
8,730✔
3222
    SSessionKey*       pKey = (SSessionKey*)pPos->pKey;
8,730✔
3223

3224
    if (pBlock->info.id.groupId == 0) {
8,730✔
3225
      pBlock->info.id.groupId = pKey->groupId;
6,231✔
3226

3227
      void*   tbname = NULL;
6,231✔
3228
      int32_t winCode = TSDB_CODE_SUCCESS;
6,231✔
3229
      code = pAPI->stateStore.streamStateGetParName((void*)pTaskInfo->streamInfo.pState, pBlock->info.id.groupId,
6,231✔
3230
                                                    &tbname, false, &winCode);
3231
      QUERY_CHECK_CODE(code, lino, _end);
6,230!
3232

3233
      if (winCode != TSDB_CODE_SUCCESS) {
6,230✔
3234
        pBlock->info.parTbName[0] = 0;
1,780✔
3235
      } else {
3236
        memcpy(pBlock->info.parTbName, tbname, TSDB_TABLE_NAME_LEN);
4,450✔
3237
      }
3238
      pAPI->stateStore.streamStateFreeVal(tbname);
6,230✔
3239
    } else {
3240
      // current value belongs to different group, it can't be packed into one datablock
3241
      if (pBlock->info.id.groupId != pKey->groupId) {
2,499✔
3242
        break;
1,785✔
3243
      }
3244
    }
3245

3246
    code = pAPI->stateStore.streamStateGetByPos(pState, pPos, (void**)&pRow);
6,945✔
3247
    QUERY_CHECK_CODE(code, lino, _end);
6,945!
3248

3249
    doUpdateNumOfRows(pCtx, pRow, numOfExprs, rowEntryOffset);
6,945✔
3250
    // no results, continue to check the next one
3251
    if (pRow->numOfRows == 0) {
6,944!
UNCOV
3252
      pGroupResInfo->index += 1;
×
3253
      continue;
60✔
3254
    }
3255
    // skip the window which is less than the windowMinSize
3256
    if (pKey->win.ekey - pKey->win.skey < minWindowSize) {
6,944✔
3257
      qDebug("skip small window, groupId: %" PRId64 ", windowSize: %" PRId64 ", minWindowSize: %" PRId64, pKey->groupId,
60!
3258
             pKey->win.ekey - pKey->win.skey, minWindowSize);
3259
      pGroupResInfo->index += 1;
60✔
3260
      continue;
60✔
3261
    }
3262

3263
    if (pBlock->info.rows + pRow->numOfRows > pBlock->info.capacity) {
6,884!
UNCOV
3264
      break;
×
3265
    }
3266

3267
    pGroupResInfo->index += 1;
6,884✔
3268

3269
    for (int32_t j = 0; j < numOfExprs; ++j) {
114,411✔
3270
      int32_t slotId = pExprInfo[j].base.resSchema.slotId;
107,543✔
3271

3272
      pCtx[j].resultInfo = getResultEntryInfo(pRow, j, rowEntryOffset);
107,543✔
3273
      if (pCtx[j].fpSet.finalize) {
107,537✔
3274
        int32_t tmpRes = pCtx[j].fpSet.finalize(&pCtx[j], pBlock);
98,220✔
3275
        if (TAOS_FAILED(tmpRes)) {
98,218!
UNCOV
3276
          qError("%s build result data block error, code %s", GET_TASKID(pTaskInfo), tstrerror(tmpRes));
×
UNCOV
3277
          QUERY_CHECK_CODE(code, lino, _end);
×
3278
        }
3279
      } else if (strcmp(pCtx[j].pExpr->pExpr->_function.functionName, "_select_value") == 0) {
9,317✔
3280
        // do nothing, todo refactor
3281
      } else {
3282
        // expand the result into multiple rows. E.g., _wstart, top(k, 20)
3283
        // the _wstart needs to copy to 20 following rows, since the results of top-k expands to 20 different rows.
3284
        SColumnInfoData* pColInfoData = taosArrayGet(pBlock->pDataBlock, slotId);
9,252✔
3285
        char*            in = GET_ROWCELL_INTERBUF(pCtx[j].resultInfo);
9,252✔
3286
        for (int32_t k = 0; k < pRow->numOfRows; ++k) {
18,502✔
3287
          code = colDataSetVal(pColInfoData, pBlock->info.rows + k, in, pCtx[j].resultInfo->isNullRes);
9,252✔
3288
          QUERY_CHECK_CODE(code, lino, _end);
9,250!
3289
        }
3290
      }
3291
    }
3292

3293
    if (pSessionKeys) {
6,868!
UNCOV
3294
      for (int32_t j = 0; j < pRow->numOfRows; ++j) {
×
UNCOV
3295
        const void* px = taosArrayPush(pSessionKeys, pKey);
×
UNCOV
3296
        QUERY_CHECK_NULL(px, code, lino, _end, terrno);
×
3297
      }
3298
    }
3299

3300
    pBlock->info.dataLoad = 1;
6,868✔
3301
    pBlock->info.rows += pRow->numOfRows;
6,868✔
3302
  }
3303
  code = blockDataUpdateTsWindow(pBlock, 0);
5,626✔
3304
  QUERY_CHECK_CODE(code, lino, _end);
5,643!
3305

3306
_end:
5,643✔
3307
  if (code != TSDB_CODE_SUCCESS) {
5,643!
UNCOV
3308
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
3309
  }
3310
  return code;
5,643✔
3311
}
3312

3313
void doBuildSessionResult(SOperatorInfo* pOperator, void* pState, SGroupResInfo* pGroupResInfo, SSDataBlock* pBlock,
17,176✔
3314
                          SArray* pSessionKeys) {
3315
  int32_t        code = TSDB_CODE_SUCCESS;
17,176✔
3316
  int32_t        lino = 0;
17,176✔
3317
  SExecTaskInfo* pTaskInfo = pOperator->pTaskInfo;
17,176✔
3318
  // set output datablock version
3319
  pBlock->info.version = pTaskInfo->version;
17,176✔
3320

3321
  blockDataCleanup(pBlock);
17,176✔
3322
  taosArrayClear(pSessionKeys);
17,198✔
3323
  if (!hasRemainResults(pGroupResInfo)) {
17,198✔
3324
    cleanupGroupResInfo(pGroupResInfo);
11,561✔
3325
    goto _end;
11,569✔
3326
  }
3327

3328
  // clear the existed group id
3329
  pBlock->info.id.groupId = 0;
5,642✔
3330
  code = buildSessionResultDataBlock(pOperator, pState, pBlock, &pOperator->exprSupp, pGroupResInfo, pSessionKeys);
5,642✔
3331
  QUERY_CHECK_CODE(code, lino, _end);
5,643!
3332

3333
  if (pBlock->info.rows == 0) {
5,643!
UNCOV
3334
    cleanupGroupResInfo(pGroupResInfo);
×
3335
  }
3336

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

3343
static int32_t buildSessionResult(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
7,067✔
3344
  int32_t                        code = TSDB_CODE_SUCCESS;
7,067✔
3345
  int32_t                        lino = 0;
7,067✔
3346
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
7,067✔
3347
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
7,067✔
3348
  SOptrBasicInfo*                pBInfo = &pInfo->binfo;
7,067✔
3349
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
7,067✔
3350
  SStreamNotifyEventSupp*        pNotifySup = &pInfo->basic.notifyEventSup;
7,067✔
3351
  STaskNotifyEventStat*          pNotifyEventStat = pTaskInfo->streamInfo.pNotifyEventStat;
7,067✔
3352
  bool                           addNotifyEvent = false;
7,067✔
3353
  addNotifyEvent = IS_NORMAL_SESSION_OP(pOperator) &&
12,673✔
3354
                   BIT_FLAG_TEST_MASK(pTaskInfo->streamInfo.eventTypes, SNOTIFY_EVENT_WINDOW_CLOSE);
5,606!
3355
  doBuildDeleteDataBlock(pOperator, pInfo->pStDeleted, pInfo->pDelRes, &pInfo->pDelIterator, &pInfo->groupResInfo);
7,067✔
3356
  if (pInfo->pDelRes->info.rows > 0) {
7,051✔
3357
    printDataBlock(pInfo->pDelRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
258✔
3358
    if (addNotifyEvent) {
260!
UNCOV
3359
      code = addAggDeleteNotifyEvent(pInfo->pDelRes, pNotifySup, pNotifyEventStat);
×
UNCOV
3360
      QUERY_CHECK_CODE(code, lino, _end);
×
3361
    }
3362
    (*ppRes) = pInfo->pDelRes;
260✔
3363
    return code;
260✔
3364
  }
3365

3366
  doBuildSessionResult(pOperator, pAggSup->pState, &pInfo->groupResInfo, pBInfo->pRes,
6,793!
3367
                       addNotifyEvent ? pNotifySup->pSessionKeys : NULL);
3368
  if (pBInfo->pRes->info.rows > 0) {
6,816✔
3369
    printDataBlock(pBInfo->pRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
1,899✔
3370
    if (addNotifyEvent) {
1,899!
3371
      // Adjust the window end time based on the Session Window gap
UNCOV
3372
      for (int32_t i = 0; i < taosArrayGetSize(pNotifySup->pSessionKeys); ++i) {
×
UNCOV
3373
        SSessionKey* pKey = taosArrayGet(pNotifySup->pSessionKeys, i);
×
UNCOV
3374
        pKey->win.ekey += pAggSup->gap;
×
3375
      }
3376
      code = addAggResultNotifyEvent(pBInfo->pRes, pNotifySup->pSessionKeys, pTaskInfo->streamInfo.notifyResultSchema,
×
3377
                                     pNotifySup, pNotifyEventStat);
3378
      QUERY_CHECK_CODE(code, lino, _end);
×
3379
    }
3380
    (*ppRes) = pBInfo->pRes;
1,899✔
3381
    return code;
1,899✔
3382
  }
3383

3384
  code = buildNotifyEventBlock(pTaskInfo, pNotifySup, pNotifyEventStat);
4,917✔
3385
  QUERY_CHECK_CODE(code, lino, _end);
4,916!
3386
  if (pNotifySup->pEventBlock && pNotifySup->pEventBlock->info.rows > 0) {
4,916!
UNCOV
3387
    printDataBlock(pNotifySup->pEventBlock, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
UNCOV
3388
    (*ppRes) = pNotifySup->pEventBlock;
×
UNCOV
3389
    return code;
×
3390
  }
3391

3392
  code = removeOutdatedNotifyEvents(&pInfo->twAggSup, pNotifySup, pNotifyEventStat);
4,916✔
3393
  QUERY_CHECK_CODE(code, lino, _end);
4,912!
3394

3395
_end:
4,912✔
3396
  if (code != TSDB_CODE_SUCCESS) {
4,912!
UNCOV
3397
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
3398
  }
3399
  (*ppRes) = NULL;
4,910✔
3400
  return code;
4,910✔
3401
}
3402

3403
int32_t getMaxTsWins(const SArray* pAllWins, SArray* pMaxWins) {
393✔
3404
  int32_t code = TSDB_CODE_SUCCESS;
393✔
3405
  int32_t lino = 0;
393✔
3406
  int32_t size = taosArrayGetSize(pAllWins);
393✔
3407
  if (size == 0) {
393✔
3408
    goto _end;
260✔
3409
  }
3410
  SResultWindowInfo* pWinInfo = taosArrayGet(pAllWins, size - 1);
133✔
3411
  SSessionKey*       pSeKey = &pWinInfo->sessionWin;
133✔
3412
  void*              tmp = taosArrayPush(pMaxWins, pSeKey);
133✔
3413
  if (!tmp) {
133!
UNCOV
3414
    code = terrno;
×
UNCOV
3415
    QUERY_CHECK_CODE(code, lino, _end);
×
3416
  }
3417

3418
  if (pSeKey->groupId == 0) {
133✔
3419
    goto _end;
17✔
3420
  }
3421
  uint64_t preGpId = pSeKey->groupId;
116✔
3422
  for (int32_t i = size - 2; i >= 0; i--) {
437✔
3423
    pWinInfo = taosArrayGet(pAllWins, i);
321✔
3424
    pSeKey = &pWinInfo->sessionWin;
321✔
3425
    if (preGpId != pSeKey->groupId) {
321✔
3426
      void* tmp = taosArrayPush(pMaxWins, pSeKey);
205✔
3427
      if (!tmp) {
205!
UNCOV
3428
        code = terrno;
×
UNCOV
3429
        QUERY_CHECK_CODE(code, lino, _end);
×
3430
      }
3431
      preGpId = pSeKey->groupId;
205✔
3432
    }
3433
  }
3434

3435
_end:
116✔
3436
  if (code != TSDB_CODE_SUCCESS) {
393!
UNCOV
3437
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
3438
  }
3439
  return code;
393✔
3440
}
3441

3442
int32_t encodeSSessionKey(void** buf, SSessionKey* key) {
8✔
3443
  int32_t tlen = 0;
8✔
3444
  tlen += encodeSTimeWindow(buf, &key->win);
8✔
3445
  tlen += taosEncodeFixedU64(buf, key->groupId);
8✔
3446
  return tlen;
8✔
3447
}
3448

3449
void* decodeSSessionKey(void* buf, SSessionKey* key) {
2✔
3450
  buf = decodeSTimeWindow(buf, &key->win);
2✔
3451
  buf = taosDecodeFixedU64(buf, &key->groupId);
2!
3452
  return buf;
2✔
3453
}
3454

3455
int32_t encodeSResultWindowInfo(void** buf, SResultWindowInfo* key, int32_t outLen) {
4✔
3456
  int32_t tlen = 0;
4✔
3457
  tlen += taosEncodeFixedBool(buf, key->isOutput);
4✔
3458
  tlen += encodeSSessionKey(buf, &key->sessionWin);
4✔
3459
  return tlen;
4✔
3460
}
3461

3462
void* decodeSResultWindowInfo(void* buf, SResultWindowInfo* key, int32_t outLen) {
1✔
3463
  buf = taosDecodeFixedBool(buf, &key->isOutput);
1✔
3464
  buf = decodeSSessionKey(buf, &key->sessionWin);
1✔
3465
  return buf;
1✔
3466
}
3467

3468
int32_t doStreamSessionEncodeOpState(void** buf, int32_t len, SOperatorInfo* pOperator, bool isParent) {
×
3469
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
×
3470
  if (!pInfo) {
×
3471
    return 0;
×
3472
  }
3473

3474
  void* pData = (buf == NULL) ? NULL : *buf;
×
3475

3476
  // 1.streamAggSup.pResultRows
UNCOV
3477
  int32_t tlen = 0;
×
UNCOV
3478
  int32_t mapSize = tSimpleHashGetSize(pInfo->streamAggSup.pResultRows);
×
3479
  tlen += taosEncodeFixedI32(buf, mapSize);
×
UNCOV
3480
  void*   pIte = NULL;
×
UNCOV
3481
  size_t  keyLen = 0;
×
3482
  int32_t iter = 0;
×
3483
  while ((pIte = tSimpleHashIterate(pInfo->streamAggSup.pResultRows, pIte, &iter)) != NULL) {
×
3484
    void* key = tSimpleHashGetKey(pIte, &keyLen);
×
3485
    tlen += encodeSSessionKey(buf, key);
×
3486
    tlen += encodeSResultWindowInfo(buf, pIte, pInfo->streamAggSup.resultRowSize);
×
3487
  }
3488

3489
  // 2.twAggSup
3490
  tlen += encodeSTimeWindowAggSupp(buf, &pInfo->twAggSup);
×
3491

3492
  // 3.pChildren
3493
  int32_t size = taosArrayGetSize(pInfo->pChildren);
×
UNCOV
3494
  tlen += taosEncodeFixedI32(buf, size);
×
UNCOV
3495
  for (int32_t i = 0; i < size; i++) {
×
3496
    SOperatorInfo* pChOp = taosArrayGetP(pInfo->pChildren, i);
×
3497
    tlen += doStreamSessionEncodeOpState(buf, 0, pChOp, false);
×
3498
  }
3499

3500
  // 4.dataVersion
3501
  tlen += taosEncodeFixedI64(buf, pInfo->dataVersion);
×
3502

3503
  // 5.basicInfo
UNCOV
3504
  tlen += encodeStreamBasicInfo(buf, &pInfo->basic);
×
3505

3506
  // 6.checksum
UNCOV
3507
  if (isParent) {
×
3508
    if (buf) {
×
3509
      uint32_t cksum = taosCalcChecksum(0, pData, len - sizeof(uint32_t));
×
3510
      tlen += taosEncodeFixedU32(buf, cksum);
×
3511
    } else {
3512
      tlen += sizeof(uint32_t);
×
3513
    }
3514
  }
3515

3516
  return tlen;
×
3517
}
3518

UNCOV
3519
int32_t doStreamSessionDecodeOpState(void* buf, int32_t len, SOperatorInfo* pOperator, bool isParent, void** ppBuf) {
×
UNCOV
3520
  int32_t                        code = TSDB_CODE_SUCCESS;
×
3521
  int32_t                        lino = 0;
×
3522
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
×
3523
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
×
3524
  void*                        pDataEnd = POINTER_SHIFT(buf, len);
×
3525
  if (!pInfo) {
×
3526
    code = TSDB_CODE_FAILED;
×
3527
    QUERY_CHECK_CODE(code, lino, _end);
×
3528
  }
3529
  SStreamAggSupporter* pAggSup = &pInfo->streamAggSup;
×
3530

3531
  // 6.checksum
UNCOV
3532
  if (isParent) {
×
3533
    int32_t dataLen = len - sizeof(uint32_t);
×
3534
    void*   pCksum = POINTER_SHIFT(buf, dataLen);
×
3535
    if (taosCheckChecksum(buf, dataLen, *(uint32_t*)pCksum) != TSDB_CODE_SUCCESS) {
×
3536
      qError("stream session state is invalid");
×
3537
      code = TSDB_CODE_FAILED;
×
3538
      QUERY_CHECK_CODE(code, lino, _end);
×
3539
    }
UNCOV
3540
    pDataEnd = pCksum;
×
3541
  }
3542

3543
  // 1.streamAggSup.pResultRows
3544
  int32_t mapSize = 0;
×
3545
  buf = taosDecodeFixedI32(buf, &mapSize);
×
UNCOV
3546
  for (int32_t i = 0; i < mapSize; i++) {
×
3547
    SResultWindowInfo winfo = {0};
×
UNCOV
3548
    buf = decodeSSessionKey(buf, &winfo.sessionWin);
×
UNCOV
3549
    int32_t winCode = TSDB_CODE_SUCCESS;
×
UNCOV
3550
    code = pAggSup->stateStore.streamStateSessionAddIfNotExist(
×
3551
        pAggSup->pState, &winfo.sessionWin, pAggSup->gap, (void**)&winfo.pStatePos, &pAggSup->resultRowSize, &winCode);
UNCOV
3552
    QUERY_CHECK_CODE(code, lino, _end);
×
UNCOV
3553
    QUERY_CHECK_CONDITION((winCode == TSDB_CODE_SUCCESS), code, lino, _end, TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR);
×
3554

3555
    buf = decodeSResultWindowInfo(buf, &winfo, pInfo->streamAggSup.resultRowSize);
×
3556
    code = tSimpleHashPut(pInfo->streamAggSup.pResultRows, &winfo.sessionWin, sizeof(SSessionKey), &winfo,
×
3557
                          sizeof(SResultWindowInfo));
3558
    QUERY_CHECK_CODE(code, lino, _end);
×
3559
  }
3560

3561
  // 2.twAggSup
UNCOV
3562
  buf = decodeSTimeWindowAggSupp(buf, &pInfo->twAggSup);
×
3563

3564
  // 3.pChildren
3565
  int32_t size = 0;
×
UNCOV
3566
  buf = taosDecodeFixedI32(buf, &size);
×
UNCOV
3567
  for (int32_t i = 0; i < size; i++) {
×
UNCOV
3568
    SOperatorInfo* pChOp = taosArrayGetP(pInfo->pChildren, i);
×
3569
    code = doStreamSessionDecodeOpState(buf, 0, pChOp, false, &buf);
×
3570
    QUERY_CHECK_CODE(code, lino, _end);
×
3571
  }
3572

3573
  // 4.dataVersion
3574
  buf = taosDecodeFixedI64(buf, &pInfo->dataVersion);
×
3575
  if (ppBuf) {
×
3576
    (*ppBuf) = buf;
×
3577
  }
3578

3579
  // 5.basicInfo
UNCOV
3580
  if (buf < pDataEnd) {
×
UNCOV
3581
    code = decodeStreamBasicInfo(&buf, &pInfo->basic);
×
UNCOV
3582
    QUERY_CHECK_CODE(code, lino, _end);
×
3583
  }
3584

3585
_end:
×
3586
  if (code != TSDB_CODE_SUCCESS) {
×
3587
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
3588
  }
UNCOV
3589
  return code;
×
3590
}
3591

3592
void doStreamSessionSaveCheckpoint(SOperatorInfo* pOperator) {
191✔
3593
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
191✔
3594
  if (needSaveStreamOperatorInfo(&pInfo->basic)) {
191!
3595
    int32_t len = doStreamSessionEncodeOpState(NULL, 0, pOperator, true);
×
UNCOV
3596
    void*   buf = taosMemoryCalloc(1, len);
×
UNCOV
3597
    if (!buf) {
×
UNCOV
3598
      qError("%s failed at line %d since %s", __func__, __LINE__, tstrerror(TSDB_CODE_OUT_OF_MEMORY));
×
UNCOV
3599
      return;
×
3600
    }
UNCOV
3601
    void* pBuf = buf;
×
UNCOV
3602
    len = doStreamSessionEncodeOpState(&pBuf, len, pOperator, true);
×
UNCOV
3603
    pInfo->streamAggSup.stateStore.streamStateSaveInfo(pInfo->streamAggSup.pState, STREAM_SESSION_OP_CHECKPOINT_NAME,
×
3604
                                                       strlen(STREAM_SESSION_OP_CHECKPOINT_NAME), buf, len);
UNCOV
3605
    taosMemoryFree(buf);
×
UNCOV
3606
    saveStreamOperatorStateComplete(&pInfo->basic);
×
3607
  }
3608
}
3609

3610
void resetUnCloseSessionWinInfo(SSHashObj* winMap) {
109✔
3611
  void*   pIte = NULL;
109✔
3612
  int32_t iter = 0;
109✔
3613
  while ((pIte = tSimpleHashIterate(winMap, pIte, &iter)) != NULL) {
218✔
3614
    SResultWindowInfo* pResInfo = pIte;
109✔
3615
    pResInfo->pStatePos->beUsed = true;
109✔
3616
  }
3617
}
109✔
3618

3619
int32_t copyDeleteSessionKey(SSHashObj* source, SSHashObj* dest) {
32✔
3620
  int32_t code = TSDB_CODE_SUCCESS;
32✔
3621
  int32_t lino = 0;
32✔
3622
  if (tSimpleHashGetSize(source) == 0) {
32✔
3623
    goto _end;
23✔
3624
  }
3625
  void*   pIte = NULL;
9✔
3626
  int32_t iter = 0;
9✔
3627
  size_t  keyLen = 0;
9✔
3628
  while ((pIte = tSimpleHashIterate(source, pIte, &iter)) != NULL) {
21✔
3629
    SSessionKey* pKey = tSimpleHashGetKey(pIte, &keyLen);
12✔
3630
    code = saveDeleteRes(dest, *pKey);
12✔
3631
    QUERY_CHECK_CODE(code, lino, _end);
12!
3632
  }
3633
  tSimpleHashClear(source);
9✔
3634

3635
_end:
32✔
3636
  if (code != TSDB_CODE_SUCCESS) {
32!
UNCOV
3637
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
3638
  }
3639
  return code;
32✔
3640
}
3641

3642
static int32_t doStreamSessionAggNext(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
6,470✔
3643
  int32_t                        code = TSDB_CODE_SUCCESS;
6,470✔
3644
  int32_t                        lino = 0;
6,470✔
3645
  SExprSupp*                     pSup = &pOperator->exprSupp;
6,470✔
3646
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
6,470✔
3647
  SOptrBasicInfo*                pBInfo = &pInfo->binfo;
6,470✔
3648
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
6,470✔
3649
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
6,470✔
3650
  qDebug("stask:%s  %s status: %d", GET_TASKID(pTaskInfo), getStreamOpName(pOperator->operatorType), pOperator->status);
6,470✔
3651
  if (pOperator->status == OP_EXEC_DONE) {
6,471!
UNCOV
3652
    (*ppRes) = NULL;
×
UNCOV
3653
    return code;
×
3654
  } else if (pOperator->status == OP_RES_TO_RETURN) {
6,471✔
3655
    SSDataBlock* opRes = NULL;
1,865✔
3656
    code = buildSessionResult(pOperator, &opRes);
1,865✔
3657
    QUERY_CHECK_CODE(code, lino, _end);
1,864!
3658
    if (opRes) {
1,864✔
3659
      (*ppRes) = opRes;
447✔
3660
      return code;
1,864✔
3661
    }
3662

3663
    if (pInfo->recvGetAll) {
1,417✔
3664
      pInfo->recvGetAll = false;
83✔
3665
      resetUnCloseSessionWinInfo(pInfo->streamAggSup.pResultRows);
83✔
3666
    }
3667

3668
    if (pInfo->reCkBlock) {
1,417!
UNCOV
3669
      pInfo->reCkBlock = false;
×
UNCOV
3670
      printDataBlock(pInfo->pCheckpointRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
UNCOV
3671
      (*ppRes) = pInfo->pCheckpointRes;
×
UNCOV
3672
      return code;
×
3673
    }
3674

3675
    setStreamOperatorCompleted(pOperator);
1,417✔
3676
    (*ppRes) = NULL;
1,417✔
3677
    return code;
1,417✔
3678
  }
3679

3680
  SOperatorInfo* downstream = pOperator->pDownstream[0];
4,606✔
3681
  if (!pInfo->pUpdated) {
4,606✔
3682
    pInfo->pUpdated = taosArrayInit(16, sizeof(SResultWindowInfo));
3,751✔
3683
    QUERY_CHECK_NULL(pInfo->pUpdated, code, lino, _end, terrno);
3,747!
3684
  }
3685
  if (!pInfo->pStUpdated) {
4,602✔
3686
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
3,678✔
3687
    pInfo->pStUpdated = tSimpleHashInit(64, hashFn);
3,681✔
3688
    QUERY_CHECK_NULL(pInfo->pStUpdated, code, lino, _end, terrno);
3,679!
3689
  }
3690
  while (1) {
3,322✔
3691
    SSDataBlock* pBlock = NULL;
7,925✔
3692
    code = downstream->fpSet.getNextFn(downstream, &pBlock);
7,925✔
3693
    QUERY_CHECK_CODE(code, lino, _end);
7,927!
3694

3695
    if (pBlock == NULL) {
7,927✔
3696
      break;
3,752✔
3697
    }
3698
    printSpecDataBlock(pBlock, getStreamOpName(pOperator->operatorType), "recv", GET_TASKID(pTaskInfo));
4,175✔
3699
    setStreamOperatorState(&pInfo->basic, pBlock->info.type);
4,174✔
3700

3701
    if (pBlock->info.type == STREAM_DELETE_DATA || pBlock->info.type == STREAM_DELETE_RESULT ||
4,173✔
3702
        pBlock->info.type == STREAM_CLEAR) {
3,930✔
3703
      SArray* pWins = taosArrayInit(16, sizeof(SSessionKey));
409✔
3704
      QUERY_CHECK_NULL(pWins, code, lino, _end, terrno);
409!
3705
      // gap must be 0
3706
      code = doDeleteTimeWindows(pAggSup, pBlock, pWins);
409✔
3707
      QUERY_CHECK_CODE(code, lino, _end);
409!
3708

3709
      removeSessionResults(pAggSup, pInfo->pStUpdated, pWins);
409✔
3710
      if (IS_FINAL_SESSION_OP(pOperator)) {
409✔
3711
        int32_t                        childIndex = getChildIndex(pBlock);
56✔
3712
        SOperatorInfo*                 pChildOp = taosArrayGetP(pInfo->pChildren, childIndex);
56✔
3713
        SStreamSessionAggOperatorInfo* pChildInfo = pChildOp->info;
56✔
3714
        // gap must be 0
3715
        code = doDeleteTimeWindows(&pChildInfo->streamAggSup, pBlock, NULL);
56✔
3716
        QUERY_CHECK_CODE(code, lino, _end);
56!
3717

3718
        code = rebuildSessionWindow(pOperator, pWins, pInfo->pStUpdated);
56✔
3719
        QUERY_CHECK_CODE(code, lino, _end);
56!
3720
      }
3721
      code = copyDeleteWindowInfo(pWins, pInfo->pStDeleted);
409✔
3722
      QUERY_CHECK_CODE(code, lino, _end);
409!
3723

3724
      if (pInfo->destHasPrimaryKey && IS_NORMAL_SESSION_OP(pOperator)) {
409!
3725
        code = copyDeleteWindowInfo(pWins, pInfo->pPkDeleted);
2✔
3726
        QUERY_CHECK_CODE(code, lino, _end);
2!
3727
      }
3728
      taosArrayDestroy(pWins);
409✔
3729
      continue;
771✔
3730
    } else if (pBlock->info.type == STREAM_GET_ALL) {
3,764✔
3731
      pInfo->recvGetAll = true;
189✔
3732
      code = getAllSessionWindow(pAggSup->pResultRows, pInfo->pStUpdated);
189✔
3733
      QUERY_CHECK_CODE(code, lino, _end);
189!
3734
      continue;
189✔
3735
    } else if (pBlock->info.type == STREAM_CREATE_CHILD_TABLE) {
3,575✔
3736
      (*ppRes) = pBlock;
854✔
3737
      return code;
854✔
3738
    } else if (pBlock->info.type == STREAM_CHECKPOINT) {
2,721✔
3739
      pAggSup->stateStore.streamStateCommit(pAggSup->pState);
176✔
3740
      doStreamSessionSaveCheckpoint(pOperator);
176✔
3741
      code = copyDataBlock(pInfo->pCheckpointRes, pBlock);
176✔
3742
      QUERY_CHECK_CODE(code, lino, _end);
176!
3743

3744
      continue;
176✔
3745
    } else {
3746
      if (pBlock->info.type != STREAM_NORMAL && pBlock->info.type != STREAM_INVALID) {
2,545!
UNCOV
3747
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
UNCOV
3748
        QUERY_CHECK_CODE(code, lino, _end);
×
3749
      }
3750
    }
3751

3752
    if (pInfo->scalarSupp.pExprInfo != NULL) {
2,545✔
3753
      SExprSupp* pExprSup = &pInfo->scalarSupp;
13✔
3754
      code = projectApplyFunctions(pExprSup->pExprInfo, pBlock, pBlock, pExprSup->pCtx, pExprSup->numOfExprs, NULL);
13✔
3755
      QUERY_CHECK_CODE(code, lino, _end);
13!
3756
    }
3757
    // the pDataBlock are always the same one, no need to call this again
3758
    code = setInputDataBlock(pSup, pBlock, TSDB_ORDER_ASC, MAIN_SCAN, true);
2,545✔
3759
    QUERY_CHECK_CODE(code, lino, _end);
2,554!
3760

3761
    doStreamSessionAggImpl(pOperator, pBlock, pInfo->pStUpdated, pInfo->pStDeleted, IS_FINAL_SESSION_OP(pOperator),
2,554✔
3762
                           true);
3763
    if (IS_FINAL_SESSION_OP(pOperator)) {
2,553✔
3764
      int32_t chIndex = getChildIndex(pBlock);
238✔
3765
      int32_t size = taosArrayGetSize(pInfo->pChildren);
238✔
3766
      // if chIndex + 1 - size > 0, add new child
3767
      for (int32_t i = 0; i < chIndex + 1 - size; i++) {
238!
3768
        SOperatorInfo* pChildOp = NULL;
×
UNCOV
3769
        code = createStreamFinalSessionAggOperatorInfo(NULL, pInfo->pPhyNode, pOperator->pTaskInfo, 0, NULL, &pChildOp);
×
UNCOV
3770
        if (pChildOp == NULL || code != 0) {
×
UNCOV
3771
          qError("%s create stream child of final session error", GET_TASKID(pTaskInfo));
×
UNCOV
3772
          code = TSDB_CODE_FAILED;
×
UNCOV
3773
          QUERY_CHECK_CODE(code, lino, _end);
×
3774
        }
3775

UNCOV
3776
        void* tmp = taosArrayPush(pInfo->pChildren, &pChildOp);
×
UNCOV
3777
        if (!tmp) {
×
UNCOV
3778
          code = terrno;
×
UNCOV
3779
          QUERY_CHECK_CODE(code, lino, _end);
×
3780
        }
3781
      }
3782

3783
      SOperatorInfo* pChildOp = taosArrayGetP(pInfo->pChildren, chIndex);
238✔
3784
      code = setInputDataBlock(&pChildOp->exprSupp, pBlock, TSDB_ORDER_ASC, MAIN_SCAN, true);
238✔
3785
      QUERY_CHECK_CODE(code, lino, _end);
238!
3786
      doStreamSessionAggImpl(pChildOp, pBlock, NULL, NULL, true, false);
238✔
3787
    }
3788
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.window.ekey);
2,551✔
3789
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.watermark);
2,551✔
3790
  }
3791
  // restore the value
3792
  pOperator->status = OP_RES_TO_RETURN;
3,752✔
3793

3794
  code = closeSessionWindow(pAggSup->pResultRows, &pInfo->twAggSup, pInfo->pStUpdated);
3,752✔
3795
  QUERY_CHECK_CODE(code, lino, _end);
3,752!
3796

3797
  code = closeChildSessionWindow(pInfo->pChildren, pInfo->twAggSup.maxTs);
3,752✔
3798
  QUERY_CHECK_CODE(code, lino, _end);
3,746!
3799

3800
  code = copyUpdateResult(&pInfo->pStUpdated, pInfo->pUpdated, sessionKeyCompareAsc);
3,746✔
3801
  QUERY_CHECK_CODE(code, lino, _end);
3,737!
3802

3803
  if (!pInfo->destHasPrimaryKey) {
3,737✔
3804
    removeSessionDeleteResults(pInfo->pStDeleted, pInfo->pUpdated);
3,729✔
3805
  }
3806
  if (pInfo->isHistoryOp) {
3,732✔
3807
    code = getMaxTsWins(pInfo->pUpdated, pInfo->historyWins);
201✔
3808
    QUERY_CHECK_CODE(code, lino, _end);
201!
3809
  }
3810
  if (pInfo->destHasPrimaryKey && IS_NORMAL_SESSION_OP(pOperator)) {
3,732!
3811
    code = copyDeleteSessionKey(pInfo->pPkDeleted, pInfo->pStDeleted);
20✔
3812
    QUERY_CHECK_CODE(code, lino, _end);
20!
3813
  }
3814
  initGroupResInfoFromArrayList(&pInfo->groupResInfo, pInfo->pUpdated);
3,732✔
3815
  pInfo->pUpdated = NULL;
3,715✔
3816
  code = blockDataEnsureCapacity(pInfo->binfo.pRes, pOperator->resultInfo.capacity);
3,715✔
3817
  QUERY_CHECK_CODE(code, lino, _end);
3,731!
3818

3819
  SSDataBlock* opRes = NULL;
3,731✔
3820
  code = buildSessionResult(pOperator, &opRes);
3,731✔
3821
  QUERY_CHECK_CODE(code, lino, _end);
3,746!
3822
  if (opRes) {
3,746✔
3823
    (*ppRes) = opRes;
1,418✔
3824
    return code;
1,418✔
3825
  }
3826

3827
_end:
2,328✔
3828
  if (code != TSDB_CODE_SUCCESS) {
2,328!
3829
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
3830
    pTaskInfo->code = code;
×
UNCOV
3831
    T_LONG_JMP(pTaskInfo->env, code);
×
3832
  }
3833
  setStreamOperatorCompleted(pOperator);
2,328✔
3834
  (*ppRes) = NULL;
2,332✔
3835
  return code;
2,332✔
3836
}
3837

UNCOV
3838
static SSDataBlock* doStreamSessionAgg(SOperatorInfo* pOperator) {
×
3839
  SSDataBlock* pRes = NULL;
×
UNCOV
3840
  int32_t      code = doStreamSessionAggNext(pOperator, &pRes);
×
UNCOV
3841
  return pRes;
×
3842
}
3843

3844
void streamSessionReleaseState(SOperatorInfo* pOperator) {
191✔
3845
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
191✔
3846
  int32_t                        winSize = taosArrayGetSize(pInfo->historyWins) * sizeof(SSessionKey);
191✔
3847
  int32_t                        resSize = winSize + sizeof(TSKEY);
191✔
3848
  char*                          pBuff = taosMemoryCalloc(1, resSize);
191!
3849
  if (!pBuff) {
191!
UNCOV
3850
    return;
×
3851
  }
3852
  memcpy(pBuff, pInfo->historyWins->pData, winSize);
191✔
3853
  memcpy(pBuff + winSize, &pInfo->twAggSup.maxTs, sizeof(TSKEY));
191✔
3854
  pInfo->streamAggSup.stateStore.streamStateSaveInfo(pInfo->streamAggSup.pState, STREAM_SESSION_OP_STATE_NAME,
191✔
3855
                                                     strlen(STREAM_SESSION_OP_STATE_NAME), pBuff, resSize);
3856
  pInfo->streamAggSup.stateStore.streamStateCommit(pInfo->streamAggSup.pState);
191✔
3857
  taosMemoryFreeClear(pBuff);
191!
3858
  SOperatorInfo* downstream = pOperator->pDownstream[0];
191✔
3859
  if (downstream->fpSet.releaseStreamStateFn) {
191!
3860
    downstream->fpSet.releaseStreamStateFn(downstream);
191✔
3861
  }
3862
}
3863

3864
void resetWinRange(STimeWindow* winRange) {
359✔
3865
  winRange->skey = INT64_MIN;
359✔
3866
  winRange->ekey = INT64_MAX;
359✔
3867
}
359✔
3868

3869
int32_t getSessionWindowInfoByKey(SStreamAggSupporter* pAggSup, SSessionKey* pKey, SResultWindowInfo* pWinInfo) {
338✔
3870
  int32_t code = TSDB_CODE_SUCCESS;
338✔
3871
  int32_t lino = 0;
338✔
3872
  int32_t rowSize = pAggSup->resultRowSize;
338✔
3873
  int32_t winCode = TSDB_CODE_SUCCESS;
338✔
3874
  code = pAggSup->stateStore.streamStateSessionGet(pAggSup->pState, pKey, (void**)&pWinInfo->pStatePos, &rowSize,
338✔
3875
                                                   &winCode);
3876
  QUERY_CHECK_CODE(code, lino, _end);
338!
3877

3878
  if (winCode == TSDB_CODE_SUCCESS) {
338!
3879
    pWinInfo->sessionWin = *pKey;
338✔
3880
    pWinInfo->isOutput = true;
338✔
3881
    if (pWinInfo->pStatePos->needFree) {
338!
3882
      pAggSup->stateStore.streamStateSessionDel(pAggSup->pState, &pWinInfo->sessionWin);
338✔
3883
    }
3884
  } else {
UNCOV
3885
    SET_SESSION_WIN_INVALID((*pWinInfo));
×
3886
  }
3887

3888
_end:
338✔
3889
  if (code != TSDB_CODE_SUCCESS) {
338!
UNCOV
3890
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
3891
  }
3892
  return code;
338✔
3893
}
3894

3895
void reloadAggSupFromDownStream(SOperatorInfo* downstream, SStreamAggSupporter* pAggSup) {
643✔
3896
  SStateStore* pAPI = &downstream->pTaskInfo->storageAPI.stateStore;
643✔
3897

3898
  if (downstream->operatorType != QUERY_NODE_PHYSICAL_PLAN_STREAM_SCAN) {
643✔
3899
    reloadAggSupFromDownStream(downstream->pDownstream[0], pAggSup);
205✔
3900
    return;
205✔
3901
  }
3902

3903
  SStreamScanInfo* pScanInfo = downstream->info;
438✔
3904
  pAggSup->pUpdateInfo = pScanInfo->pUpdateInfo;
438✔
3905
}
3906

3907
void streamSessionSemiReloadState(SOperatorInfo* pOperator) {
15✔
3908
  int32_t                        code = TSDB_CODE_SUCCESS;
15✔
3909
  int32_t                        lino = 0;
15✔
3910
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
15✔
3911
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
15✔
3912
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
15✔
3913
  resetWinRange(&pAggSup->winRange);
15✔
3914

3915
  SResultWindowInfo winInfo = {0};
15✔
3916
  int32_t           size = 0;
15✔
3917
  void*             pBuf = NULL;
15✔
3918
  code = pAggSup->stateStore.streamStateGetInfo(pAggSup->pState, STREAM_SESSION_OP_STATE_NAME,
15✔
3919
                                                strlen(STREAM_SESSION_OP_STATE_NAME), &pBuf, &size);
3920
  QUERY_CHECK_CODE(code, lino, _end);
15!
3921

3922
  int32_t      num = (size - sizeof(TSKEY)) / sizeof(SSessionKey);
15✔
3923
  SSessionKey* pSeKeyBuf = (SSessionKey*)pBuf;
15✔
3924
  for (int32_t i = 0; i < num; i++) {
40✔
3925
    SResultWindowInfo winInfo = {0};
25✔
3926
    code = getSessionWindowInfoByKey(pAggSup, pSeKeyBuf + i, &winInfo);
25✔
3927
    QUERY_CHECK_CODE(code, lino, _end);
25!
3928
    if (!IS_VALID_SESSION_WIN(winInfo)) {
25!
UNCOV
3929
      continue;
×
3930
    }
3931
    compactSessionSemiWindow(pOperator, &winInfo);
25✔
3932
    code = saveSessionOutputBuf(pAggSup, &winInfo);
25✔
3933
    QUERY_CHECK_CODE(code, lino, _end);
25!
3934
  }
3935
  TSKEY ts = *(TSKEY*)((char*)pBuf + size - sizeof(TSKEY));
15✔
3936
  taosMemoryFree(pBuf);
15!
3937
  pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, ts);
15✔
3938
  pAggSup->stateStore.streamStateReloadInfo(pAggSup->pState, ts);
15✔
3939

3940
  SOperatorInfo* downstream = pOperator->pDownstream[0];
15✔
3941
  if (downstream->fpSet.reloadStreamStateFn) {
15!
3942
    downstream->fpSet.reloadStreamStateFn(downstream);
15✔
3943
  }
3944
  reloadAggSupFromDownStream(downstream, &pInfo->streamAggSup);
15✔
3945

3946
_end:
15✔
3947
  if (code != TSDB_CODE_SUCCESS) {
15!
UNCOV
3948
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
3949
  }
3950
}
15✔
3951

3952
void streamSessionReloadState(SOperatorInfo* pOperator) {
176✔
3953
  int32_t                        code = TSDB_CODE_SUCCESS;
176✔
3954
  int32_t                        lino = 0;
176✔
3955
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
176✔
3956
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
176✔
3957
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
176✔
3958
  resetWinRange(&pAggSup->winRange);
176✔
3959

3960
  int32_t size = 0;
176✔
3961
  void*   pBuf = NULL;
176✔
3962
  code = pAggSup->stateStore.streamStateGetInfo(pAggSup->pState, STREAM_SESSION_OP_STATE_NAME,
176✔
3963
                                                strlen(STREAM_SESSION_OP_STATE_NAME), &pBuf, &size);
3964

3965
  QUERY_CHECK_CODE(code, lino, _end);
176!
3966

3967
  int32_t      num = (size - sizeof(TSKEY)) / sizeof(SSessionKey);
176✔
3968
  SSessionKey* pSeKeyBuf = (SSessionKey*)pBuf;
176✔
3969

3970
  TSKEY ts = *(TSKEY*)((char*)pBuf + size - sizeof(TSKEY));
176✔
3971
  pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, ts);
176✔
3972
  pAggSup->stateStore.streamStateReloadInfo(pAggSup->pState, ts);
176✔
3973

3974
  if (!pInfo->pStUpdated && num > 0) {
176!
3975
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
70✔
3976
    pInfo->pStUpdated = tSimpleHashInit(64, hashFn);
70✔
3977
    QUERY_CHECK_NULL(pInfo->pStUpdated, code, lino, _end, terrno);
70!
3978
  }
3979
  for (int32_t i = 0; i < num; i++) {
337✔
3980
    SResultWindowInfo winInfo = {0};
161✔
3981
    code = getSessionWindowInfoByKey(pAggSup, pSeKeyBuf + i, &winInfo);
161✔
3982
    QUERY_CHECK_CODE(code, lino, _end);
161!
3983
    if (!IS_VALID_SESSION_WIN(winInfo)) {
161!
3984
      continue;
×
3985
    }
3986

3987
    int32_t winNum = 0;
161✔
3988
    code = compactSessionWindow(pOperator, &winInfo, pInfo->pStUpdated, pInfo->pStDeleted, true, &winNum, NULL);
161✔
3989
    QUERY_CHECK_CODE(code, lino, _end);
161!
3990

3991
    if (winNum > 0) {
161!
3992
      qDebug("===stream=== reload state. save result %" PRId64 ", %" PRIu64, winInfo.sessionWin.win.skey,
×
3993
             winInfo.sessionWin.groupId);
3994
      if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_AT_ONCE) {
×
UNCOV
3995
        code = saveResult(winInfo, pInfo->pStUpdated);
×
UNCOV
3996
        QUERY_CHECK_CODE(code, lino, _end);
×
UNCOV
3997
      } else if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_WINDOW_CLOSE) {
×
UNCOV
3998
        if (!isCloseWindow(&winInfo.sessionWin.win, &pInfo->twAggSup)) {
×
UNCOV
3999
          code = saveDeleteRes(pInfo->pStDeleted, winInfo.sessionWin);
×
UNCOV
4000
          QUERY_CHECK_CODE(code, lino, _end);
×
4001
        }
UNCOV
4002
        SSessionKey key = {0};
×
UNCOV
4003
        getSessionHashKey(&winInfo.sessionWin, &key);
×
UNCOV
4004
        code = tSimpleHashPut(pAggSup->pResultRows, &key, sizeof(SSessionKey), &winInfo, sizeof(SResultWindowInfo));
×
UNCOV
4005
        QUERY_CHECK_CODE(code, lino, _end);
×
4006
      }
4007
    }
4008
    code = saveSessionOutputBuf(pAggSup, &winInfo);
161✔
4009
    QUERY_CHECK_CODE(code, lino, _end);
161!
4010
  }
4011
  taosMemoryFree(pBuf);
176!
4012

4013
  SOperatorInfo* downstream = pOperator->pDownstream[0];
176✔
4014
  if (downstream->fpSet.reloadStreamStateFn) {
176!
4015
    downstream->fpSet.reloadStreamStateFn(downstream);
176✔
4016
  }
4017
  reloadAggSupFromDownStream(downstream, &pInfo->streamAggSup);
176✔
4018

4019
_end:
176✔
4020
  if (code != TSDB_CODE_SUCCESS) {
176!
UNCOV
4021
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
4022
  }
4023
}
176✔
4024

4025
int32_t createStreamSessionAggOperatorInfo(SOperatorInfo* downstream, SPhysiNode* pPhyNode, SExecTaskInfo* pTaskInfo,
903✔
4026
                                           SReadHandle* pHandle, SOperatorInfo** pOptrInfo) {
4027
  QRY_PARAM_CHECK(pOptrInfo);
903!
4028

4029
  SSessionWinodwPhysiNode*       pSessionNode = (SSessionWinodwPhysiNode*)pPhyNode;
903✔
4030
  int32_t                        numOfCols = 0;
903✔
4031
  int32_t                        code = TSDB_CODE_OUT_OF_MEMORY;
903✔
4032
  int32_t                        lino = 0;
903✔
4033
  SStreamSessionAggOperatorInfo* pInfo = taosMemoryCalloc(1, sizeof(SStreamSessionAggOperatorInfo));
903!
4034
  SOperatorInfo*                 pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo));
902!
4035
  if (pInfo == NULL || pOperator == NULL) {
903!
UNCOV
4036
    code = terrno;
×
UNCOV
4037
    goto _error;
×
4038
  }
4039

4040
  pOperator->pTaskInfo = pTaskInfo;
903✔
4041

4042
  initResultSizeInfo(&pOperator->resultInfo, 4096);
903✔
4043
  if (pSessionNode->window.pExprs != NULL) {
902✔
4044
    int32_t    numOfScalar = 0;
1✔
4045
    SExprInfo* pScalarExprInfo = NULL;
1✔
4046
    code = createExprInfo(pSessionNode->window.pExprs, NULL, &pScalarExprInfo, &numOfScalar);
1✔
4047
    QUERY_CHECK_CODE(code, lino, _error);
1!
4048

4049
    code = initExprSupp(&pInfo->scalarSupp, pScalarExprInfo, numOfScalar, &pTaskInfo->storageAPI.functionStore);
1✔
4050
    if (code != TSDB_CODE_SUCCESS) {
1!
UNCOV
4051
      goto _error;
×
4052
    }
4053
  }
4054
  SExprSupp* pExpSup = &pOperator->exprSupp;
902✔
4055

4056
  SSDataBlock* pResBlock = createDataBlockFromDescNode(pPhyNode->pOutputDataBlockDesc);
902✔
4057
  QUERY_CHECK_NULL(pResBlock, code, lino, _error, terrno);
904!
4058
  pInfo->binfo.pRes = pResBlock;
904✔
4059

4060
  SExprInfo* pExprInfo = NULL;
904✔
4061
  code = createExprInfo(pSessionNode->window.pFuncs, NULL, &pExprInfo, &numOfCols);
904✔
4062
  QUERY_CHECK_CODE(code, lino, _error);
904!
4063

4064
  code = initBasicInfoEx(&pInfo->binfo, pExpSup, pExprInfo, numOfCols, pResBlock, &pTaskInfo->storageAPI.functionStore);
904✔
4065
  QUERY_CHECK_CODE(code, lino, _error);
904!
4066

4067
  pInfo->twAggSup = (STimeWindowAggSupp){
903✔
4068
      .waterMark = pSessionNode->window.watermark,
903✔
4069
      .calTrigger = pSessionNode->window.triggerType,
904✔
4070
      .maxTs = INT64_MIN,
4071
      .minTs = INT64_MAX,
4072
      .deleteMark = getDeleteMark(&pSessionNode->window, 0),
904✔
4073
  };
4074

4075
  pInfo->primaryTsIndex = ((SColumnNode*)pSessionNode->window.pTspk)->slotId;
903✔
4076
  code =
4077
      initStreamAggSupporter(&pInfo->streamAggSup, pExpSup, numOfCols, pSessionNode->gap, pTaskInfo->streamInfo.pState,
903✔
4078
                             0, 0, &pTaskInfo->storageAPI.stateStore, pHandle, &pInfo->twAggSup, GET_TASKID(pTaskInfo),
903✔
4079
                             &pTaskInfo->storageAPI, pInfo->primaryTsIndex, STREAM_STATE_BUFF_SORT, 1);
4080
  if (code != TSDB_CODE_SUCCESS) {
904!
UNCOV
4081
    goto _error;
×
4082
  }
4083

4084
  code = initExecTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &pTaskInfo->window);
904✔
4085
  QUERY_CHECK_CODE(code, lino, _error);
904!
4086

4087
  if (pSessionNode->window.pTsEnd) {
904!
4088
    pInfo->endTsIndex = ((SColumnNode*)pSessionNode->window.pTsEnd)->slotId;
904✔
4089
  }
4090

4091
  pInfo->order = TSDB_ORDER_ASC;
904✔
4092
  _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
904✔
4093
  pInfo->pStDeleted = tSimpleHashInit(64, hashFn);
904✔
4094
  QUERY_CHECK_NULL(pInfo->pStDeleted, code, lino, _error, terrno);
904!
4095
  pInfo->pDelIterator = NULL;
904✔
4096
  code = createSpecialDataBlock(STREAM_DELETE_RESULT, &pInfo->pDelRes);
904✔
4097
  QUERY_CHECK_CODE(code, lino, _error);
904!
4098

4099
  pInfo->pChildren = NULL;
904✔
4100
  pInfo->pPhyNode = pPhyNode;
904✔
4101
  pInfo->ignoreExpiredData = pSessionNode->window.igExpired;
904✔
4102
  pInfo->ignoreExpiredDataSaved = false;
904✔
4103
  pInfo->pUpdated = NULL;
904✔
4104
  pInfo->pStUpdated = NULL;
904✔
4105
  pInfo->dataVersion = 0;
904✔
4106
  pInfo->historyWins = taosArrayInit(4, sizeof(SSessionKey));
904✔
4107
  if (!pInfo->historyWins) {
904!
UNCOV
4108
    goto _error;
×
4109
  }
4110
  if (pHandle) {
904!
4111
    pInfo->isHistoryOp = (pHandle->fillHistory == STREAM_HISTORY_OPERATOR);
904✔
4112
  }
4113

4114
  code = createSpecialDataBlock(STREAM_CHECKPOINT, &pInfo->pCheckpointRes);
904✔
4115
  QUERY_CHECK_CODE(code, lino, _error);
904!
4116

4117
  pInfo->clearState = false;
904✔
4118
  pInfo->recvGetAll = false;
904✔
4119
  pInfo->destHasPrimaryKey = pSessionNode->window.destHasPrimaryKey;
904✔
4120
  pInfo->pPkDeleted = tSimpleHashInit(64, hashFn);
904✔
4121
  QUERY_CHECK_NULL(pInfo->pPkDeleted, code, lino, _error, terrno);
904!
4122
  pInfo->pOperator = pOperator;
904✔
4123
  initNonBlockAggSupptor(&pInfo->nbSup, NULL, NULL);
904✔
4124

4125
  setOperatorInfo(pOperator, getStreamOpName(pOperator->operatorType), nodeType(pSessionNode), true,
904✔
4126
                  OP_NOT_OPENED, pInfo, pTaskInfo);
4127
  if (pPhyNode->type != QUERY_NODE_PHYSICAL_PLAN_STREAM_FINAL_SESSION) {
904✔
4128
    // for stream
4129
    void*   buff = NULL;
741✔
4130
    int32_t len = 0;
741✔
4131
    int32_t res =
4132
        pInfo->streamAggSup.stateStore.streamStateGetInfo(pInfo->streamAggSup.pState, STREAM_SESSION_OP_CHECKPOINT_NAME,
741✔
4133
                                                          strlen(STREAM_SESSION_OP_CHECKPOINT_NAME), &buff, &len);
4134
    if (res == TSDB_CODE_SUCCESS) {
741!
UNCOV
4135
      code = doStreamSessionDecodeOpState(buff, len, pOperator, true, NULL);
×
UNCOV
4136
      taosMemoryFree(buff);
×
UNCOV
4137
      QUERY_CHECK_CODE(code, lino, _error);
×
4138
    }
4139
  }
4140

4141
  code = initStreamBasicInfo(&pInfo->basic, pOperator);
904✔
4142
  QUERY_CHECK_CODE(code, lino, _error);
904!
4143

4144
  if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_CONTINUOUS_WINDOW_CLOSE) {
904!
UNCOV
4145
    if (pHandle->fillHistory == STREAM_HISTORY_OPERATOR) {
×
UNCOV
4146
      setFillHistoryOperatorFlag(&pInfo->basic);
×
UNCOV
4147
    } else if (pHandle->fillHistory == STREAM_RECALCUL_OPERATOR) {
×
UNCOV
4148
      setRecalculateOperatorFlag(&pInfo->basic);
×
4149
    }
4150
    pOperator->fpSet =
4151
        createOperatorFpSet(optrDummyOpenFn, doStreamSessionNonblockAggNext, NULL, destroyStreamSessionAggOperatorInfo,
×
4152
                            optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
UNCOV
4153
    setOperatorStreamStateFn(pOperator, streamSessionNonblockReleaseState, streamSessionNonblockReloadState);
×
4154
  } else {
4155
    pOperator->fpSet =
4156
        createOperatorFpSet(optrDummyOpenFn, doStreamSessionAggNext, NULL, destroyStreamSessionAggOperatorInfo,
904✔
4157
                            optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
4158
    setOperatorStreamStateFn(pOperator, streamSessionReleaseState, streamSessionReloadState);
904✔
4159
  }
4160

4161
  if (downstream) {
904✔
4162
    pInfo->basic.primaryPkIndex = -1;
779✔
4163
    code = initDownStream(downstream, &pInfo->streamAggSup, pOperator->operatorType, pInfo->primaryTsIndex,
779✔
4164
                          &pInfo->twAggSup, &pInfo->basic, pSessionNode->window.recalculateInterval);
779✔
4165
    QUERY_CHECK_CODE(code, lino, _error);
779!
4166

4167
    code = appendDownstream(pOperator, &downstream, 1);
779✔
4168
    QUERY_CHECK_CODE(code, lino, _error);
779!
4169
  }
4170

4171
  *pOptrInfo = pOperator;
904✔
4172
  return TSDB_CODE_SUCCESS;
904✔
4173

UNCOV
4174
_error:
×
UNCOV
4175
  if (pInfo != NULL) {
×
UNCOV
4176
    destroyStreamSessionAggOperatorInfo(pInfo);
×
4177
  }
UNCOV
4178
  destroyOperatorAndDownstreams(pOperator, &downstream, 1);
×
UNCOV
4179
  pTaskInfo->code = code;
×
UNCOV
4180
  qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
UNCOV
4181
  return code;
×
4182
}
4183

4184
static void clearStreamSessionOperator(SStreamSessionAggOperatorInfo* pInfo) {
510✔
4185
  tSimpleHashClear(pInfo->streamAggSup.pResultRows);
510✔
4186
  pInfo->streamAggSup.stateStore.streamStateSessionClear(pInfo->streamAggSup.pState);
510✔
4187
  pInfo->clearState = false;
506✔
4188
}
506✔
4189

4190
int32_t deleteSessionWinState(SStreamAggSupporter* pAggSup, SSDataBlock* pBlock, SSHashObj* pMapUpdate,
654✔
4191
                              SSHashObj* pMapDelete, SSHashObj* pPkDelete, bool needAdd) {
4192
  int32_t code = TSDB_CODE_SUCCESS;
654✔
4193
  int32_t lino = 0;
654✔
4194
  SArray* pWins = taosArrayInit(16, sizeof(SSessionKey));
654✔
4195
  if (!pWins) {
653!
UNCOV
4196
    code = terrno;
×
UNCOV
4197
    QUERY_CHECK_CODE(code, lino, _end);
×
4198
  }
4199
  code = doDeleteTimeWindows(pAggSup, pBlock, pWins);
653✔
4200
  QUERY_CHECK_CODE(code, lino, _end);
654!
4201

4202
  removeSessionResults(pAggSup, pMapUpdate, pWins);
654✔
4203
  code = copyDeleteWindowInfo(pWins, pMapDelete);
654✔
4204
  QUERY_CHECK_CODE(code, lino, _end);
654!
4205

4206
  if (needAdd) {
654!
4207
    code = copyDeleteWindowInfo(pWins, pPkDelete);
×
4208
    QUERY_CHECK_CODE(code, lino, _end);
×
4209
  }
4210
  taosArrayDestroy(pWins);
654✔
4211

4212
_end:
654✔
4213
  if (code != TSDB_CODE_SUCCESS) {
654!
UNCOV
4214
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
4215
  }
4216
  return code;
654✔
4217
}
4218

4219
static int32_t doStreamSessionSemiAggNext(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
951✔
4220
  int32_t                        code = TSDB_CODE_SUCCESS;
951✔
4221
  int32_t                        lino = 0;
951✔
4222
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
951✔
4223
  SOptrBasicInfo*                pBInfo = &pInfo->binfo;
951✔
4224
  TSKEY                          maxTs = INT64_MIN;
951✔
4225
  SExprSupp*                     pSup = &pOperator->exprSupp;
951✔
4226
  SStreamAggSupporter*           pAggSup = &pInfo->streamAggSup;
951✔
4227
  SExecTaskInfo*                 pTaskInfo = pOperator->pTaskInfo;
951✔
4228

4229
  qDebug("stask:%s  %s status: %d", GET_TASKID(pTaskInfo), getStreamOpName(pOperator->operatorType), pOperator->status);
951✔
4230
  if (pOperator->status == OP_EXEC_DONE) {
951!
4231
    (*ppRes) = NULL;
×
UNCOV
4232
    return code;
×
4233
  }
4234

4235
  {
4236
    SSDataBlock* opRes = NULL;
951✔
4237
    code = buildSessionResult(pOperator, &opRes);
951✔
4238
    QUERY_CHECK_CODE(code, lino, _end);
950!
4239
    if (opRes) {
950✔
4240
      (*ppRes) = opRes;
92✔
4241
      return code;
238✔
4242
    }
4243

4244
    if (pInfo->clearState) {
858✔
4245
      clearFunctionContext(&pOperator->exprSupp);
56✔
4246
      // semi session operator clear disk buffer
4247
      clearStreamSessionOperator(pInfo);
56✔
4248
    }
4249

4250
    if (pOperator->status == OP_RES_TO_RETURN) {
856✔
4251
      if (pInfo->reCkBlock) {
146!
UNCOV
4252
        pInfo->reCkBlock = false;
×
UNCOV
4253
        printDataBlock(pInfo->pCheckpointRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
UNCOV
4254
        (*ppRes) = pInfo->pCheckpointRes;
×
UNCOV
4255
        return code;
×
4256
      }
4257
      clearFunctionContext(&pOperator->exprSupp);
146✔
4258
      // semi session operator clear disk buffer
4259
      clearStreamSessionOperator(pInfo);
146✔
4260
      setStreamOperatorCompleted(pOperator);
146✔
4261
      (*ppRes) = NULL;
146✔
4262
      return code;
146✔
4263
    }
4264
  }
4265

4266
  SOperatorInfo* downstream = pOperator->pDownstream[0];
710✔
4267
  if (!pInfo->pUpdated) {
710✔
4268
    pInfo->pUpdated = taosArrayInit(16, sizeof(SResultWindowInfo));
509✔
4269
    QUERY_CHECK_NULL(pInfo->pUpdated, code, lino, _end, terrno);
508!
4270
  }
4271
  if (!pInfo->pStUpdated) {
709✔
4272
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
508✔
4273
    pInfo->pStUpdated = tSimpleHashInit(64, hashFn);
509✔
4274
    QUERY_CHECK_NULL(pInfo->pStUpdated, code, lino, _end, terrno);
512!
4275
  }
4276
  while (1) {
375✔
4277
    SSDataBlock* pBlock = NULL;
1,088✔
4278
    code = downstream->fpSet.getNextFn(downstream, &pBlock);
1,088✔
4279
    QUERY_CHECK_CODE(code, lino, _end);
1,088!
4280

4281
    if (pBlock == NULL) {
1,088✔
4282
      pOperator->status = OP_RES_TO_RETURN;
454✔
4283
      break;
454✔
4284
    }
4285
    printSpecDataBlock(pBlock, getStreamOpName(pOperator->operatorType), "recv", GET_TASKID(pTaskInfo));
634✔
4286
    setStreamOperatorState(&pInfo->basic, pBlock->info.type);
634✔
4287

4288
    if (pBlock->info.type == STREAM_DELETE_DATA || pBlock->info.type == STREAM_DELETE_RESULT ||
634✔
4289
        pBlock->info.type == STREAM_CLEAR) {
583✔
4290
      // gap must be 0
4291
      code = deleteSessionWinState(pAggSup, pBlock, pInfo->pStUpdated, pInfo->pStDeleted, NULL, false);
56✔
4292
      QUERY_CHECK_CODE(code, lino, _end);
56!
4293
      pInfo->clearState = true;
56✔
4294
      break;
56✔
4295
    } else if (pBlock->info.type == STREAM_GET_ALL) {
578!
UNCOV
4296
      code = getAllSessionWindow(pInfo->streamAggSup.pResultRows, pInfo->pStUpdated);
×
UNCOV
4297
      QUERY_CHECK_CODE(code, lino, _end);
×
4298
      continue;
15✔
4299
    } else if (pBlock->info.type == STREAM_CREATE_CHILD_TABLE) {
578✔
4300
      (*ppRes) = pBlock;
203✔
4301
      return code;
203✔
4302
    } else if (pBlock->info.type == STREAM_CHECKPOINT) {
375✔
4303
      pAggSup->stateStore.streamStateCommit(pAggSup->pState);
15✔
4304
      doStreamSessionSaveCheckpoint(pOperator);
15✔
4305
      continue;
15✔
4306
    } else {
4307
      if (pBlock->info.type != STREAM_NORMAL && pBlock->info.type != STREAM_INVALID) {
360!
UNCOV
4308
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
UNCOV
4309
        QUERY_CHECK_CODE(code, lino, _end);
×
4310
      }
4311
    }
4312

4313
    if (pInfo->scalarSupp.pExprInfo != NULL) {
360!
UNCOV
4314
      SExprSupp* pExprSup = &pInfo->scalarSupp;
×
UNCOV
4315
      code = projectApplyFunctions(pExprSup->pExprInfo, pBlock, pBlock, pExprSup->pCtx, pExprSup->numOfExprs, NULL);
×
UNCOV
4316
      QUERY_CHECK_CODE(code, lino, _end);
×
4317
    }
4318
    // the pDataBlock are always the same one, no need to call this again
4319
    code = setInputDataBlock(pSup, pBlock, TSDB_ORDER_ASC, MAIN_SCAN, true);
360✔
4320
    QUERY_CHECK_CODE(code, lino, _end);
360!
4321
    doStreamSessionAggImpl(pOperator, pBlock, pInfo->pStUpdated, NULL, false, false);
360✔
4322
    maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.window.ekey);
360✔
4323
  }
4324

4325
  pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, maxTs);
510✔
4326
  pBInfo->pRes->info.watermark = pInfo->twAggSup.maxTs;
510✔
4327

4328
  code = copyUpdateResult(&pInfo->pStUpdated, pInfo->pUpdated, sessionKeyCompareAsc);
510✔
4329
  QUERY_CHECK_CODE(code, lino, _end);
510!
4330

4331
  removeSessionDeleteResults(pInfo->pStDeleted, pInfo->pUpdated);
510✔
4332

4333
  if (pInfo->isHistoryOp) {
509✔
4334
    code = getMaxTsWins(pInfo->pUpdated, pInfo->historyWins);
14✔
4335
    QUERY_CHECK_CODE(code, lino, _end);
14!
4336
  }
4337

4338
  initGroupResInfoFromArrayList(&pInfo->groupResInfo, pInfo->pUpdated);
509✔
4339
  pInfo->pUpdated = NULL;
510✔
4340
  code = blockDataEnsureCapacity(pBInfo->pRes, pOperator->resultInfo.capacity);
510✔
4341
  QUERY_CHECK_CODE(code, lino, _end);
510!
4342

4343
  SSDataBlock* opRes = NULL;
510✔
4344
  code = buildSessionResult(pOperator, &opRes);
510✔
4345
  QUERY_CHECK_CODE(code, lino, _end);
510!
4346
  if (opRes) {
510✔
4347
    (*ppRes) = opRes;
202✔
4348
    return code;
202✔
4349
  }
4350

4351
_end:
308✔
4352
  if (code != TSDB_CODE_SUCCESS) {
308!
UNCOV
4353
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
UNCOV
4354
    pTaskInfo->code = code;
×
UNCOV
4355
    T_LONG_JMP(pTaskInfo->env, code);
×
4356
  }
4357

4358
  clearFunctionContext(&pOperator->exprSupp);
308✔
4359
  // semi session operator clear disk buffer
4360
  clearStreamSessionOperator(pInfo);
307✔
4361
  setStreamOperatorCompleted(pOperator);
307✔
4362
  (*ppRes) = NULL;
308✔
4363
  return code;
308✔
4364
}
4365

UNCOV
4366
static SSDataBlock* doStreamSessionSemiAgg(SOperatorInfo* pOperator) {
×
UNCOV
4367
  SSDataBlock* pRes = NULL;
×
UNCOV
4368
  int32_t      code = doStreamSessionSemiAggNext(pOperator, &pRes);
×
UNCOV
4369
  return pRes;
×
4370
}
4371

4372
int32_t createStreamFinalSessionAggOperatorInfo(SOperatorInfo* downstream, SPhysiNode* pPhyNode,
288✔
4373
                                                SExecTaskInfo* pTaskInfo, int32_t numOfChild, SReadHandle* pHandle,
4374
                                                SOperatorInfo** pOptrInfo) {
4375
  QRY_PARAM_CHECK(pOptrInfo);
288!
4376

4377
  int32_t        code = TSDB_CODE_SUCCESS;
288✔
4378
  int32_t        lino = 0;
288✔
4379
  SOperatorInfo* pOperator = NULL;
288✔
4380
  code = createStreamSessionAggOperatorInfo(downstream, pPhyNode, pTaskInfo, pHandle, &pOperator);
288✔
4381
  if (pOperator == NULL || code != 0) {
288!
UNCOV
4382
    downstream = NULL;
×
UNCOV
4383
    QUERY_CHECK_CODE(code, lino, _error);
×
4384
  }
4385

4386
  SStreamSessionAggOperatorInfo* pInfo = pOperator->info;
288✔
4387
  pInfo->pOperator = pOperator;
288✔
4388

4389
  if (pPhyNode->type != QUERY_NODE_PHYSICAL_PLAN_STREAM_FINAL_SESSION) {
288✔
4390
    pOperator->fpSet =
125✔
4391
        createOperatorFpSet(optrDummyOpenFn, doStreamSessionSemiAggNext, NULL, destroyStreamSessionAggOperatorInfo,
125✔
4392
                            optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
4393
    setOperatorStreamStateFn(pOperator, streamSessionReleaseState, streamSessionSemiReloadState);
125✔
4394
  }
4395

4396
  if (numOfChild > 0) {
288✔
4397
    pInfo->pChildren = taosArrayInit(numOfChild, sizeof(void*));
38✔
4398
    QUERY_CHECK_NULL(pInfo->pChildren, code, lino, _error, terrno);
38!
4399
    for (int32_t i = 0; i < numOfChild; i++) {
163✔
4400
      SOperatorInfo* pChildOp = NULL;
125✔
4401
      code = createStreamFinalSessionAggOperatorInfo(NULL, pPhyNode, pTaskInfo, 0, pHandle, &pChildOp);
125✔
4402
      if (pChildOp == NULL || code != 0) {
125!
UNCOV
4403
        QUERY_CHECK_CODE(code, lino, _error);
×
4404
      }
4405

4406
      SStreamSessionAggOperatorInfo* pChInfo = pChildOp->info;
125✔
4407
      pChInfo->twAggSup.calTrigger = STREAM_TRIGGER_AT_ONCE;
125✔
4408
      pTaskInfo->storageAPI.stateStore.streamStateSetNumber(pChInfo->streamAggSup.pState, i, pInfo->primaryTsIndex);
125✔
4409
      void* tmp = taosArrayPush(pInfo->pChildren, &pChildOp);
125✔
4410
      if (!tmp) {
125!
UNCOV
4411
        code = terrno;
×
UNCOV
4412
        QUERY_CHECK_CODE(code, lino, _error);
×
4413
      }
4414
    }
4415

4416
    void*   buff = NULL;
38✔
4417
    int32_t len = 0;
38✔
4418
    int32_t res =
4419
        pInfo->streamAggSup.stateStore.streamStateGetInfo(pInfo->streamAggSup.pState, STREAM_SESSION_OP_CHECKPOINT_NAME,
38✔
4420
                                                          strlen(STREAM_SESSION_OP_CHECKPOINT_NAME), &buff, &len);
4421
    if (res == TSDB_CODE_SUCCESS) {
38!
UNCOV
4422
      code = doStreamSessionDecodeOpState(buff, len, pOperator, true, NULL);
×
4423
      taosMemoryFree(buff);
×
4424
      QUERY_CHECK_CODE(code, lino, _error);
×
4425
    }
4426
  }
4427

4428
  if (!IS_FINAL_SESSION_OP(pOperator) || numOfChild == 0) {
288✔
4429
    pInfo->twAggSup.calTrigger = STREAM_TRIGGER_AT_ONCE;
250✔
4430
  }
4431

4432
  *pOptrInfo = pOperator;
288✔
4433
  return code;
288✔
4434

UNCOV
4435
_error:
×
4436
  if (pInfo != NULL) {
×
UNCOV
4437
    destroyStreamSessionAggOperatorInfo(pInfo);
×
4438
  }
UNCOV
4439
  if (pOperator != NULL) {
×
UNCOV
4440
    pOperator->info = NULL;
×
UNCOV
4441
    destroyOperator(pOperator);
×
4442
  }
UNCOV
4443
  pTaskInfo->code = code;
×
UNCOV
4444
  if (code != TSDB_CODE_SUCCESS) {
×
UNCOV
4445
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
4446
  }
UNCOV
4447
  return code;
×
4448
}
4449

4450
void destroyStreamStateOperatorInfo(void* param) {
356✔
4451
  if (param == NULL) {
356!
UNCOV
4452
    return;
×
4453
  }
4454
  SStreamStateAggOperatorInfo* pInfo = (SStreamStateAggOperatorInfo*)param;
356✔
4455
  cleanupBasicInfo(&pInfo->binfo);
356✔
4456
  if (pInfo->pOperator) {
356!
4457
    cleanupResultInfoInStream(pInfo->pOperator->pTaskInfo, pInfo->streamAggSup.pState, &pInfo->pOperator->exprSupp,
356✔
4458
                              &pInfo->groupResInfo);
4459
    pInfo->pOperator = NULL;
356✔
4460
  }
4461

4462
  destroyStreamBasicInfo(&pInfo->basic);
356✔
4463
  clearGroupResInfo(&pInfo->groupResInfo);
356✔
4464
  taosArrayDestroyP(pInfo->pUpdated, destroyFlusedPos);
356✔
4465
  pInfo->pUpdated = NULL;
356✔
4466
  destroyStreamAggSupporter(&pInfo->streamAggSup);
356✔
4467

4468
  cleanupExprSupp(&pInfo->scalarSupp);
356✔
4469
  if (pInfo->pChildren != NULL) {
356!
UNCOV
4470
    int32_t size = taosArrayGetSize(pInfo->pChildren);
×
UNCOV
4471
    for (int32_t i = 0; i < size; i++) {
×
UNCOV
4472
      SOperatorInfo* pChild = taosArrayGetP(pInfo->pChildren, i);
×
UNCOV
4473
      destroyOperator(pChild);
×
4474
    }
UNCOV
4475
    taosArrayDestroy(pInfo->pChildren);
×
4476
  }
4477
  colDataDestroy(&pInfo->twAggSup.timeWindowData);
356✔
4478
  blockDataDestroy(pInfo->pDelRes);
356✔
4479
  tSimpleHashCleanup(pInfo->pSeUpdated);
356✔
4480
  tSimpleHashCleanup(pInfo->pSeDeleted);
356✔
4481
  cleanupGroupResInfo(&pInfo->groupResInfo);
356✔
4482

4483
  taosArrayDestroy(pInfo->historyWins);
356✔
4484
  blockDataDestroy(pInfo->pCheckpointRes);
356✔
4485
  tSimpleHashCleanup(pInfo->pPkDeleted);
356✔
4486
  destroyNonBlockAggSupptor(&pInfo->nbSup);
356✔
4487

4488
  taosMemoryFreeClear(param);
356!
4489
}
4490

4491
bool isTsInWindow(SStateWindowInfo* pWin, TSKEY ts) {
4,017✔
4492
  if (pWin->winInfo.sessionWin.win.skey <= ts && ts <= pWin->winInfo.sessionWin.win.ekey) {
4,017✔
4493
    return true;
1,314✔
4494
  }
4495
  return false;
2,703✔
4496
}
4497

4498
bool isEqualStateKey(SStateWindowInfo* pWin, char* pKeyData) {
6,609✔
4499
  return pKeyData && compareVal(pKeyData, pWin->pStateKey);
6,609!
4500
}
4501

4502
bool compareStateKey(void* data, void* key) {
2,684✔
4503
  if (!data || !key) {
2,684!
UNCOV
4504
    return true;
×
4505
  }
4506
  SStateKeys* stateKey = (SStateKeys*)key;
2,684✔
4507
  stateKey->pData = (char*)key + sizeof(SStateKeys);
2,684✔
4508
  return compareVal(data, stateKey);
2,684✔
4509
}
4510

4511
bool compareWinStateKey(SStateKeys* left, SStateKeys* right) {
124✔
4512
  if (!left || !right) {
124!
4513
    return false;
124✔
4514
  }
UNCOV
4515
  return compareVal(left->pData, right);
×
4516
}
4517

4518
void getNextStateWin(const SStreamAggSupporter* pAggSup, SStateWindowInfo* pNextWin, bool asc) {
3,411✔
4519
  SStreamStateCur* pCur = NULL;
3,411✔
4520

4521
  if (pAggSup == NULL || pNextWin == NULL) {
3,411!
UNCOV
4522
    return;
×
4523
  }
4524

4525
  if (asc)
3,411!
4526
    pCur = pAggSup->stateStore.streamStateSessionSeekKeyNext(pAggSup->pState, &pNextWin->winInfo.sessionWin);
3,411✔
4527
  else
UNCOV
4528
    pCur = pAggSup->stateStore.streamStateSessionSeekKeyPrev(pAggSup->pState, &pNextWin->winInfo.sessionWin);
×
4529
  int32_t nextSize = pAggSup->resultRowSize;
3,411✔
4530
  int32_t winCode = pAggSup->stateStore.streamStateSessionGetKVByCur(pCur, &pNextWin->winInfo.sessionWin,
3,411✔
4531
                                                                     (void**)&pNextWin->winInfo.pStatePos, &nextSize);
3,411✔
4532
  if (winCode != TSDB_CODE_SUCCESS) {
3,411✔
4533
    SET_SESSION_WIN_INVALID(pNextWin->winInfo);
3,240✔
4534
  } else {
4535
    pNextWin->pStateKey =
171✔
4536
        (SStateKeys*)((char*)pNextWin->winInfo.pStatePos->pRowBuff + (pAggSup->resultRowSize - pAggSup->stateKeySize));
171✔
4537
    pNextWin->pStateKey->bytes = pAggSup->stateKeySize - sizeof(SStateKeys);
171✔
4538
    pNextWin->pStateKey->type = pAggSup->stateKeyType;
171✔
4539
    pNextWin->pStateKey->pData = (char*)pNextWin->pStateKey + sizeof(SStateKeys);
171✔
4540
    pNextWin->pStateKey->isNull = false;
171✔
4541
    pNextWin->winInfo.isOutput = true;
171✔
4542
  }
4543
  pAggSup->stateStore.streamStateFreeCur(pCur);
3,411✔
4544
}
4545

4546
int32_t getStateWindowInfoByKey(SStreamAggSupporter* pAggSup, SSessionKey* pKey, SStateWindowInfo* pCurWin,
124✔
4547
                                SStateWindowInfo* pNextWin) {
4548
  int32_t code = TSDB_CODE_SUCCESS;
124✔
4549
  int32_t lino = 0;
124✔
4550
  int32_t size = pAggSup->resultRowSize;
124✔
4551
  pCurWin->winInfo.sessionWin.groupId = pKey->groupId;
124✔
4552
  pCurWin->winInfo.sessionWin.win.skey = pKey->win.skey;
124✔
4553
  pCurWin->winInfo.sessionWin.win.ekey = pKey->win.ekey;
124✔
4554
  code = getSessionWindowInfoByKey(pAggSup, pKey, &pCurWin->winInfo);
124✔
4555
  QUERY_CHECK_CODE(code, lino, _end);
124!
4556
  QUERY_CHECK_CONDITION((IS_VALID_SESSION_WIN(pCurWin->winInfo)), code, lino, _end,
124!
4557
                        TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR);
4558

4559
  pCurWin->pStateKey =
124✔
4560
      (SStateKeys*)((char*)pCurWin->winInfo.pStatePos->pRowBuff + (pAggSup->resultRowSize - pAggSup->stateKeySize));
124✔
4561
  pCurWin->pStateKey->bytes = pAggSup->stateKeySize - sizeof(SStateKeys);
124✔
4562
  pCurWin->pStateKey->type = pAggSup->stateKeyType;
124✔
4563
  pCurWin->pStateKey->pData = (char*)pCurWin->pStateKey + sizeof(SStateKeys);
124✔
4564
  pCurWin->pStateKey->isNull = false;
124✔
4565
  pCurWin->winInfo.isOutput = true;
124✔
4566
  if (pCurWin->winInfo.pStatePos->needFree) {
124!
4567
    pAggSup->stateStore.streamStateSessionDel(pAggSup->pState, &pCurWin->winInfo.sessionWin);
124✔
4568
  }
4569

4570
  qDebug("===stream===get state cur win buff. skey:%" PRId64 ", endkey:%" PRId64, pCurWin->winInfo.sessionWin.win.skey,
124✔
4571
         pCurWin->winInfo.sessionWin.win.ekey);
4572

4573
  pNextWin->winInfo.sessionWin = pCurWin->winInfo.sessionWin;
124✔
4574
  getNextStateWin(pAggSup, pNextWin, true);
124✔
4575

4576
_end:
124✔
4577
  qDebug("===stream===get state next win buff. skey:%" PRId64 ", endkey:%" PRId64,
124✔
4578
         pNextWin->winInfo.sessionWin.win.skey, pNextWin->winInfo.sessionWin.win.ekey);
4579
  if (code != TSDB_CODE_SUCCESS) {
124!
UNCOV
4580
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
4581
  }
4582
  return code;
124✔
4583
}
4584

4585
int32_t setStateOutputBuf(SStreamAggSupporter* pAggSup, TSKEY ts, uint64_t groupId, char* pKeyData,
3,287✔
4586
                          SStateWindowInfo* pCurWin, SStateWindowInfo* pNextWin, int32_t* pWinCode) {
4587
  int32_t size = pAggSup->resultRowSize;
3,287✔
4588
  pCurWin->winInfo.sessionWin.groupId = groupId;
3,287✔
4589
  pCurWin->winInfo.sessionWin.win.skey = ts;
3,287✔
4590
  pCurWin->winInfo.sessionWin.win.ekey = ts;
3,287✔
4591
  int32_t code = TSDB_CODE_SUCCESS;
3,287✔
4592
  int32_t lino = 0;
3,287✔
4593
  int32_t winCode = TSDB_CODE_SUCCESS;
3,287✔
4594
  code = pAggSup->stateStore.streamStateStateAddIfNotExist(pAggSup->pState, &pCurWin->winInfo.sessionWin, pKeyData,
3,287✔
4595
                                                           pAggSup->stateKeySize, compareStateKey,
4596
                                                           (void**)&pCurWin->winInfo.pStatePos, &size, &winCode);
3,287✔
4597
  QUERY_CHECK_CODE(code, lino, _end);
3,287!
4598

4599
  pCurWin->pStateKey =
3,287✔
4600
      (SStateKeys*)((char*)pCurWin->winInfo.pStatePos->pRowBuff + (pAggSup->resultRowSize - pAggSup->stateKeySize));
3,287✔
4601
  pCurWin->pStateKey->bytes = pAggSup->stateKeySize - sizeof(SStateKeys);
3,287✔
4602
  pCurWin->pStateKey->type = pAggSup->stateKeyType;
3,287✔
4603
  pCurWin->pStateKey->pData = (char*)pCurWin->pStateKey + sizeof(SStateKeys);
3,287✔
4604
  pCurWin->pStateKey->isNull = false;
3,287✔
4605

4606
  if (winCode == TSDB_CODE_SUCCESS && !inWinRange(&pAggSup->winRange, &pCurWin->winInfo.sessionWin.win)) {
3,287!
UNCOV
4607
    winCode = TSDB_CODE_FAILED;
×
UNCOV
4608
    clearOutputBuf(pAggSup->pState, pCurWin->winInfo.pStatePos, &pAggSup->pSessionAPI->stateStore);
×
UNCOV
4609
    pCurWin->pStateKey =
×
UNCOV
4610
        (SStateKeys*)((char*)pCurWin->winInfo.pStatePos->pRowBuff + (pAggSup->resultRowSize - pAggSup->stateKeySize));
×
UNCOV
4611
    pCurWin->pStateKey->bytes = pAggSup->stateKeySize - sizeof(SStateKeys);
×
UNCOV
4612
    pCurWin->pStateKey->type = pAggSup->stateKeyType;
×
UNCOV
4613
    pCurWin->pStateKey->pData = (char*)pCurWin->pStateKey + sizeof(SStateKeys);
×
UNCOV
4614
    pCurWin->pStateKey->isNull = false;
×
UNCOV
4615
    pCurWin->winInfo.sessionWin.groupId = groupId;
×
UNCOV
4616
    pCurWin->winInfo.sessionWin.win.skey = ts;
×
UNCOV
4617
    pCurWin->winInfo.sessionWin.win.ekey = ts;
×
UNCOV
4618
    qDebug("===stream===reset state win key. skey:%" PRId64 ", endkey:%" PRId64, pCurWin->winInfo.sessionWin.win.skey,
×
4619
           pCurWin->winInfo.sessionWin.win.ekey);
4620
  }
4621

4622
  if (winCode == TSDB_CODE_SUCCESS) {
3,287✔
4623
    pCurWin->winInfo.isOutput = true;
2,025✔
4624
    if (pCurWin->winInfo.pStatePos->needFree) {
2,025✔
4625
      pAggSup->stateStore.streamStateSessionDel(pAggSup->pState, &pCurWin->winInfo.sessionWin);
62✔
4626
    }
4627
  } else if (pKeyData) {
1,262!
4628
    if (IS_VAR_DATA_TYPE(pAggSup->stateKeyType)) {
1,262!
4629
      varDataCopy(pCurWin->pStateKey->pData, pKeyData);
4✔
4630
    } else {
4631
      memcpy(pCurWin->pStateKey->pData, pKeyData, pCurWin->pStateKey->bytes);
1,258✔
4632
    }
4633
  }
4634

4635
  *pWinCode = winCode;
3,287✔
4636

4637
  qDebug("===stream===set state cur win buff. skey:%" PRId64 ", endkey:%" PRId64, pCurWin->winInfo.sessionWin.win.skey,
3,287✔
4638
         pCurWin->winInfo.sessionWin.win.ekey);
4639

4640
  pNextWin->winInfo.sessionWin = pCurWin->winInfo.sessionWin;
3,287✔
4641
  getNextStateWin(pAggSup, pNextWin, true);
3,287✔
4642
  qDebug("===stream===set state next win buff. skey:%" PRId64 ", endkey:%" PRId64,
3,287✔
4643
         pNextWin->winInfo.sessionWin.win.skey, pNextWin->winInfo.sessionWin.win.ekey);
4644
_end:
1,539✔
4645
  if (code != TSDB_CODE_SUCCESS) {
3,287!
UNCOV
4646
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
4647
  }
4648
  return code;
3,287✔
4649
}
4650

4651
int32_t updateStateWindowInfo(SStreamAggSupporter* pAggSup, SStateWindowInfo* pWinInfo, SStateWindowInfo* pNextWin,
3,287✔
4652
                              TSKEY* pTs, uint64_t groupId, SColumnInfoData* pKeyCol, int32_t rows, int32_t start,
4653
                              bool* allEqual, SSHashObj* pResultRows, SSHashObj* pSeUpdated, SSHashObj* pSeDeleted,
4654
                              int32_t* pWinRows) {
4655
  int32_t code = TSDB_CODE_SUCCESS;
3,287✔
4656
  int32_t lino = 0;
3,287✔
4657
  *allEqual = true;
3,287✔
4658
  for (int32_t i = start; i < rows; ++i) {
7,192✔
4659
    char* pKeyData = colDataGetData(pKeyCol, i);
4,017!
4660
    if (!isTsInWindow(pWinInfo, pTs[i])) {
4,017✔
4661
      if (isEqualStateKey(pWinInfo, pKeyData)) {
2,703✔
4662
        if (IS_VALID_SESSION_WIN(pNextWin->winInfo)) {
2,592✔
4663
          // ts belongs to the next window
4664
          if (pTs[i] >= pNextWin->winInfo.sessionWin.win.skey) {
137!
UNCOV
4665
            (*pWinRows) = i - start;
×
UNCOV
4666
            goto _end;
×
4667
          }
4668
        }
4669
      } else {
4670
        (*pWinRows) = i - start;
111✔
4671
        goto _end;
111✔
4672
      }
4673
    }
4674

4675
    if (pWinInfo->winInfo.sessionWin.win.skey > pTs[i]) {
3,906✔
4676
      if (pSeDeleted && pWinInfo->winInfo.isOutput) {
5!
4677
        code = saveDeleteRes(pSeDeleted, pWinInfo->winInfo.sessionWin);
5✔
4678
        QUERY_CHECK_CODE(code, lino, _end);
5!
4679
      }
4680
      removeSessionResult(pAggSup, pSeUpdated, pResultRows, &pWinInfo->winInfo.sessionWin);
5✔
4681
      pWinInfo->winInfo.sessionWin.win.skey = pTs[i];
5✔
4682
    }
4683
    pWinInfo->winInfo.sessionWin.win.ekey = TMAX(pWinInfo->winInfo.sessionWin.win.ekey, pTs[i]);
3,906✔
4684
    memcpy(pWinInfo->winInfo.pStatePos->pKey, &pWinInfo->winInfo.sessionWin, sizeof(SSessionKey));
3,906✔
4685
    if (!isEqualStateKey(pWinInfo, pKeyData)) {
3,906✔
4686
      *allEqual = false;
22✔
4687
    }
4688
  }
4689
  (*pWinRows) = rows - start;
3,175✔
4690

4691
_end:
3,286✔
4692
  if (code != TSDB_CODE_SUCCESS) {
3,286!
UNCOV
4693
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
4694
  }
4695
  return code;
3,287✔
4696
}
4697

4698
static bool isWinResult(SSessionKey* pKey, SSHashObj* pSeUpdate, SSHashObj* pResults) {
3,287✔
4699
  SSessionKey checkKey = {0};
3,287✔
4700
  getSessionHashKey(pKey, &checkKey);
3,287✔
4701
  if (tSimpleHashGet(pSeUpdate, &checkKey, sizeof(SSessionKey)) != NULL) {
3,286✔
4702
    return true;
30✔
4703
  }
4704

4705
  if (tSimpleHashGet(pResults, &checkKey, sizeof(SSessionKey)) != NULL) {
3,256✔
4706
    return true;
17✔
4707
  }
4708
  return false;
3,240✔
4709
}
4710

4711
static void doStreamStateAggImpl(SOperatorInfo* pOperator, SSDataBlock* pSDataBlock, SSHashObj* pSeUpdated,
3,188✔
4712
                                 SSHashObj* pStDeleted) {
4713
  SExecTaskInfo* pTaskInfo = pOperator->pTaskInfo;
3,188✔
4714
  SStorageAPI*   pAPI = &pOperator->pTaskInfo->storageAPI;
3,188✔
4715

4716
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
3,188✔
4717
  int32_t                      numOfOutput = pOperator->exprSupp.numOfExprs;
3,188✔
4718
  uint64_t                     groupId = pSDataBlock->info.id.groupId;
3,188✔
4719
  int32_t                      code = TSDB_CODE_SUCCESS;
3,188✔
4720
  int32_t                      lino = 0;
3,188✔
4721
  TSKEY*                       tsCols = NULL;
3,188✔
4722
  SResultRow*                  pResult = NULL;
3,188✔
4723
  int32_t                      winRows = 0;
3,188✔
4724
  SStreamAggSupporter*         pAggSup = &pInfo->streamAggSup;
3,188✔
4725
  SStreamNotifyEventSupp*      pNotifySup = &pInfo->basic.notifyEventSup;
3,188✔
4726
  STaskNotifyEventStat*        pNotifyEventStat = pTaskInfo->streamInfo.pNotifyEventStat;
3,188✔
4727

4728
  pInfo->dataVersion = TMAX(pInfo->dataVersion, pSDataBlock->info.version);
3,188✔
4729
  pAggSup->winRange = pTaskInfo->streamInfo.fillHistoryWindow;
3,188✔
4730
  if (pAggSup->winRange.ekey <= 0) {
3,188!
UNCOV
4731
    pAggSup->winRange.ekey = INT64_MAX;
×
4732
  }
4733

4734
  if (pSDataBlock->pDataBlock != NULL) {
3,188!
4735
    SColumnInfoData* pColDataInfo = taosArrayGet(pSDataBlock->pDataBlock, pInfo->primaryTsIndex);
3,188✔
4736
    if (!pColDataInfo) {
3,188!
UNCOV
4737
      code = TSDB_CODE_FAILED;
×
UNCOV
4738
      QUERY_CHECK_CODE(code, lino, _end);
×
4739
    }
4740
    tsCols = (int64_t*)pColDataInfo->pData;
3,188✔
4741
  } else {
UNCOV
4742
    return;
×
4743
  }
4744

4745
  int32_t rows = pSDataBlock->info.rows;
3,188✔
4746
  code = blockDataEnsureCapacity(pAggSup->pScanBlock, rows);
3,188✔
4747
  QUERY_CHECK_CODE(code, lino, _end);
3,188!
4748

4749
  SColumnInfoData* pKeyColInfo = taosArrayGet(pSDataBlock->pDataBlock, pInfo->stateCol.slotId);
3,188✔
4750
  for (int32_t i = 0; i < rows; i += winRows) {
6,496✔
4751
    if (pInfo->ignoreExpiredData && checkExpiredData(&pInfo->streamAggSup.stateStore, pInfo->streamAggSup.pUpdateInfo,
3,372✔
4752
                                                     &pInfo->twAggSup, pSDataBlock->info.id.uid, tsCols[i], NULL, 0) ||
64✔
4753
        colDataIsNull_s(pKeyColInfo, i)) {
6,590✔
4754
      i++;
21✔
4755
      continue;
40✔
4756
    }
4757
    char*            pKeyData = colDataGetData(pKeyColInfo, i);
3,287!
4758
    int32_t          winIndex = 0;
3,287✔
4759
    bool             allEqual = true;
3,287✔
4760
    SStateWindowInfo curWin = {0};
3,287✔
4761
    SStateWindowInfo nextWin = {0};
3,287✔
4762
    int32_t          winCode = TSDB_CODE_SUCCESS;
3,287✔
4763
    code = setStateOutputBuf(pAggSup, tsCols[i], groupId, pKeyData, &curWin, &nextWin, &winCode);
3,287✔
4764
    QUERY_CHECK_CODE(code, lino, _end);
3,286!
4765

4766
    if (winCode != TSDB_CODE_SUCCESS && pTaskInfo->streamInfo.eventTypes) {
3,286!
UNCOV
4767
      SStateWindowInfo prevWin = {.winInfo.sessionWin = curWin.winInfo.sessionWin};
×
UNCOV
4768
      getNextStateWin(pAggSup, &prevWin, false);
×
UNCOV
4769
      qDebug("===stream===get state prev win buff. skey:%" PRId64 ", endkey:%" PRId64,
×
4770
             prevWin.winInfo.sessionWin.win.skey, prevWin.winInfo.sessionWin.win.ekey);
UNCOV
4771
      releaseOutputBuf(pAggSup->pState, prevWin.winInfo.pStatePos, &pAPI->stateStore);
×
4772
      // For ordered data, the previous window's closure did not record the corresponding state values, so they need to
4773
      // be added here.
UNCOV
4774
      if (BIT_FLAG_TEST_MASK(pTaskInfo->streamInfo.eventTypes, SNOTIFY_EVENT_WINDOW_CLOSE) &&
×
UNCOV
4775
          IS_VALID_SESSION_WIN(prevWin.winInfo)) {
×
UNCOV
4776
        code = addStateAggNotifyEvent(SNOTIFY_EVENT_WINDOW_CLOSE, &prevWin.winInfo.sessionWin, prevWin.pStateKey,
×
UNCOV
4777
                                      curWin.pStateKey, true, pNotifySup, pNotifyEventStat);
×
UNCOV
4778
        QUERY_CHECK_CODE(code, lino, _end);
×
4779
      }
UNCOV
4780
      if (BIT_FLAG_TEST_MASK(pTaskInfo->streamInfo.eventTypes, SNOTIFY_EVENT_WINDOW_OPEN)) {
×
UNCOV
4781
        code = addStateAggNotifyEvent(SNOTIFY_EVENT_WINDOW_OPEN, &curWin.winInfo.sessionWin, curWin.pStateKey,
×
UNCOV
4782
                                      prevWin.pStateKey, false, pNotifySup, pNotifyEventStat);
×
UNCOV
4783
        QUERY_CHECK_CODE(code, lino, _end);
×
4784
      }
4785
    }
4786

4787
    if (isWinResult(&nextWin.winInfo.sessionWin, pSeUpdated, pAggSup->pResultRows) == false) {
3,286✔
4788
      releaseOutputBuf(pAggSup->pState, nextWin.winInfo.pStatePos, &pAPI->stateStore);
3,240✔
4789
    }
4790

4791
    setSessionWinOutputInfo(pSeUpdated, &curWin.winInfo);
3,287✔
4792
    code = updateStateWindowInfo(pAggSup, &curWin, &nextWin, tsCols, groupId, pKeyColInfo, rows, i, &allEqual,
3,287✔
4793
                                 pAggSup->pResultRows, pSeUpdated, pStDeleted, &winRows);
4794
    QUERY_CHECK_CODE(code, lino, _end);
3,287!
4795

4796
    if (!allEqual) {
3,287✔
4797
      uint64_t uid = 0;
19✔
4798
      code = appendDataToSpecialBlock(pAggSup->pScanBlock, &curWin.winInfo.sessionWin.win.skey,
19✔
4799
                                      &curWin.winInfo.sessionWin.win.ekey, &uid, &groupId, NULL);
4800
      QUERY_CHECK_CODE(code, lino, _end);
19!
4801
      int32_t tmpRes = tSimpleHashRemove(pSeUpdated, &curWin.winInfo.sessionWin, sizeof(SSessionKey));
19✔
4802
      qTrace("%s at line %d res:%d", __func__, __LINE__, tmpRes);
19!
4803

4804
      doDeleteSessionWindow(pAggSup, &curWin.winInfo.sessionWin);
19✔
4805
      releaseOutputBuf(pAggSup->pState, curWin.winInfo.pStatePos, &pAPI->stateStore);
19✔
4806
      continue;
19✔
4807
    }
4808

4809
    code = doOneWindowAggImpl(&pInfo->twAggSup.timeWindowData, &curWin.winInfo, &pResult, i, winRows, rows, numOfOutput,
3,268✔
4810
                              pOperator, 0);
4811
    QUERY_CHECK_CODE(code, lino, _end);
3,268!
4812

4813
    code = saveSessionOutputBuf(pAggSup, &curWin.winInfo);
3,268✔
4814
    QUERY_CHECK_CODE(code, lino, _end);
3,268!
4815

4816
    if (pInfo->destHasPrimaryKey && curWin.winInfo.isOutput && IS_NORMAL_STATE_OP(pOperator)) {
3,268!
4817
      code = saveDeleteRes(pInfo->pPkDeleted, curWin.winInfo.sessionWin);
1✔
4818
      QUERY_CHECK_CODE(code, lino, _end);
1!
4819
    }
4820

4821
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_AT_ONCE) {
3,268✔
4822
      code = saveResult(curWin.winInfo, pSeUpdated);
2,953✔
4823
      QUERY_CHECK_CODE(code, lino, _end);
2,953!
4824
    }
4825

4826
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_WINDOW_CLOSE) {
3,268✔
4827
      curWin.winInfo.pStatePos->beUpdated = true;
315✔
4828
      SSessionKey key = {0};
315✔
4829
      getSessionHashKey(&curWin.winInfo.sessionWin, &key);
315✔
4830
      code =
4831
          tSimpleHashPut(pAggSup->pResultRows, &key, sizeof(SSessionKey), &curWin.winInfo, sizeof(SResultWindowInfo));
315✔
4832
      QUERY_CHECK_CODE(code, lino, _end);
315!
4833
    }
4834

4835
    // If this is a windown recalculation, add the corresponding state values here since the next window may not require
4836
    // recalculation.
4837
    if (BIT_FLAG_TEST_MASK(pTaskInfo->streamInfo.eventTypes, SNOTIFY_EVENT_WINDOW_CLOSE)) {
3,268!
UNCOV
4838
      code = addStateAggNotifyEvent(SNOTIFY_EVENT_WINDOW_CLOSE, &curWin.winInfo.sessionWin, curWin.pStateKey,
×
UNCOV
4839
                                    nextWin.pStateKey, false, pNotifySup, pNotifyEventStat);
×
UNCOV
4840
      QUERY_CHECK_CODE(code, lino, _end);
×
4841
    }
4842
  }
4843

4844
_end:
3,188✔
4845
  if (code != TSDB_CODE_SUCCESS) {
3,188!
UNCOV
4846
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
4847
  }
4848
}
4849

4850
int32_t doStreamStateEncodeOpState(void** buf, int32_t len, SOperatorInfo* pOperator, bool isParent) {
4✔
4851
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
4✔
4852
  if (!pInfo) {
4!
UNCOV
4853
    return 0;
×
4854
  }
4855

4856
  void* pData = (buf == NULL) ? NULL : *buf;
4✔
4857

4858
  // 1.streamAggSup.pResultRows
4859
  int32_t tlen = 0;
4✔
4860
  int32_t mapSize = tSimpleHashGetSize(pInfo->streamAggSup.pResultRows);
4✔
4861
  tlen += taosEncodeFixedI32(buf, mapSize);
4✔
4862
  void*   pIte = NULL;
4✔
4863
  size_t  keyLen = 0;
4✔
4864
  int32_t iter = 0;
4✔
4865
  while ((pIte = tSimpleHashIterate(pInfo->streamAggSup.pResultRows, pIte, &iter)) != NULL) {
8✔
4866
    void* key = tSimpleHashGetKey(pIte, &keyLen);
4✔
4867
    tlen += encodeSSessionKey(buf, key);
4✔
4868
    tlen += encodeSResultWindowInfo(buf, pIte, pInfo->streamAggSup.resultRowSize);
4✔
4869
  }
4870

4871
  // 2.twAggSup
4872
  tlen += encodeSTimeWindowAggSupp(buf, &pInfo->twAggSup);
4✔
4873

4874
  // 3.pChildren
4875
  int32_t size = taosArrayGetSize(pInfo->pChildren);
4✔
4876
  tlen += taosEncodeFixedI32(buf, size);
4✔
4877
  for (int32_t i = 0; i < size; i++) {
4!
UNCOV
4878
    SOperatorInfo* pChOp = taosArrayGetP(pInfo->pChildren, i);
×
UNCOV
4879
    tlen += doStreamStateEncodeOpState(buf, 0, pChOp, false);
×
4880
  }
4881

4882
  // 4.dataVersion
4883
  tlen += taosEncodeFixedI64(buf, pInfo->dataVersion);
4✔
4884

4885
  // 5.basicInfo
4886
  tlen += encodeStreamBasicInfo(buf, &pInfo->basic);
4✔
4887

4888
  // 6.checksum
4889
  if (isParent) {
4!
4890
    if (buf) {
4✔
4891
      uint32_t cksum = taosCalcChecksum(0, pData, len - sizeof(uint32_t));
4!
4892
      tlen += taosEncodeFixedU32(buf, cksum);
2✔
4893
    } else {
4894
      tlen += sizeof(uint32_t);
2✔
4895
    }
4896
  }
4897

4898
  return tlen;
4✔
4899
}
4900

4901
int32_t doStreamStateDecodeOpState(void* buf, int32_t len, SOperatorInfo* pOperator, bool isParent, void** ppBuf) {
1✔
4902
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
1✔
4903
  int32_t                      code = TSDB_CODE_SUCCESS;
1✔
4904
  int32_t                      lino = 0;
1✔
4905
  SStreamAggSupporter*         pAggSup = &pInfo->streamAggSup;
1✔
4906
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
1✔
4907
  void*                        pDataEnd = POINTER_SHIFT(buf, len);
1✔
4908
  if (!pInfo) {
1!
UNCOV
4909
    code = TSDB_CODE_FAILED;
×
UNCOV
4910
    QUERY_CHECK_CODE(code, lino, _end);
×
4911
  }
4912

4913
  // 6.checksum
4914
  if (isParent) {
1!
4915
    int32_t dataLen = len - sizeof(uint32_t);
1✔
4916
    void*   pCksum = POINTER_SHIFT(buf, dataLen);
1✔
4917
    if (taosCheckChecksum(buf, dataLen, *(uint32_t*)pCksum) != TSDB_CODE_SUCCESS) {
2!
UNCOV
4918
      qError("stream state_window state is invalid");
×
UNCOV
4919
      code = TSDB_CODE_FAILED;
×
UNCOV
4920
      QUERY_CHECK_CODE(code, lino, _end);
×
4921
    }
4922
    pDataEnd = pCksum;
1✔
4923
  }
4924

4925
  // 1.streamAggSup.pResultRows
4926
  int32_t mapSize = 0;
1✔
4927
  buf = taosDecodeFixedI32(buf, &mapSize);
1!
4928
  for (int32_t i = 0; i < mapSize; i++) {
2✔
4929
    SResultWindowInfo winfo = {0};
1✔
4930
    buf = decodeSSessionKey(buf, &winfo.sessionWin);
1✔
4931
    int32_t winCode = TSDB_CODE_SUCCESS;
1✔
4932
    code = pAggSup->stateStore.streamStateStateAddIfNotExist(
1✔
4933
        pAggSup->pState, &winfo.sessionWin, NULL, pAggSup->stateKeySize, compareStateKey, (void**)&winfo.pStatePos,
4934
        &pAggSup->resultRowSize, &winCode);
4935
    QUERY_CHECK_CODE(code, lino, _end);
1!
4936

4937
    buf = decodeSResultWindowInfo(buf, &winfo, pInfo->streamAggSup.resultRowSize);
1✔
4938
    code = tSimpleHashPut(pInfo->streamAggSup.pResultRows, &winfo.sessionWin, sizeof(SSessionKey), &winfo,
1✔
4939
                          sizeof(SResultWindowInfo));
4940
    QUERY_CHECK_CODE(code, lino, _end);
1!
4941
  }
4942

4943
  // 2.twAggSup
4944
  buf = decodeSTimeWindowAggSupp(buf, &pInfo->twAggSup);
1✔
4945

4946
  // 3.pChildren
4947
  int32_t size = 0;
1✔
4948
  buf = taosDecodeFixedI32(buf, &size);
1!
4949
  for (int32_t i = 0; i < size; i++) {
1!
UNCOV
4950
    SOperatorInfo* pChOp = taosArrayGetP(pInfo->pChildren, i);
×
UNCOV
4951
    code = doStreamStateDecodeOpState(buf, 0, pChOp, false, &buf);
×
UNCOV
4952
    QUERY_CHECK_CODE(code, lino, _end);
×
4953
  }
4954

4955
  // 4.dataVersion
4956
  buf = taosDecodeFixedI64(buf, &pInfo->dataVersion);
1!
4957

4958
  if (ppBuf) {
1!
UNCOV
4959
    (*ppBuf) = buf;
×
4960
  }
4961

4962
  // 5.basicInfo
4963
  if (buf < pDataEnd) {
1!
4964
    code = decodeStreamBasicInfo(&buf, &pInfo->basic);
1✔
4965
    QUERY_CHECK_CODE(code, lino, _end);
1!
4966
  }
4967

4968
_end:
1✔
4969
  if (code != TSDB_CODE_SUCCESS) {
1!
UNCOV
4970
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
4971
  }
4972
  return code;
1✔
4973
}
4974

4975
void doStreamStateSaveCheckpoint(SOperatorInfo* pOperator) {
513✔
4976
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
513✔
4977
  if (needSaveStreamOperatorInfo(&pInfo->basic)) {
513✔
4978
    int32_t len = doStreamStateEncodeOpState(NULL, 0, pOperator, true);
2✔
4979
    void*   buf = taosMemoryCalloc(1, len);
2!
4980
    if (!buf) {
2!
UNCOV
4981
      qError("%s failed at line %d since %s", __func__, __LINE__, tstrerror(TSDB_CODE_OUT_OF_MEMORY));
×
UNCOV
4982
      return;
×
4983
    }
4984
    void* pBuf = buf;
2✔
4985
    len = doStreamStateEncodeOpState(&pBuf, len, pOperator, true);
2✔
4986
    pInfo->streamAggSup.stateStore.streamStateSaveInfo(pInfo->streamAggSup.pState, STREAM_STATE_OP_CHECKPOINT_NAME,
2✔
4987
                                                       strlen(STREAM_STATE_OP_CHECKPOINT_NAME), buf, len);
4988
    taosMemoryFree(buf);
2!
4989
    saveStreamOperatorStateComplete(&pInfo->basic);
2✔
4990
  }
4991
}
4992

4993
static int32_t buildStateResult(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
4,271✔
4994
  int32_t                      code = TSDB_CODE_SUCCESS;
4,271✔
4995
  int32_t                      lino = 0;
4,271✔
4996
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
4,271✔
4997
  SOptrBasicInfo*              pBInfo = &pInfo->binfo;
4,271✔
4998
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
4,271✔
4999
  SStreamNotifyEventSupp*      pNotifySup = &pInfo->basic.notifyEventSup;
4,271✔
5000
  STaskNotifyEventStat*        pNotifyEventStat = pTaskInfo->streamInfo.pNotifyEventStat;
4,271✔
5001
  bool                         addNotifyEvent = false;
4,271✔
5002
  addNotifyEvent = BIT_FLAG_TEST_MASK(pTaskInfo->streamInfo.eventTypes, SNOTIFY_EVENT_WINDOW_CLOSE);
4,271✔
5003
  doBuildDeleteDataBlock(pOperator, pInfo->pSeDeleted, pInfo->pDelRes, &pInfo->pDelIterator, &pInfo->groupResInfo);
4,271✔
5004
  if (pInfo->pDelRes->info.rows > 0) {
4,269✔
5005
    printDataBlock(pInfo->pDelRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
198✔
5006
    if (addNotifyEvent) {
199!
UNCOV
5007
      code = addAggDeleteNotifyEvent(pInfo->pDelRes, pNotifySup, pNotifyEventStat);
×
UNCOV
5008
      QUERY_CHECK_CODE(code, lino, _end);
×
5009
    }
5010
    (*ppRes) = pInfo->pDelRes;
199✔
5011
    return code;
199✔
5012
  }
5013

5014
  doBuildSessionResult(pOperator, pInfo->streamAggSup.pState, &pInfo->groupResInfo, pBInfo->pRes,
4,071!
5015
                       addNotifyEvent ? pNotifySup->pSessionKeys : NULL);
5016
  if (pBInfo->pRes->info.rows > 0) {
4,072✔
5017
    printDataBlock(pBInfo->pRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
1,288✔
5018
    if (addNotifyEvent) {
1,288!
UNCOV
5019
      code = addAggResultNotifyEvent(pBInfo->pRes, pNotifySup->pSessionKeys, pTaskInfo->streamInfo.notifyResultSchema,
×
5020
                                     pNotifySup, pNotifyEventStat);
UNCOV
5021
      QUERY_CHECK_CODE(code, lino, _end);
×
5022
    }
5023
    (*ppRes) = pBInfo->pRes;
1,288✔
5024
    return code;
1,288✔
5025
  }
5026

5027
  code = buildNotifyEventBlock(pTaskInfo, pNotifySup, pNotifyEventStat);
2,784✔
5028
  QUERY_CHECK_CODE(code, lino, _end);
2,782!
5029
  if (pNotifySup->pEventBlock && pNotifySup->pEventBlock->info.rows > 0) {
2,782!
UNCOV
5030
    printDataBlock(pNotifySup->pEventBlock, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
5031
    (*ppRes) = pNotifySup->pEventBlock;
×
5032
    return code;
×
5033
  }
5034

5035
  code = removeOutdatedNotifyEvents(&pInfo->twAggSup, pNotifySup, pNotifyEventStat);
2,782✔
5036
  QUERY_CHECK_CODE(code, lino, _end);
2,782!
5037

5038
_end:
2,782✔
5039
  if (code != TSDB_CODE_SUCCESS) {
2,782!
UNCOV
5040
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
5041
  }
5042
  (*ppRes) = NULL;
2,782✔
5043
  return code;
2,782✔
5044
}
5045

5046
static int32_t doStreamStateAggNext(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
4,669✔
5047
  if (pOperator->status == OP_EXEC_DONE) {
4,669!
UNCOV
5048
    (*ppRes) = NULL;
×
UNCOV
5049
    return TSDB_CODE_SUCCESS;
×
5050
  }
5051

5052
  int32_t                      code = TSDB_CODE_SUCCESS;
4,669✔
5053
  int32_t                      lino = 0;
4,669✔
5054
  SExprSupp*                   pSup = &pOperator->exprSupp;
4,669✔
5055
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
4,669✔
5056
  SOptrBasicInfo*              pBInfo = &pInfo->binfo;
4,669✔
5057
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
4,669✔
5058
  qDebug("===stream=== stream state agg");
4,669✔
5059
  if (pOperator->status == OP_RES_TO_RETURN) {
4,669✔
5060
    SSDataBlock* resBlock = NULL;
1,487✔
5061
    code = buildStateResult(pOperator, &resBlock);
1,487✔
5062
    QUERY_CHECK_CODE(code, lino, _end);
1,487!
5063
    if (resBlock != NULL) {
1,487✔
5064
      (*ppRes) = resBlock;
353✔
5065
      return code;
1,487✔
5066
    }
5067

5068
    if (pInfo->recvGetAll) {
1,134✔
5069
      pInfo->recvGetAll = false;
3✔
5070
      resetUnCloseSessionWinInfo(pInfo->streamAggSup.pResultRows);
3✔
5071
    }
5072

5073
    if (pInfo->reCkBlock) {
1,134!
UNCOV
5074
      pInfo->reCkBlock = false;
×
UNCOV
5075
      printDataBlock(pInfo->pCheckpointRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
×
UNCOV
5076
      (*ppRes) = pInfo->pCheckpointRes;
×
UNCOV
5077
      return code;
×
5078
    }
5079

5080
    setStreamOperatorCompleted(pOperator);
1,134✔
5081
    (*ppRes) = NULL;
1,134✔
5082
    return code;
1,134✔
5083
  }
5084

5085
  SOperatorInfo* downstream = pOperator->pDownstream[0];
3,182✔
5086
  if (!pInfo->pUpdated) {
3,182✔
5087
    pInfo->pUpdated = taosArrayInit(16, sizeof(SResultWindowInfo));
2,784✔
5088
    QUERY_CHECK_NULL(pInfo->pUpdated, code, lino, _end, terrno);
2,783!
5089
  }
5090
  if (!pInfo->pSeUpdated) {
3,181✔
5091
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
2,750✔
5092
    pInfo->pSeUpdated = tSimpleHashInit(64, hashFn);
2,750✔
5093
    QUERY_CHECK_NULL(pInfo->pSeUpdated, code, lino, _end, terrno);
2,752!
5094
  }
5095
  while (1) {
4,249✔
5096
    SSDataBlock* pBlock = NULL;
7,432✔
5097
    code = downstream->fpSet.getNextFn(downstream, &pBlock);
7,432✔
5098
    QUERY_CHECK_CODE(code, lino, _end);
7,430!
5099

5100
    if (pBlock == NULL) {
7,430✔
5101
      break;
2,783✔
5102
    }
5103
    printSpecDataBlock(pBlock, getStreamOpName(pOperator->operatorType), "recv", GET_TASKID(pTaskInfo));
4,647✔
5104
    setStreamOperatorState(&pInfo->basic, pBlock->info.type);
4,647✔
5105

5106
    if (pBlock->info.type == STREAM_DELETE_DATA || pBlock->info.type == STREAM_DELETE_RESULT ||
4,647✔
5107
        pBlock->info.type == STREAM_CLEAR) {
4,174✔
5108
      bool add = pInfo->destHasPrimaryKey && IS_NORMAL_STATE_OP(pOperator);
538!
5109
      code = deleteSessionWinState(&pInfo->streamAggSup, pBlock, pInfo->pSeUpdated, pInfo->pSeDeleted,
538✔
5110
                                   pInfo->pPkDeleted, add);
5111
      QUERY_CHECK_CODE(code, lino, _end);
538!
5112
      continue;
1,061✔
5113
    } else if (pBlock->info.type == STREAM_GET_ALL) {
4,109✔
5114
      pInfo->recvGetAll = true;
10✔
5115
      code = getAllSessionWindow(pInfo->streamAggSup.pResultRows, pInfo->pSeUpdated);
10✔
5116
      QUERY_CHECK_CODE(code, lino, _end);
10!
5117
      continue;
10✔
5118
    } else if (pBlock->info.type == STREAM_CREATE_CHILD_TABLE) {
4,099✔
5119
      (*ppRes) = pBlock;
398✔
5120
      return code;
398✔
5121
    } else if (pBlock->info.type == STREAM_CHECKPOINT) {
3,701✔
5122
      pInfo->streamAggSup.stateStore.streamStateCommit(pInfo->streamAggSup.pState);
513✔
5123
      doStreamStateSaveCheckpoint(pOperator);
513✔
5124
      code = copyDataBlock(pInfo->pCheckpointRes, pBlock);
513✔
5125
      QUERY_CHECK_CODE(code, lino, _end);
513!
5126

5127
      continue;
513✔
5128
    } else {
5129
      if (pBlock->info.type != STREAM_NORMAL && pBlock->info.type != STREAM_INVALID) {
3,188!
UNCOV
5130
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
UNCOV
5131
        QUERY_CHECK_CODE(code, lino, _end);
×
5132
      }
5133
    }
5134

5135
    if (pInfo->scalarSupp.pExprInfo != NULL) {
3,188✔
5136
      SExprSupp* pExprSup = &pInfo->scalarSupp;
256✔
5137
      code = projectApplyFunctions(pExprSup->pExprInfo, pBlock, pBlock, pExprSup->pCtx, pExprSup->numOfExprs, NULL);
256✔
5138
      QUERY_CHECK_CODE(code, lino, _end);
256!
5139
    }
5140
    // the pDataBlock are always the same one, no need to call this again
5141
    code = setInputDataBlock(pSup, pBlock, TSDB_ORDER_ASC, MAIN_SCAN, true);
3,188✔
5142
    QUERY_CHECK_CODE(code, lino, _end);
3,188!
5143
    doStreamStateAggImpl(pOperator, pBlock, pInfo->pSeUpdated, pInfo->pSeDeleted);
3,188✔
5144
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.window.ekey);
3,188✔
5145
  }
5146
  // restore the value
5147
  pOperator->status = OP_RES_TO_RETURN;
2,783✔
5148

5149
  code = closeSessionWindow(pInfo->streamAggSup.pResultRows, &pInfo->twAggSup, pInfo->pSeUpdated);
2,783✔
5150
  QUERY_CHECK_CODE(code, lino, _end);
2,784!
5151

5152
  code = copyUpdateResult(&pInfo->pSeUpdated, pInfo->pUpdated, sessionKeyCompareAsc);
2,784✔
5153
  QUERY_CHECK_CODE(code, lino, _end);
2,782!
5154

5155
  removeSessionDeleteResults(pInfo->pSeDeleted, pInfo->pUpdated);
2,782✔
5156

5157
  if (pInfo->isHistoryOp) {
2,784✔
5158
    code = getMaxTsWins(pInfo->pUpdated, pInfo->historyWins);
97✔
5159
    QUERY_CHECK_CODE(code, lino, _end);
97!
5160
  }
5161
  if (pInfo->destHasPrimaryKey && IS_NORMAL_STATE_OP(pOperator)) {
2,784!
5162
    code = copyDeleteSessionKey(pInfo->pPkDeleted, pInfo->pSeDeleted);
4✔
5163
    QUERY_CHECK_CODE(code, lino, _end);
4!
5164
  }
5165

5166
  initGroupResInfoFromArrayList(&pInfo->groupResInfo, pInfo->pUpdated);
2,784✔
5167
  pInfo->pUpdated = NULL;
2,781✔
5168
  code = blockDataEnsureCapacity(pInfo->binfo.pRes, pOperator->resultInfo.capacity);
2,781✔
5169
  QUERY_CHECK_CODE(code, lino, _end);
2,784!
5170

5171
  SSDataBlock* resBlock = NULL;
2,784✔
5172
  code = buildStateResult(pOperator, &resBlock);
2,784✔
5173
  QUERY_CHECK_CODE(code, lino, _end);
2,783!
5174
  if (resBlock != NULL) {
2,783✔
5175
    (*ppRes) = resBlock;
1,134✔
5176
    return code;
1,134✔
5177
  }
5178

5179
_end:
1,649✔
5180
  if (code != TSDB_CODE_SUCCESS) {
1,649!
UNCOV
5181
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
UNCOV
5182
    pTaskInfo->code = code;
×
UNCOV
5183
    T_LONG_JMP(pTaskInfo->env, code);
×
5184
  }
5185
  setStreamOperatorCompleted(pOperator);
1,649✔
5186
  (*ppRes) = NULL;
1,649✔
5187
  return code;
1,649✔
5188
}
5189

UNCOV
5190
static SSDataBlock* doStreamStateAgg(SOperatorInfo* pOperator) {
×
UNCOV
5191
  SSDataBlock* pRes = NULL;
×
UNCOV
5192
  int32_t      code = doStreamStateAggNext(pOperator, &pRes);
×
UNCOV
5193
  return pRes;
×
5194
}
5195

5196
void streamStateReleaseState(SOperatorInfo* pOperator) {
87✔
5197
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
87✔
5198
  int32_t                      winSize = taosArrayGetSize(pInfo->historyWins) * sizeof(SSessionKey);
87✔
5199
  int32_t                      resSize = winSize + sizeof(TSKEY);
87✔
5200
  char*                        pBuff = taosMemoryCalloc(1, resSize);
87!
5201
  if (!pBuff) {
87!
UNCOV
5202
    return;
×
5203
  }
5204
  memcpy(pBuff, pInfo->historyWins->pData, winSize);
87✔
5205
  memcpy(pBuff + winSize, &pInfo->twAggSup.maxTs, sizeof(TSKEY));
87✔
5206
  qDebug("===stream=== relase state. save result count:%d", (int32_t)taosArrayGetSize(pInfo->historyWins));
87✔
5207
  pInfo->streamAggSup.stateStore.streamStateSaveInfo(pInfo->streamAggSup.pState, STREAM_STATE_OP_STATE_NAME,
87✔
5208
                                                     strlen(STREAM_STATE_OP_STATE_NAME), pBuff, resSize);
5209
  pInfo->streamAggSup.stateStore.streamStateCommit(pInfo->streamAggSup.pState);
87✔
5210
  taosMemoryFreeClear(pBuff);
87!
5211

5212
  SOperatorInfo* downstream = pOperator->pDownstream[0];
87✔
5213
  if (downstream->fpSet.releaseStreamStateFn) {
87!
5214
    downstream->fpSet.releaseStreamStateFn(downstream);
87✔
5215
  }
5216
}
5217

UNCOV
5218
int32_t compactStateWindow(SOperatorInfo* pOperator, SResultWindowInfo* pCurWin, SResultWindowInfo* pNextWin,
×
5219
                           SSHashObj* pStUpdated, SSHashObj* pStDeleted) {
UNCOV
5220
  SExprSupp*                   pSup = &pOperator->exprSupp;
×
UNCOV
5221
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
×
UNCOV
5222
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
×
UNCOV
5223
  return compactTimeWindow(pSup, &pInfo->streamAggSup, &pInfo->twAggSup, pTaskInfo, pCurWin, pNextWin, pStUpdated,
×
5224
                           pStDeleted, false);
5225
}
5226

5227
void streamStateReloadState(SOperatorInfo* pOperator) {
87✔
5228
  int32_t                      code = TSDB_CODE_SUCCESS;
87✔
5229
  int32_t                      lino = 0;
87✔
5230
  SStreamStateAggOperatorInfo* pInfo = pOperator->info;
87✔
5231
  SStreamAggSupporter*         pAggSup = &pInfo->streamAggSup;
87✔
5232
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
87✔
5233
  resetWinRange(&pAggSup->winRange);
87✔
5234

5235
  SSessionKey seKey = {.win.skey = INT64_MIN, .win.ekey = INT64_MIN, .groupId = 0};
87✔
5236
  int32_t     size = 0;
87✔
5237
  void*       pBuf = NULL;
87✔
5238
  code = pAggSup->stateStore.streamStateGetInfo(pAggSup->pState, STREAM_STATE_OP_STATE_NAME,
87✔
5239
                                                strlen(STREAM_STATE_OP_STATE_NAME), &pBuf, &size);
5240
  QUERY_CHECK_CODE(code, lino, _end);
87!
5241

5242
  int32_t num = (size - sizeof(TSKEY)) / sizeof(SSessionKey);
87✔
5243
  qDebug("===stream=== reload state. get result count:%d", num);
87✔
5244
  SSessionKey* pSeKeyBuf = (SSessionKey*)pBuf;
87✔
5245

5246
  TSKEY ts = *(TSKEY*)((char*)pBuf + size - sizeof(TSKEY));
87✔
5247
  pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, ts);
87✔
5248
  pAggSup->stateStore.streamStateReloadInfo(pAggSup->pState, ts);
87✔
5249

5250
  if (!pInfo->pSeUpdated && num > 0) {
87!
5251
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
33✔
5252
    pInfo->pSeUpdated = tSimpleHashInit(64, hashFn);
33✔
5253
    QUERY_CHECK_NULL(pInfo->pSeUpdated, code, lino, _end, terrno);
33!
5254
  }
5255
  if (!pInfo->pSeDeleted && num > 0) {
87!
5256
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
×
UNCOV
5257
    pInfo->pSeDeleted = tSimpleHashInit(64, hashFn);
×
5258
    QUERY_CHECK_NULL(pInfo->pSeDeleted, code, lino, _end, terrno);
×
5259
  }
5260
  for (int32_t i = 0; i < num; i++) {
211✔
5261
    SStateWindowInfo curInfo = {0};
124✔
5262
    SStateWindowInfo nextInfo = {0};
124✔
5263
    qDebug("===stream=== reload state. try process result %" PRId64 ", %" PRIu64 ", index:%d", pSeKeyBuf[i].win.skey,
124✔
5264
           pSeKeyBuf[i].groupId, i);
5265
    code = getStateWindowInfoByKey(pAggSup, pSeKeyBuf + i, &curInfo, &nextInfo);
124✔
5266
    QUERY_CHECK_CODE(code, lino, _end);
124!
5267

5268
    bool cpRes = compareWinStateKey(curInfo.pStateKey, nextInfo.pStateKey);
124✔
5269
    qDebug("===stream=== reload state. next window info %" PRId64 ", %" PRIu64 ", compare:%d",
124✔
5270
           nextInfo.winInfo.sessionWin.win.skey, nextInfo.winInfo.sessionWin.groupId, cpRes);
5271
    if (cpRes) {
124!
5272
      code = compactStateWindow(pOperator, &curInfo.winInfo, &nextInfo.winInfo, pInfo->pSeUpdated, pInfo->pSeDeleted);
×
UNCOV
5273
      qDebug("===stream=== reload state. save result %" PRId64 ", %" PRIu64, curInfo.winInfo.sessionWin.win.skey,
×
5274
             curInfo.winInfo.sessionWin.groupId);
5275
      QUERY_CHECK_CODE(code, lino, _end);
×
5276

UNCOV
5277
      if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_AT_ONCE) {
×
UNCOV
5278
        code = saveResult(curInfo.winInfo, pInfo->pSeUpdated);
×
UNCOV
5279
        QUERY_CHECK_CODE(code, lino, _end);
×
UNCOV
5280
      } else if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_WINDOW_CLOSE) {
×
UNCOV
5281
        if (!isCloseWindow(&curInfo.winInfo.sessionWin.win, &pInfo->twAggSup)) {
×
UNCOV
5282
          code = saveDeleteRes(pInfo->pSeDeleted, curInfo.winInfo.sessionWin);
×
UNCOV
5283
          QUERY_CHECK_CODE(code, lino, _end);
×
5284
        }
UNCOV
5285
        SSessionKey key = {0};
×
UNCOV
5286
        getSessionHashKey(&curInfo.winInfo.sessionWin, &key);
×
UNCOV
5287
        code = tSimpleHashPut(pAggSup->pResultRows, &key, sizeof(SSessionKey), &curInfo.winInfo,
×
5288
                              sizeof(SResultWindowInfo));
UNCOV
5289
        QUERY_CHECK_CODE(code, lino, _end);
×
5290
      }
5291
    } else if (IS_VALID_SESSION_WIN(nextInfo.winInfo)) {
124!
UNCOV
5292
      releaseOutputBuf(pAggSup->pState, nextInfo.winInfo.pStatePos, &pAggSup->pSessionAPI->stateStore);
×
5293
    }
5294

5295
    if (IS_VALID_SESSION_WIN(curInfo.winInfo)) {
124!
5296
      code = saveSessionOutputBuf(pAggSup, &curInfo.winInfo);
124✔
5297
      QUERY_CHECK_CODE(code, lino, _end);
124!
5298
    }
5299
  }
5300
  taosMemoryFreeClear(pBuf);
87!
5301

5302
  SOperatorInfo* downstream = pOperator->pDownstream[0];
87✔
5303
  if (downstream->fpSet.reloadStreamStateFn) {
87!
5304
    downstream->fpSet.reloadStreamStateFn(downstream);
87✔
5305
  }
5306
  reloadAggSupFromDownStream(downstream, &pInfo->streamAggSup);
87✔
5307

5308
_end:
87✔
5309
  taosMemoryFreeClear(pBuf);
87!
5310
  if (code != TSDB_CODE_SUCCESS) {
87!
5311
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
5312
  }
5313
}
87✔
5314

5315
int32_t createStreamStateAggOperatorInfo(SOperatorInfo* downstream, SPhysiNode* pPhyNode, SExecTaskInfo* pTaskInfo,
356✔
5316
                                         SReadHandle* pHandle, SOperatorInfo** pOptrInfo) {
5317
  QRY_PARAM_CHECK(pOptrInfo);
356!
5318
  int32_t code = 0;
356✔
5319
  int32_t lino = 0;
356✔
5320

5321
  SStreamStateWinodwPhysiNode* pStateNode = (SStreamStateWinodwPhysiNode*)pPhyNode;
356✔
5322
  int32_t                      tsSlotId = ((SColumnNode*)pStateNode->window.pTspk)->slotId;
356✔
5323
  SColumnNode*                 pColNode = (SColumnNode*)(pStateNode->pStateKey);
356✔
5324
  SStreamStateAggOperatorInfo* pInfo = taosMemoryCalloc(1, sizeof(SStreamStateAggOperatorInfo));
356!
5325
  SOperatorInfo*               pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo));
356!
5326
  if (pInfo == NULL || pOperator == NULL) {
356!
UNCOV
5327
    code = terrno;
×
UNCOV
5328
    QUERY_CHECK_CODE(code, lino, _error);
×
5329
  }
5330

5331
  pInfo->stateCol = extractColumnFromColumnNode(pColNode);
356✔
5332
  initResultSizeInfo(&pOperator->resultInfo, 4096);
356✔
5333
  if (pStateNode->window.pExprs != NULL) {
356✔
5334
    int32_t    numOfScalar = 0;
25✔
5335
    SExprInfo* pScalarExprInfo = NULL;
25✔
5336
    code = createExprInfo(pStateNode->window.pExprs, NULL, &pScalarExprInfo, &numOfScalar);
25✔
5337
    QUERY_CHECK_CODE(code, lino, _error);
25!
5338

5339
    code = initExprSupp(&pInfo->scalarSupp, pScalarExprInfo, numOfScalar, &pTaskInfo->storageAPI.functionStore);
25✔
5340
    QUERY_CHECK_CODE(code, lino, _error);
25!
5341
  }
5342

5343
  pInfo->twAggSup = (STimeWindowAggSupp){
356✔
5344
      .waterMark = pStateNode->window.watermark,
356✔
5345
      .calTrigger = pStateNode->window.triggerType,
356✔
5346
      .maxTs = INT64_MIN,
5347
      .minTs = INT64_MAX,
5348
      .deleteMark = getDeleteMark(&pStateNode->window, 0),
356✔
5349
  };
5350

5351
  code = initExecTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &pTaskInfo->window);
356✔
5352
  QUERY_CHECK_CODE(code, lino, _error);
356!
5353

5354
  SSDataBlock* pResBlock = createDataBlockFromDescNode(pPhyNode->pOutputDataBlockDesc);
356✔
5355
  QUERY_CHECK_NULL(pResBlock, code, lino, _error, terrno);
356!
5356
  pInfo->binfo.pRes = pResBlock;
356✔
5357

5358
  SExprSupp* pExpSup = &pOperator->exprSupp;
356✔
5359
  int32_t    numOfCols = 0;
356✔
5360
  SExprInfo* pExprInfo = NULL;
356✔
5361
  code = createExprInfo(pStateNode->window.pFuncs, NULL, &pExprInfo, &numOfCols);
356✔
5362
  QUERY_CHECK_CODE(code, lino, _error);
356!
5363

5364
  code = initBasicInfoEx(&pInfo->binfo, pExpSup, pExprInfo, numOfCols, pResBlock, &pTaskInfo->storageAPI.functionStore);
356✔
5365
  if (code != TSDB_CODE_SUCCESS) {
356!
UNCOV
5366
    goto _error;
×
5367
  }
5368
  int32_t keySize = sizeof(SStateKeys) + pColNode->node.resType.bytes;
356✔
5369
  int16_t type = pColNode->node.resType.type;
356✔
5370
  pInfo->primaryTsIndex = tsSlotId;
356✔
5371
  code =
5372
      initStreamAggSupporter(&pInfo->streamAggSup, pExpSup, numOfCols, 0, pTaskInfo->streamInfo.pState, keySize, type,
356✔
5373
                             &pTaskInfo->storageAPI.stateStore, pHandle, &pInfo->twAggSup, GET_TASKID(pTaskInfo),
356✔
5374
                             &pTaskInfo->storageAPI, pInfo->primaryTsIndex, STREAM_STATE_BUFF_SORT, 1);
5375
  QUERY_CHECK_CODE(code, lino, _error);
356!
5376

5377
  _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
356✔
5378
  pInfo->pSeDeleted = tSimpleHashInit(64, hashFn);
356✔
5379
  QUERY_CHECK_NULL(pInfo->pSeDeleted, code, lino, _error, terrno);
356!
5380
  pInfo->pDelIterator = NULL;
356✔
5381

5382
  code = createSpecialDataBlock(STREAM_DELETE_RESULT, &pInfo->pDelRes);
356✔
5383
  QUERY_CHECK_CODE(code, lino, _error);
356!
5384

5385
  pInfo->pChildren = NULL;
356✔
5386
  pInfo->ignoreExpiredData = pStateNode->window.igExpired;
356✔
5387
  pInfo->ignoreExpiredDataSaved = false;
356✔
5388
  pInfo->pUpdated = NULL;
356✔
5389
  pInfo->pSeUpdated = NULL;
356✔
5390
  pInfo->dataVersion = 0;
356✔
5391
  pInfo->historyWins = taosArrayInit(4, sizeof(SSessionKey));
356✔
5392
  if (!pInfo->historyWins) {
356!
UNCOV
5393
    code = terrno;
×
UNCOV
5394
    QUERY_CHECK_CODE(code, lino, _error);
×
5395
  }
5396

5397
  if (pHandle) {
356!
5398
    pInfo->isHistoryOp = (pHandle->fillHistory == STREAM_HISTORY_OPERATOR);
356✔
5399
  }
5400

5401
  code = createSpecialDataBlock(STREAM_CHECKPOINT, &pInfo->pCheckpointRes);
356✔
5402
  QUERY_CHECK_CODE(code, lino, _error);
356!
5403

5404
  pInfo->recvGetAll = false;
356✔
5405
  pInfo->pPkDeleted = tSimpleHashInit(64, hashFn);
356✔
5406
  QUERY_CHECK_NULL(pInfo->pPkDeleted, code, lino, _error, terrno);
356!
5407
  pInfo->destHasPrimaryKey = pStateNode->window.destHasPrimaryKey;
356✔
5408
  pInfo->pOperator = pOperator;
356✔
5409

5410
  setOperatorInfo(pOperator, "StreamStateAggOperator", nodeType(pPhyNode), true, OP_NOT_OPENED,
356✔
5411
                  pInfo, pTaskInfo);
5412
  // for stream
5413
  void*   buff = NULL;
356✔
5414
  int32_t len = 0;
356✔
5415
  int32_t res =
5416
      pInfo->streamAggSup.stateStore.streamStateGetInfo(pInfo->streamAggSup.pState, STREAM_STATE_OP_CHECKPOINT_NAME,
356✔
5417
                                                        strlen(STREAM_STATE_OP_CHECKPOINT_NAME), &buff, &len);
5418
  if (res == TSDB_CODE_SUCCESS) {
356✔
5419
    code = doStreamStateDecodeOpState(buff, len, pOperator, true, NULL);
1✔
5420
    taosMemoryFree(buff);
1!
5421
    QUERY_CHECK_CODE(code, lino, _error);
1!
5422
  }
5423
  initNonBlockAggSupptor(&pInfo->nbSup, NULL, NULL);
356✔
5424
  code = initStreamBasicInfo(&pInfo->basic, pOperator);
356✔
5425
  QUERY_CHECK_CODE(code, lino, _error);
356!
5426

5427
  if (pStateNode->window.triggerType == STREAM_TRIGGER_CONTINUOUS_WINDOW_CLOSE) {
356!
5428
    if (pHandle->fillHistory == STREAM_HISTORY_OPERATOR) {
×
5429
      setFillHistoryOperatorFlag(&pInfo->basic);
×
5430
    } else if (pHandle->fillHistory == STREAM_RECALCUL_OPERATOR) {
×
5431
      setRecalculateOperatorFlag(&pInfo->basic);
×
5432
    }
5433

5434
    pOperator->fpSet =
UNCOV
5435
        createOperatorFpSet(optrDummyOpenFn, doStreamStateNonblockAggNext, NULL, destroyStreamStateOperatorInfo,
×
5436
                            optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
UNCOV
5437
    setOperatorStreamStateFn(pOperator, streamStateNonblockReleaseState, streamStateNonblockReloadState);
×
5438
  } else {
5439
    pOperator->fpSet = createOperatorFpSet(optrDummyOpenFn, doStreamStateAggNext, NULL, destroyStreamStateOperatorInfo,
356✔
5440
                                           optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
5441
    setOperatorStreamStateFn(pOperator, streamStateReleaseState, streamStateReloadState);
356✔
5442
  }
5443

5444
  code = initDownStream(downstream, &pInfo->streamAggSup, pOperator->operatorType, pInfo->primaryTsIndex,
356✔
5445
                        &pInfo->twAggSup, &pInfo->basic, 0);
356✔
5446
  QUERY_CHECK_CODE(code, lino, _error);
356!
5447

5448
  code = appendDownstream(pOperator, &downstream, 1);
356✔
5449
  QUERY_CHECK_CODE(code, lino, _error);
356!
5450

5451
  pInfo->trueForLimit = pStateNode->trueForLimit;
356✔
5452

5453
  *pOptrInfo = pOperator;
356✔
5454
  return TSDB_CODE_SUCCESS;
356✔
5455

UNCOV
5456
_error:
×
UNCOV
5457
  if (pInfo != NULL) destroyStreamStateOperatorInfo(pInfo);
×
UNCOV
5458
  destroyOperatorAndDownstreams(pOperator, &downstream, 1);
×
UNCOV
5459
  pTaskInfo->code = code;
×
UNCOV
5460
  qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
UNCOV
5461
  return code;
×
5462
}
5463

5464
#ifdef BUILD_NO_CALL
5465
static void setInverFunction(SqlFunctionCtx* pCtx, int32_t num, EStreamType type) {
5466
  for (int i = 0; i < num; i++) {
5467
    if (type == STREAM_INVERT) {
5468
      fmSetInvertFunc(pCtx[i].functionId, &(pCtx[i].fpSet));
5469
    } else if (type == STREAM_NORMAL) {
5470
      fmSetNormalFunc(pCtx[i].functionId, &(pCtx[i].fpSet));
5471
    }
5472
  }
5473
}
5474
#endif
5475

5476
static int32_t doStreamIntervalAggNext(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
139,283✔
5477
  int32_t                      code = TSDB_CODE_SUCCESS;
139,283✔
5478
  int32_t                      lino = 0;
139,283✔
5479
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
139,283✔
5480
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
139,283✔
5481
  SStorageAPI*                 pAPI = &pOperator->pTaskInfo->storageAPI;
139,283✔
5482
  SExprSupp*                   pSup = &pOperator->exprSupp;
139,283✔
5483

5484
  qDebug("stask:%s  %s status: %d", GET_TASKID(pTaskInfo), getStreamOpName(pOperator->operatorType), pOperator->status);
139,283✔
5485

5486
  if (pOperator->status == OP_EXEC_DONE) {
139,287✔
5487
    (*ppRes) = NULL;
668✔
5488
    return code;
668✔
5489
  }
5490

5491
  if (pOperator->status == OP_RES_TO_RETURN) {
138,619✔
5492
    SSDataBlock* resBlock = NULL;
110,668✔
5493
    code = buildIntervalResult(pOperator, &resBlock);
110,668✔
5494
    QUERY_CHECK_CODE(code, lino, _end);
110,667!
5495
    if (resBlock != NULL) {
110,667✔
5496
      (*ppRes) = resBlock;
96,189✔
5497
      return code;
110,668✔
5498
    }
5499

5500
    if (pInfo->recvGetAll) {
14,478✔
5501
      pInfo->recvGetAll = false;
177✔
5502
      resetUnCloseWinInfo(pInfo->aggSup.pResultRowHashTable);
177✔
5503
    }
5504

5505
    if (pInfo->reCkBlock) {
14,477✔
5506
      pInfo->reCkBlock = false;
118✔
5507
      printDataBlock(pInfo->pCheckpointRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
118✔
5508
      (*ppRes) = pInfo->pCheckpointRes;
118✔
5509
      return code;
118✔
5510
    }
5511

5512
    setStreamOperatorCompleted(pOperator);
14,359✔
5513
    (*ppRes) = NULL;
14,361✔
5514
    return code;
14,361✔
5515
  }
5516

5517
  SOperatorInfo* downstream = pOperator->pDownstream[0];
27,951✔
5518

5519
  if (!pInfo->pUpdated) {
27,951✔
5520
    pInfo->pUpdated = taosArrayInit(4096, POINTER_BYTES);
25,069✔
5521
    QUERY_CHECK_NULL(pInfo->pUpdated, code, lino, _end, terrno);
25,064!
5522
  }
5523

5524
  if (!pInfo->pUpdatedMap) {
27,946✔
5525
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
25,064✔
5526
    pInfo->pUpdatedMap = tSimpleHashInit(4096, hashFn);
25,063✔
5527
    QUERY_CHECK_NULL(pInfo->pUpdatedMap, code, lino, _end, terrno);
25,069!
5528
  }
5529

5530
  while (1) {
1,135,608✔
5531
    SSDataBlock* pBlock = NULL;
1,163,559✔
5532
    code = downstream->fpSet.getNextFn(downstream, &pBlock);
1,163,559✔
5533
    QUERY_CHECK_CODE(code, lino, _end);
1,163,560✔
5534

5535
    if (pBlock == NULL) {
1,163,540✔
5536
      qDebug("===stream===return data:%s. recv datablock num:%" PRIu64, getStreamOpName(pOperator->operatorType),
25,068✔
5537
             pInfo->numOfDatapack);
5538
      pInfo->numOfDatapack = 0;
25,067✔
5539
      break;
25,067✔
5540
    }
5541

5542
    pInfo->numOfDatapack++;
1,138,472✔
5543
    printSpecDataBlock(pBlock, getStreamOpName(pOperator->operatorType), "recv", GET_TASKID(pTaskInfo));
1,138,472✔
5544
    setStreamOperatorState(&pInfo->basic, pBlock->info.type);
1,138,479✔
5545

5546
    if (pBlock->info.type == STREAM_DELETE_DATA || pBlock->info.type == STREAM_DELETE_RESULT ||
1,138,482✔
5547
        pBlock->info.type == STREAM_CLEAR) {
1,137,985✔
5548
      code = doDeleteWindows(pOperator, &pInfo->interval, pBlock, pInfo->pDelWins, pInfo->pUpdatedMap, NULL);
1,451✔
5549
      QUERY_CHECK_CODE(code, lino, _end);
1,451!
5550
      continue;
3,861✔
5551
    } else if (pBlock->info.type == STREAM_GET_ALL) {
1,137,031✔
5552
      pInfo->recvGetAll = true;
1,013✔
5553
      code = getAllIntervalWindow(pInfo->aggSup.pResultRowHashTable, pInfo->pUpdatedMap);
1,013✔
5554
      QUERY_CHECK_CODE(code, lino, _end);
1,014!
5555
      continue;
1,014✔
5556
    } else if (pBlock->info.type == STREAM_CREATE_CHILD_TABLE) {
1,136,018✔
5557
      printDataBlock(pBlock, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
2,808✔
5558
      (*ppRes) = pBlock;
2,808✔
5559
      return code;
2,863✔
5560
    } else if (pBlock->info.type == STREAM_DROP_CHILD_TABLE) {
1,133,210✔
5561
      doDeleteWindowByGroupId(pOperator, pBlock);
55✔
5562
      printDataBlock(pBlock, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
55✔
5563
      (*ppRes) = pBlock;
55✔
5564
      return code;
55✔
5565
    } else if (pBlock->info.type == STREAM_CHECKPOINT) {
1,133,155✔
5566
      pAPI->stateStore.streamStateCommit(pInfo->pState);
1,396✔
5567
      doStreamIntervalSaveCheckpoint(pOperator);
1,396✔
5568
      pInfo->reCkBlock = true;
1,396✔
5569
      code = copyDataBlock(pInfo->pCheckpointRes, pBlock);
1,396✔
5570
      QUERY_CHECK_CODE(code, lino, _end);
1,396!
5571

5572
      continue;
1,396✔
5573
    } else {
5574
      if (pBlock->info.type != STREAM_NORMAL && pBlock->info.type != STREAM_INVALID) {
1,131,759!
5575
        qDebug("===stream===%s ignore recv block. type:%d", GET_TASKID(pTaskInfo), pBlock->info.type);
×
5576
        continue;
×
5577
      }
5578
    }
5579

5580
    if (pBlock->info.type == STREAM_NORMAL && pBlock->info.version != 0) {
1,131,759✔
5581
      // set input version
5582
      pTaskInfo->version = pBlock->info.version;
326,204✔
5583
    }
5584

5585
    if (pInfo->scalarSupp.pExprInfo != NULL) {
1,131,759✔
5586
      SExprSupp* pExprSup = &pInfo->scalarSupp;
13✔
5587
      code = projectApplyFunctions(pExprSup->pExprInfo, pBlock, pBlock, pExprSup->pCtx, pExprSup->numOfExprs, NULL);
13✔
5588
      QUERY_CHECK_CODE(code, lino, _end);
13!
5589
    }
5590

5591
    // The timewindow that overlaps the timestamps of the input pBlock need to be recalculated and return to the
5592
    // caller. Note that all the time window are not close till now.
5593
    // the pDataBlock are always the same one, no need to call this again
5594
    code = setInputDataBlock(pSup, pBlock, TSDB_ORDER_ASC, MAIN_SCAN, true);
1,131,759✔
5595
    QUERY_CHECK_CODE(code, lino, _end);
1,131,768!
5596
#ifdef BUILD_NO_CALL
5597
    if (pInfo->invertible) {
5598
      setInverFunction(pSup->pCtx, pOperator->exprSupp.numOfExprs, pBlock->info.type);
5599
    }
5600
#endif
5601

5602
    code = doStreamIntervalAggImpl(pOperator, pBlock, pBlock->info.id.groupId, pInfo->pUpdatedMap, pInfo->pDeletedMap);
1,131,768✔
5603
    if (code == TSDB_CODE_STREAM_INTERNAL_ERROR) {
1,131,747!
UNCOV
5604
      pOperator->status = OP_RES_TO_RETURN;
×
UNCOV
5605
      code = TSDB_CODE_SUCCESS;
×
UNCOV
5606
      break;
×
5607
    }
5608
    QUERY_CHECK_CODE(code, lino, _end);
1,131,747!
5609
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.window.ekey);
1,131,747✔
5610
    pInfo->twAggSup.minTs = TMIN(pInfo->twAggSup.minTs, pBlock->info.window.skey);
1,131,747✔
5611
  }
5612
  pOperator->status = OP_RES_TO_RETURN;
25,067✔
5613
  if (!pInfo->destHasPrimaryKey) {
25,067✔
5614
    removeDeleteResults(pInfo->pUpdatedMap, pInfo->pDelWins);
25,055✔
5615
  }
5616
  code = closeStreamIntervalWindow(pInfo->aggSup.pResultRowHashTable, &pInfo->twAggSup, &pInfo->interval, NULL,
25,054✔
5617
                                   pInfo->pUpdatedMap, pInfo->pDelWins, pOperator);
5618
  QUERY_CHECK_CODE(code, lino, _end);
25,067!
5619

5620
  if (pInfo->destHasPrimaryKey && IS_NORMAL_INTERVAL_OP(pOperator)) {
25,067!
5621
    code = copyIntervalDeleteKey(pInfo->pDeletedMap, pInfo->pDelWins);
14✔
5622
    QUERY_CHECK_CODE(code, lino, _end);
14!
5623
  }
5624

5625
  void*   pIte = NULL;
25,067✔
5626
  int32_t iter = 0;
25,067✔
5627
  while ((pIte = tSimpleHashIterate(pInfo->pUpdatedMap, pIte, &iter)) != NULL) {
9,438,090✔
5628
    void* tmp = taosArrayPush(pInfo->pUpdated, pIte);
9,413,023✔
5629
    if (!tmp) {
9,413,023!
UNCOV
5630
      code = terrno;
×
UNCOV
5631
      QUERY_CHECK_CODE(code, lino, _end);
×
5632
    }
5633
  }
5634
  taosArraySort(pInfo->pUpdated, winPosCmprImpl);
25,069✔
5635

5636
  initMultiResInfoFromArrayList(&pInfo->groupResInfo, pInfo->pUpdated);
25,070✔
5637
  pInfo->pUpdated = NULL;
25,070✔
5638
  code = blockDataEnsureCapacity(pInfo->binfo.pRes, pOperator->resultInfo.capacity);
25,070✔
5639
  QUERY_CHECK_CODE(code, lino, _end);
25,069!
5640

5641
  tSimpleHashCleanup(pInfo->pUpdatedMap);
25,069✔
5642
  pInfo->pUpdatedMap = NULL;
25,070✔
5643

5644
  code = buildIntervalResult(pOperator, ppRes);
25,070✔
5645
  QUERY_CHECK_CODE(code, lino, _end);
25,070!
5646

5647
  return code;
25,070✔
5648

5649
_end:
20✔
5650
  if (code != TSDB_CODE_SUCCESS) {
20!
5651
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
20!
5652
    pTaskInfo->code = code;
20✔
5653
    T_LONG_JMP(pTaskInfo->env, code);
20!
5654
  }
UNCOV
5655
  setStreamOperatorCompleted(pOperator);
×
UNCOV
5656
  (*ppRes) = NULL;
×
UNCOV
5657
  return code;
×
5658
}
5659

5660
int32_t createStreamSingleIntervalOperatorInfo(SOperatorInfo* downstream, SPhysiNode* pPhyNode,
3,071✔
5661
                                               SExecTaskInfo* pTaskInfo, SReadHandle* pHandle,
5662
                                               SOperatorInfo** pOptrInfo) {
5663
  QRY_PARAM_CHECK(pOptrInfo);
3,071!
5664

5665
  int32_t code = TSDB_CODE_SUCCESS;
3,071✔
5666
  int32_t lino = 0;
3,071✔
5667
  int32_t numOfCols = 0;
3,071✔
5668

5669
  SStreamIntervalOperatorInfo* pInfo = taosMemoryCalloc(1, sizeof(SStreamIntervalOperatorInfo));
3,071!
5670
  SOperatorInfo*               pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo));
3,071!
5671
  if (pInfo == NULL || pOperator == NULL) {
3,071!
UNCOV
5672
    code = terrno;
×
UNCOV
5673
    QUERY_CHECK_CODE(code, lino, _error);
×
5674
  }
5675

5676
  SStreamIntervalPhysiNode* pIntervalPhyNode = (SStreamIntervalPhysiNode*)pPhyNode;
3,071✔
5677

5678
  SSDataBlock* pResBlock = createDataBlockFromDescNode(pPhyNode->pOutputDataBlockDesc);
3,071✔
5679
  QUERY_CHECK_NULL(pResBlock, code, lino, _error, terrno);
3,071!
5680
  initBasicInfo(&pInfo->binfo, pResBlock);
3,071✔
5681

5682
  pInfo->interval = (SInterval){
3,071✔
5683
      .interval = pIntervalPhyNode->interval,
3,071✔
5684
      .sliding = pIntervalPhyNode->sliding,
3,071✔
5685
      .intervalUnit = pIntervalPhyNode->intervalUnit,
3,071✔
5686
      .slidingUnit = pIntervalPhyNode->slidingUnit,
3,071✔
5687
      .offset = pIntervalPhyNode->offset,
3,071✔
5688
      .precision = ((SColumnNode*)pIntervalPhyNode->window.pTspk)->node.resType.precision,
3,071✔
5689
      .timeRange = pIntervalPhyNode->timeRange,
3,071✔
5690
  };
5691
  calcIntervalAutoOffset(&pInfo->interval);
3,071✔
5692

5693
  pInfo->twAggSup =
3,071✔
5694
      (STimeWindowAggSupp){.waterMark = pIntervalPhyNode->window.watermark,
3,071✔
5695
                           .calTrigger = pIntervalPhyNode->window.triggerType,
3,071✔
5696
                           .maxTs = INT64_MIN,
5697
                           .minTs = INT64_MAX,
5698
                           .deleteMark = getDeleteMark(&pIntervalPhyNode->window, pIntervalPhyNode->interval)};
3,071✔
5699

5700
  pOperator->pTaskInfo = pTaskInfo;
3,071✔
5701
  SStorageAPI* pAPI = &pOperator->pTaskInfo->storageAPI;
3,071✔
5702

5703
  pInfo->ignoreExpiredData = pIntervalPhyNode->window.igExpired;
3,071✔
5704
  pInfo->ignoreExpiredDataSaved = false;
3,071✔
5705

5706
  SExprSupp* pSup = &pOperator->exprSupp;
3,071✔
5707
  pSup->hasWindowOrGroup = true;
3,071✔
5708

5709
  code = initExecTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &pTaskInfo->window);
3,071✔
5710
  QUERY_CHECK_CODE(code, lino, _error);
3,071!
5711

5712
  pInfo->primaryTsIndex = ((SColumnNode*)pIntervalPhyNode->window.pTspk)->slotId;
3,071✔
5713
  initResultSizeInfo(&pOperator->resultInfo, 4096);
3,071✔
5714

5715
  pInfo->pState = taosMemoryCalloc(1, sizeof(SStreamState));
3,071!
5716
  QUERY_CHECK_NULL(pInfo->pState, code, lino, _error, terrno);
3,071!
5717
  *(pInfo->pState) = *(pTaskInfo->streamInfo.pState);
3,071✔
5718
  pAPI->stateStore.streamStateSetNumber(pInfo->pState, -1, pInfo->primaryTsIndex);
3,071✔
5719

5720
  size_t     keyBufSize = sizeof(int64_t) + sizeof(int64_t) + POINTER_BYTES;
3,071✔
5721
  SExprInfo* pExprInfo = NULL;
3,071✔
5722
  code = createExprInfo(pIntervalPhyNode->window.pFuncs, NULL, &pExprInfo, &numOfCols);
3,071✔
5723
  QUERY_CHECK_CODE(code, lino, _error);
3,070!
5724
  code = initAggSup(pSup, &pInfo->aggSup, pExprInfo, numOfCols, keyBufSize, pTaskInfo->id.str, pInfo->pState,
3,070✔
5725
                    &pTaskInfo->storageAPI.functionStore);
5726
  QUERY_CHECK_CODE(code, lino, _error);
3,070!
5727

5728
  if (pIntervalPhyNode->window.pExprs != NULL) {
3,070✔
5729
    int32_t    numOfScalar = 0;
1✔
5730
    SExprInfo* pScalarExprInfo = NULL;
1✔
5731

5732
    code = createExprInfo(pIntervalPhyNode->window.pExprs, NULL, &pScalarExprInfo, &numOfScalar);
1✔
5733
    QUERY_CHECK_CODE(code, lino, _error);
1!
5734

5735
    code = initExprSupp(&pInfo->scalarSupp, pScalarExprInfo, numOfScalar, &pTaskInfo->storageAPI.functionStore);
1✔
5736
    QUERY_CHECK_CODE(code, lino, _error);
1!
5737
  }
5738

5739
  pInfo->invertible = false;
3,070✔
5740
  pInfo->pDelWins = taosArrayInit(4, sizeof(SWinKey));
3,070✔
5741
  QUERY_CHECK_NULL(pInfo->pDelWins, code, lino, _error, terrno);
3,071!
5742
  pInfo->delIndex = 0;
3,071✔
5743

5744
  code = createSpecialDataBlock(STREAM_DELETE_RESULT, &pInfo->pDelRes);
3,071✔
5745
  QUERY_CHECK_CODE(code, lino, _error);
3,071!
5746

5747
  initResultRowInfo(&pInfo->binfo.resultRowInfo);
3,071✔
5748

5749
  pInfo->pPhyNode = NULL;  // create new child
3,071✔
5750
  pInfo->pPullDataMap = NULL;
3,071✔
5751
  pInfo->pFinalPullDataMap = NULL;
3,071✔
5752
  pInfo->pPullWins = NULL;  // SPullWindowInfo
3,071✔
5753
  pInfo->pullIndex = 0;
3,071✔
5754
  pInfo->pPullDataRes = NULL;
3,071✔
5755
  pInfo->numOfChild = 0;
3,071✔
5756
  pInfo->delKey.ts = INT64_MAX;
3,071✔
5757
  pInfo->delKey.groupId = 0;
3,071✔
5758
  pInfo->numOfDatapack = 0;
3,071✔
5759
  pInfo->pUpdated = NULL;
3,071✔
5760
  pInfo->pUpdatedMap = NULL;
3,071✔
5761
  int32_t funResSize = getMaxFunResSize(pSup, numOfCols);
3,071✔
5762

5763
  pInfo->stateStore = pTaskInfo->storageAPI.stateStore;
3,071✔
5764
  pInfo->pState->pFileState = NULL;
3,071✔
5765

5766
  // used for backward compatibility of function's result info
5767
  pInfo->pState->pResultRowStore.resultRowGet = getResultRowFromBuf;
3,071✔
5768
  pInfo->pState->pResultRowStore.resultRowPut = putResultRowToBuf;
3,071✔
5769
  pInfo->pState->pExprSupp = &pOperator->exprSupp;
3,071✔
5770

5771
  code = pTaskInfo->storageAPI.stateStore.streamFileStateInit(
3,071✔
5772
      tsStreamBufferSize, sizeof(SWinKey), pInfo->aggSup.resultRowSize, funResSize, compareTs, pInfo->pState,
3,071✔
5773
      pInfo->twAggSup.deleteMark, GET_TASKID(pTaskInfo), pHandle->checkpointId, STREAM_STATE_BUFF_HASH,
3,071✔
5774
      &pInfo->pState->pFileState);
3,071✔
5775
  QUERY_CHECK_CODE(code, lino, _error);
3,071!
5776

5777
  pInfo->pOperator = pOperator;
3,071✔
5778
  setOperatorInfo(pOperator, "StreamIntervalOperator", QUERY_NODE_PHYSICAL_PLAN_STREAM_INTERVAL, true, OP_NOT_OPENED,
3,071✔
5779
                  pInfo, pTaskInfo);
5780
  pOperator->fpSet =
5781
      createOperatorFpSet(optrDummyOpenFn, doStreamIntervalAggNext, NULL, destroyStreamFinalIntervalOperatorInfo,
3,070✔
5782
                          optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
5783
  setOperatorStreamStateFn(pOperator, streamIntervalReleaseState, streamIntervalReloadState);
3,071✔
5784

5785
  code = initStreamBasicInfo(&pInfo->basic, pOperator);
3,071✔
5786
  QUERY_CHECK_CODE(code, lino, _error);
3,071!
5787

5788
  pInfo->recvGetAll = false;
3,071✔
5789

5790
  code = createSpecialDataBlock(STREAM_CHECKPOINT, &pInfo->pCheckpointRes);
3,071✔
5791
  QUERY_CHECK_CODE(code, lino, _error);
3,071!
5792

5793
  _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
3,071✔
5794
  pInfo->pDeletedMap = tSimpleHashInit(4096, hashFn);
3,071✔
5795
  QUERY_CHECK_NULL(pInfo->pDeletedMap, code, lino, _error, terrno);
3,071!
5796
  pInfo->destHasPrimaryKey = pIntervalPhyNode->window.destHasPrimaryKey;
3,071✔
5797

5798
  // for stream
5799
  void*   buff = NULL;
3,071✔
5800
  int32_t len = 0;
3,071✔
5801
  int32_t res = pAPI->stateStore.streamStateGetInfo(pInfo->pState, STREAM_INTERVAL_OP_CHECKPOINT_NAME,
3,071✔
5802
                                                    strlen(STREAM_INTERVAL_OP_CHECKPOINT_NAME), &buff, &len);
5803
  if (res == TSDB_CODE_SUCCESS) {
3,071✔
5804
    doStreamIntervalDecodeOpState(buff, len, pOperator);
23✔
5805
    taosMemoryFree(buff);
23!
5806
  }
5807

5808
  pInfo->basic.primaryPkIndex = -1;
3,071✔
5809
  code = initIntervalDownStream(downstream, pPhyNode->type, pInfo, &pInfo->basic);
3,071✔
5810
  QUERY_CHECK_CODE(code, lino, _error);
3,071!
5811

5812
  code = appendDownstream(pOperator, &downstream, 1);
3,071✔
5813
  QUERY_CHECK_CODE(code, lino, _error);
3,071!
5814

5815
  *pOptrInfo = pOperator;
3,071✔
5816
  return TSDB_CODE_SUCCESS;
3,071✔
5817

UNCOV
5818
_error:
×
UNCOV
5819
  if (pInfo != NULL) destroyStreamFinalIntervalOperatorInfo(pInfo);
×
UNCOV
5820
  destroyOperatorAndDownstreams(pOperator, &downstream, 1);
×
UNCOV
5821
  pTaskInfo->code = code;
×
UNCOV
5822
  return code;
×
5823
}
5824

5825
static void doStreamMidIntervalAggImpl(SOperatorInfo* pOperator, SSDataBlock* pSDataBlock, SSHashObj* pUpdatedMap) {
38✔
5826
  int32_t                      code = TSDB_CODE_SUCCESS;
38✔
5827
  int32_t                      lino = 0;
38✔
5828
  SStreamIntervalOperatorInfo* pInfo = (SStreamIntervalOperatorInfo*)pOperator->info;
38✔
5829
  pInfo->dataVersion = TMAX(pInfo->dataVersion, pSDataBlock->info.version);
38✔
5830

5831
  SResultRowInfo*  pResultRowInfo = &(pInfo->binfo.resultRowInfo);
38✔
5832
  SExecTaskInfo*   pTaskInfo = pOperator->pTaskInfo;
38✔
5833
  SExprSupp*       pSup = &pOperator->exprSupp;
38✔
5834
  int32_t          numOfOutput = pSup->numOfExprs;
38✔
5835
  int32_t          step = 1;
38✔
5836
  SRowBuffPos*     pResPos = NULL;
38✔
5837
  SResultRow*      pResult = NULL;
38✔
5838
  int32_t          forwardRows = 1;
38✔
5839
  uint64_t         groupId = pSDataBlock->info.id.groupId;
38✔
5840
  SColumnInfoData* pColDataInfo = taosArrayGet(pSDataBlock->pDataBlock, pInfo->primaryTsIndex);
38✔
5841
  TSKEY*           tsCol = (int64_t*)pColDataInfo->pData;
38✔
5842

5843
  int32_t     startPos = 0;
38✔
5844
  TSKEY       ts = getStartTsKey(&pSDataBlock->info.window, tsCol);
38✔
5845
  STimeWindow nextWin = getFinalTimeWindow(ts, &pInfo->interval);
38✔
5846

5847
  while (1) {
1,266✔
5848
    SWinKey key = {
1,304✔
5849
        .ts = nextWin.skey,
1,304✔
5850
        .groupId = groupId,
5851
    };
5852
    void*   chIds = taosHashGet(pInfo->pPullDataMap, &key, sizeof(SWinKey));
1,304✔
5853
    int32_t index = -1;
1,304✔
5854
    SArray* chArray = NULL;
1,304✔
5855
    int32_t chId = 0;
1,304✔
5856
    if (chIds) {
1,304✔
5857
      chArray = *(void**)chIds;
4✔
5858
      chId = getChildIndex(pSDataBlock);
4✔
5859
      index = taosArraySearchIdx(chArray, &chId, compareInt32Val, TD_EQ);
4✔
5860
    }
5861
    if (!(index == -1 || pSDataBlock->info.type == STREAM_PULL_DATA)) {
1,304!
UNCOV
5862
      startPos = getNextQualifiedFinalWindow(&pInfo->interval, &nextWin, &pSDataBlock->info, tsCol, startPos);
×
UNCOV
5863
      if (startPos < 0) {
×
5864
        break;
38✔
5865
      }
UNCOV
5866
      continue;
×
5867
    }
5868

5869
    if (!inSlidingWindow(&pInfo->interval, &nextWin, &pSDataBlock->info)) {
1,304!
UNCOV
5870
      startPos = getNexWindowPos(&pInfo->interval, &pSDataBlock->info, tsCol, startPos, nextWin.ekey, &nextWin);
×
5871
      if (startPos < 0) {
×
5872
        break;
×
5873
      }
UNCOV
5874
      continue;
×
5875
    }
5876

5877
    int32_t winCode = TSDB_CODE_SUCCESS;
1,304✔
5878
    code = setIntervalOutputBuf(pInfo->pState, &nextWin, &pResPos, groupId, pSup->pCtx, numOfOutput,
1,304✔
5879
                                pSup->rowEntryInfoOffset, &pInfo->aggSup, &pInfo->stateStore, &winCode);
5880
    QUERY_CHECK_CODE(code, lino, _end);
1,304!
5881

5882
    pResult = (SResultRow*)pResPos->pRowBuff;
1,304✔
5883

5884
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_AT_ONCE) {
1,304!
5885
      code = saveWinResult(&key, pResPos, pUpdatedMap);
1,304✔
5886
      QUERY_CHECK_CODE(code, lino, _end);
1,304!
5887
    }
5888

5889
    if (pInfo->twAggSup.calTrigger == STREAM_TRIGGER_WINDOW_CLOSE) {
1,304!
5890
      code = tSimpleHashPut(pInfo->aggSup.pResultRowHashTable, &key, sizeof(SWinKey), &pResPos, POINTER_BYTES);
×
UNCOV
5891
      QUERY_CHECK_CODE(code, lino, _end);
×
5892
    }
5893

5894
    updateTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &nextWin, 1);
1,304✔
5895
    code = applyAggFunctionOnPartialTuples(pTaskInfo, pSup->pCtx, &pInfo->twAggSup.timeWindowData, startPos,
1,304✔
5896
                                           forwardRows, pSDataBlock->info.rows, numOfOutput);
1,304✔
5897
    QUERY_CHECK_CODE(code, lino, _end);
1,304!
5898
    key.ts = nextWin.skey;
1,304✔
5899

5900
    if (pInfo->delKey.ts > key.ts) {
1,304✔
5901
      pInfo->delKey = key;
10✔
5902
    }
5903
    int32_t prevEndPos = (forwardRows - 1) * step + startPos;
1,304✔
5904
    if (pSDataBlock->info.window.skey <= 0 || pSDataBlock->info.window.ekey <= 0) {
1,304!
UNCOV
5905
      qError("table uid %" PRIu64 " data block timestamp range may not be calculated! minKey %" PRId64
×
5906
             ",maxKey %" PRId64,
5907
             pSDataBlock->info.id.uid, pSDataBlock->info.window.skey, pSDataBlock->info.window.ekey);
UNCOV
5908
      code = blockDataUpdateTsWindow(pSDataBlock, 0);
×
UNCOV
5909
      QUERY_CHECK_CODE(code, lino, _end);
×
5910

5911
      // timestamp of the data is incorrect
UNCOV
5912
      if (pSDataBlock->info.window.skey <= 0 || pSDataBlock->info.window.ekey <= 0) {
×
UNCOV
5913
        qError("table uid %" PRIu64 " data block timestamp is out of range! minKey %" PRId64 ",maxKey %" PRId64,
×
5914
               pSDataBlock->info.id.uid, pSDataBlock->info.window.skey, pSDataBlock->info.window.ekey);
5915
      }
5916
    }
5917
    startPos = getNextQualifiedFinalWindow(&pInfo->interval, &nextWin, &pSDataBlock->info, tsCol, prevEndPos);
1,304✔
5918
    if (startPos < 0) {
1,304✔
5919
      break;
38✔
5920
    }
5921
  }
5922

5923
_end:
38✔
5924
  if (code != TSDB_CODE_SUCCESS) {
38!
5925
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
5926
  }
5927
}
38✔
5928

5929
static int32_t addMidRetriveWindow(SArray* wins, SHashObj* pMidPullMap, int32_t numOfChild) {
12✔
5930
  int32_t code = TSDB_CODE_SUCCESS;
12✔
5931
  int32_t lino = 0;
12✔
5932
  int32_t size = taosArrayGetSize(wins);
12✔
5933
  for (int32_t i = 0; i < size; i++) {
18✔
5934
    SWinKey* winKey = taosArrayGet(wins, i);
6✔
5935
    void*    chIds = taosHashGet(pMidPullMap, winKey, sizeof(SWinKey));
6✔
5936
    if (!chIds) {
6!
5937
      code = addPullWindow(pMidPullMap, winKey, numOfChild);
6✔
5938
      qDebug("===stream===prepare mid operator retrive for delete %" PRId64 ", size:%d", winKey->ts, numOfChild);
6!
5939
      QUERY_CHECK_CODE(code, lino, _end);
6!
5940
    }
5941
  }
5942
_end:
12✔
5943
  if (code != TSDB_CODE_SUCCESS) {
12!
UNCOV
5944
    qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
×
5945
  }
5946
  return code;
12✔
5947
}
5948

5949
static SSDataBlock* buildMidIntervalResult(SOperatorInfo* pOperator) {
106✔
5950
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
106✔
5951
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
106✔
5952
  uint16_t                     opType = pOperator->operatorType;
106✔
5953

5954
  if (pInfo->recvPullover) {
106✔
5955
    pInfo->recvPullover = false;
6✔
5956
    printDataBlock(pInfo->pMidPulloverRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
6✔
5957
    return pInfo->pMidPulloverRes;
6✔
5958
  }
5959

5960
  qDebug("===stream=== build mid interval result");
100!
5961
  doBuildDeleteResult(pTaskInfo, pInfo->pMidPullDatas, &pInfo->midDelIndex, pInfo->pDelRes);
100✔
5962
  if (pInfo->pDelRes->info.rows != 0) {
100!
5963
    // process the rest of the data
UNCOV
5964
    printDataBlock(pInfo->pDelRes, getStreamOpName(opType), GET_TASKID(pTaskInfo));
×
UNCOV
5965
    return pInfo->pDelRes;
×
5966
  }
5967

5968
  if (pInfo->recvRetrive) {
100✔
5969
    pInfo->recvRetrive = false;
12✔
5970
    printDataBlock(pInfo->pMidRetriveRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
12✔
5971
    return pInfo->pMidRetriveRes;
12✔
5972
  }
5973

5974
  return NULL;
88✔
5975
}
5976

5977
static int32_t doStreamMidIntervalAggNext(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
105✔
5978
  int32_t                      code = TSDB_CODE_SUCCESS;
105✔
5979
  int32_t                      lino = 0;
105✔
5980
  SStreamIntervalOperatorInfo* pInfo = pOperator->info;
105✔
5981
  SExecTaskInfo*               pTaskInfo = pOperator->pTaskInfo;
105✔
5982
  SStorageAPI*                 pAPI = &pOperator->pTaskInfo->storageAPI;
105✔
5983
  SOperatorInfo*               downstream = pOperator->pDownstream[0];
105✔
5984
  SExprSupp*                   pSup = &pOperator->exprSupp;
105✔
5985

5986
  qDebug("stask:%s  %s status: %d", GET_TASKID(pTaskInfo), getStreamOpName(pOperator->operatorType), pOperator->status);
105!
5987

5988
  if (pOperator->status == OP_EXEC_DONE) {
105!
UNCOV
5989
    (*ppRes) = NULL;
×
UNCOV
5990
    return code;
×
5991
  } else if (pOperator->status == OP_RES_TO_RETURN) {
105✔
5992
    SSDataBlock* resBlock = NULL;
35✔
5993
    code = buildIntervalResult(pOperator, &resBlock);
35✔
5994
    QUERY_CHECK_CODE(code, lino, _end);
35!
5995
    if (resBlock != NULL) {
35✔
5996
      (*ppRes) = resBlock;
10✔
5997
      return code;
35✔
5998
    }
5999

6000
    setOperatorCompleted(pOperator);
25✔
6001
    clearFunctionContext(&pOperator->exprSupp);
25✔
6002
    clearStreamIntervalOperator(pInfo);
25✔
6003
    qDebug("stask:%s  ===stream===%s clear", GET_TASKID(pTaskInfo), getStreamOpName(pOperator->operatorType));
25!
6004
    (*ppRes) = NULL;
25✔
6005
    return code;
25✔
6006
  } else {
6007
    SSDataBlock* resBlock = NULL;
70✔
6008
    code = buildIntervalResult(pOperator, &resBlock);
70✔
6009
    QUERY_CHECK_CODE(code, lino, _end);
70!
6010
    if (resBlock != NULL) {
70!
UNCOV
6011
      (*ppRes) = resBlock;
×
6012
      return code;
3✔
6013
    }
6014

6015
    resBlock = buildMidIntervalResult(pOperator);
70✔
6016
    if (resBlock != NULL) {
70✔
6017
      (*ppRes) = resBlock;
3✔
6018
      return code;
3✔
6019
    }
6020

6021
    if (pInfo->clearState) {
67✔
6022
      pInfo->clearState = false;
18✔
6023
      clearFunctionContext(&pOperator->exprSupp);
18✔
6024
      clearStreamIntervalOperator(pInfo);
18✔
6025
    }
6026
  }
6027

6028
  if (!pInfo->pUpdated) {
67✔
6029
    pInfo->pUpdated = taosArrayInit(4096, POINTER_BYTES);
64✔
6030
    QUERY_CHECK_NULL(pInfo->pUpdated, code, lino, _end, terrno);
64!
6031
  }
6032
  if (!pInfo->pUpdatedMap) {
67✔
6033
    _hash_fn_t hashFn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY);
64✔
6034
    pInfo->pUpdatedMap = tSimpleHashInit(4096, hashFn);
64✔
6035
    QUERY_CHECK_NULL(pInfo->pUpdatedMap, code, lino, _end, terrno);
64!
6036
  }
6037

6038
  while (1) {
54✔
6039
    if (isTaskKilled(pTaskInfo)) {
121!
UNCOV
6040
      qInfo("===stream=== %s task is killed, code %s", GET_TASKID(pTaskInfo), tstrerror(pTaskInfo->code));
×
UNCOV
6041
      (*ppRes) = NULL;
×
6042
      return code;
3✔
6043
    }
6044

6045
    SSDataBlock* pBlock = NULL;
121✔
6046
    code = downstream->fpSet.getNextFn(downstream, &pBlock);
121✔
6047
    QUERY_CHECK_CODE(code, lino, _end);
121!
6048

6049
    if (pBlock == NULL) {
121✔
6050
      pOperator->status = OP_RES_TO_RETURN;
46✔
6051
      qDebug("===stream===return data:%s. recv datablock num:%" PRIu64, getStreamOpName(pOperator->operatorType),
46!
6052
             pInfo->numOfDatapack);
6053
      pInfo->numOfDatapack = 0;
46✔
6054
      break;
46✔
6055
    }
6056
    pInfo->numOfDatapack++;
75✔
6057
    printSpecDataBlock(pBlock, getStreamOpName(pOperator->operatorType), "recv", GET_TASKID(pTaskInfo));
75✔
6058
    setStreamOperatorState(&pInfo->basic, pBlock->info.type);
75✔
6059

6060
    if (pBlock->info.type == STREAM_NORMAL || pBlock->info.type == STREAM_PULL_DATA) {
75✔
6061
      pInfo->binfo.pRes->info.type = pBlock->info.type;
8✔
6062
    } else if (pBlock->info.type == STREAM_DELETE_DATA || pBlock->info.type == STREAM_DELETE_RESULT ||
67!
6063
               pBlock->info.type == STREAM_CLEAR) {
65✔
6064
      SArray* delWins = taosArrayInit(8, sizeof(SWinKey));
3✔
6065
      if (!delWins) {
3!
UNCOV
6066
        code = terrno;
×
UNCOV
6067
        QUERY_CHECK_CODE(code, lino, _end);
×
6068
      }
6069
      code =
6070
          doDeleteWindows(pOperator, &pInfo->interval, pBlock, delWins, pInfo->pUpdatedMap, pInfo->pFinalPullDataMap);
3✔
6071
      QUERY_CHECK_CODE(code, lino, _end);
3!
6072

6073
      removeResults(delWins, pInfo->pUpdatedMap);
3✔
6074
      void* tmp = taosArrayAddAll(pInfo->pDelWins, delWins);
3✔
6075
      if (!tmp && taosArrayGetSize(delWins) > 0) {
3!
6076
        code = TSDB_CODE_OUT_OF_MEMORY;
×
6077
        QUERY_CHECK_CODE(code, lino, _end);
×
6078
      }
6079
      taosArrayDestroy(delWins);
3✔
6080

6081
      doBuildDeleteResult(pTaskInfo, pInfo->pDelWins, &pInfo->delIndex, pInfo->pDelRes);
3✔
6082
      if (pInfo->pDelRes->info.rows != 0) {
3!
6083
        // process the rest of the data
6084
        printDataBlock(pInfo->pDelRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
3✔
6085
        if (pBlock->info.type == STREAM_CLEAR) {
3✔
6086
          pInfo->pDelRes->info.type = STREAM_CLEAR;
1✔
6087
        } else {
6088
          pInfo->pDelRes->info.type = STREAM_DELETE_RESULT;
2✔
6089
        }
6090
        (*ppRes) = pInfo->pDelRes;
3✔
6091
        return code;
3✔
6092
      }
6093
      continue;
16✔
6094
    } else if (pBlock->info.type == STREAM_CREATE_CHILD_TABLE) {
64!
UNCOV
6095
      (*ppRes) = pBlock;
×
UNCOV
6096
      return code;
×
6097
    } else if (pBlock->info.type == STREAM_PULL_OVER) {
64✔
6098
      code = processPullOver(pBlock, pInfo->pPullDataMap, pInfo->pFinalPullDataMap, &pInfo->interval, pInfo->pPullWins,
12✔
6099
                             pInfo->numOfChild, pOperator, &pInfo->recvPullover);
6100
      QUERY_CHECK_CODE(code, lino, _end);
12!
6101

6102
      if (pInfo->recvPullover) {
12✔
6103
        code = copyDataBlock(pInfo->pMidPulloverRes, pBlock);
6✔
6104
        QUERY_CHECK_CODE(code, lino, _end);
6!
6105

6106
        pInfo->clearState = true;
6✔
6107
        break;
6✔
6108
      }
6109
      continue;
6✔
6110
    } else if (pBlock->info.type == STREAM_CHECKPOINT) {
52✔
6111
      pAPI->stateStore.streamStateCommit(pInfo->pState);
10✔
6112
      doStreamIntervalSaveCheckpoint(pOperator);
10✔
6113
      code = copyDataBlock(pInfo->pCheckpointRes, pBlock);
10✔
6114
      QUERY_CHECK_CODE(code, lino, _end);
10!
6115

6116
      continue;
10✔
6117
    } else if (pBlock->info.type == STREAM_MID_RETRIEVE) {
42✔
6118
      SArray* delWins = taosArrayInit(8, sizeof(SWinKey));
12✔
6119
      if (!delWins) {
12!
6120
        code = terrno;
×
6121
        QUERY_CHECK_CODE(code, lino, _end);
×
6122
      }
6123
      code = doDeleteWindows(pOperator, &pInfo->interval, pBlock, delWins, pInfo->pUpdatedMap, NULL);
12✔
6124
      QUERY_CHECK_CODE(code, lino, _end);
12!
6125

6126
      code = addMidRetriveWindow(delWins, pInfo->pPullDataMap, pInfo->numOfChild);
12✔
6127
      QUERY_CHECK_CODE(code, lino, _end);
12!
6128

6129
      taosArrayDestroy(delWins);
12✔
6130
      pInfo->recvRetrive = true;
12✔
6131
      code = copyDataBlock(pInfo->pMidRetriveRes, pBlock);
12✔
6132
      QUERY_CHECK_CODE(code, lino, _end);
12!
6133

6134
      pInfo->pMidRetriveRes->info.type = STREAM_MID_RETRIEVE;
12✔
6135
      pInfo->clearState = true;
12✔
6136
      break;
12✔
6137
    } else {
6138
      if (pBlock->info.type != STREAM_INVALID) {
30!
UNCOV
6139
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
UNCOV
6140
        QUERY_CHECK_CODE(code, lino, _end);
×
6141
      }
6142
    }
6143

6144
    if (pInfo->scalarSupp.pExprInfo != NULL) {
38!
UNCOV
6145
      SExprSupp* pExprSup = &pInfo->scalarSupp;
×
6146
      code = projectApplyFunctions(pExprSup->pExprInfo, pBlock, pBlock, pExprSup->pCtx, pExprSup->numOfExprs, NULL);
×
6147
      QUERY_CHECK_CODE(code, lino, _end);
×
6148
    }
6149
    code = setInputDataBlock(pSup, pBlock, TSDB_ORDER_ASC, MAIN_SCAN, true);
38✔
6150
    QUERY_CHECK_CODE(code, lino, _end);
38!
6151
    doStreamMidIntervalAggImpl(pOperator, pBlock, pInfo->pUpdatedMap);
38✔
6152
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.window.ekey);
38✔
6153
    pInfo->twAggSup.maxTs = TMAX(pInfo->twAggSup.maxTs, pBlock->info.watermark);
38✔
6154
    pInfo->twAggSup.minTs = TMIN(pInfo->twAggSup.minTs, pBlock->info.window.skey);
38✔
6155
  }
6156

6157
  removeDeleteResults(pInfo->pUpdatedMap, pInfo->pDelWins);
64✔
6158
  pInfo->binfo.pRes->info.watermark = pInfo->twAggSup.maxTs;
64✔
6159

6160
  void*   pIte = NULL;
64✔
6161
  int32_t iter = 0;
64✔
6162
  while ((pIte = tSimpleHashIterate(pInfo->pUpdatedMap, pIte, &iter)) != NULL) {
1,368✔
6163
    void* tmp = taosArrayPush(pInfo->pUpdated, pIte);
1,304✔
6164
    if (!tmp) {
1,304!
UNCOV
6165
      code = terrno;
×
UNCOV
6166
      QUERY_CHECK_CODE(code, lino, _end);
×
6167
    }
6168
  }
6169

6170
  tSimpleHashCleanup(pInfo->pUpdatedMap);
64✔
6171
  pInfo->pUpdatedMap = NULL;
64✔
6172
  taosArraySort(pInfo->pUpdated, winPosCmprImpl);
64✔
6173

6174
  initMultiResInfoFromArrayList(&pInfo->groupResInfo, pInfo->pUpdated);
64✔
6175
  pInfo->pUpdated = NULL;
64✔
6176
  code = blockDataEnsureCapacity(pInfo->binfo.pRes, pOperator->resultInfo.capacity);
64✔
6177
  QUERY_CHECK_CODE(code, lino, _end);
64!
6178

6179
  SSDataBlock* resBlock = NULL;
64✔
6180
  code = buildIntervalResult(pOperator, &resBlock);
64✔
6181
  QUERY_CHECK_CODE(code, lino, _end);
64!
6182
  if (resBlock != NULL) {
64✔
6183
    (*ppRes) = resBlock;
28✔
6184
    return code;
28✔
6185
  }
6186

6187
  resBlock = buildMidIntervalResult(pOperator);
36✔
6188
  if (resBlock != NULL) {
36✔
6189
    (*ppRes) = resBlock;
15✔
6190
    return code;
15✔
6191
  }
6192

6193
  if (pInfo->clearState) {
21!
UNCOV
6194
    pInfo->clearState = false;
×
UNCOV
6195
    clearFunctionContext(&pOperator->exprSupp);
×
UNCOV
6196
    clearStreamIntervalOperator(pInfo);
×
6197
  }
6198

6199
_end:
21✔
6200
  if (code != TSDB_CODE_SUCCESS) {
21!
UNCOV
6201
    qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
×
UNCOV
6202
    pTaskInfo->code = code;
×
UNCOV
6203
    T_LONG_JMP(pTaskInfo->env, code);
×
6204
  }
6205
  (*ppRes) = NULL;
21✔
6206
  return code;
21✔
6207
}
6208

UNCOV
6209
static SSDataBlock* doStreamMidIntervalAgg(SOperatorInfo* pOperator) {
×
UNCOV
6210
  SSDataBlock* pRes = NULL;
×
UNCOV
6211
  int32_t      code = doStreamMidIntervalAggNext(pOperator, &pRes);
×
UNCOV
6212
  return pRes;
×
6213
}
6214

6215
void setStreamOperatorCompleted(SOperatorInfo* pOperator) {
35,929✔
6216
  qDebug("stask:%s  %s status: %d. set completed", GET_TASKID(pOperator->pTaskInfo),
35,929✔
6217
         getStreamOpName(pOperator->operatorType), pOperator->status);
6218
  setOperatorCompleted(pOperator);
35,929✔
6219
}
35,933✔
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