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

16
#include "builtinsimpl.h"
17
#include "cJSON.h"
18
#include "decimal.h"
19
#include "function.h"
20
#include "functionResInfoInt.h"
21
#include "query.h"
22
#include "querynodes.h"
23
#include "tanalytics.h"
24
#include "tcompare.h"
25
#include "tdatablock.h"
26
#include "tdigest.h"
27
#include "tfunctionInt.h"
28
#include "tglobal.h"
29
#include "thistogram.h"
30
#include "tpercentile.h"
31

32
bool ignoreNegative(int8_t ignoreOption) { return (ignoreOption & 0x1) == 0x1; }
1,250,846,137✔
33
bool ignoreNull(int8_t ignoreOption) { return (ignoreOption & 0x2) == 0x2; }
1,516,381✔
34

35
typedef enum {
36
  APERCT_ALGO_UNKNOWN = 0,
37
  APERCT_ALGO_DEFAULT,
38
  APERCT_ALGO_TDIGEST,
39
} EAPerctAlgoType;
40

41
typedef enum { UNKNOWN_BIN = 0, USER_INPUT_BIN, LINEAR_BIN, LOG_BIN } EHistoBinType;
42

43
typedef enum {
44
  STATE_OPER_INVALID = 0,
45
  STATE_OPER_LT,
46
  STATE_OPER_GT,
47
  STATE_OPER_LE,
48
  STATE_OPER_GE,
49
  STATE_OPER_NE,
50
  STATE_OPER_EQ,
51
} EStateOperType;
52

53
#define SET_VAL(_info, numOfElem, res) \
54
  do {                                 \
55
    if ((numOfElem) <= 0) {            \
56
      break;                           \
57
    }                                  \
58
    (_info)->numOfRes = (res);         \
59
  } while (0)
60

61
#define GET_TS_LIST(x)    ((TSKEY*)((x)->ptsList))
62
#define GET_TS_DATA(x, y) (GET_TS_LIST(x)[(y)])
63

64
#define DO_UPDATE_SUBSID_RES(ctx, ts)                          \
65
  do {                                                         \
66
    for (int32_t _i = 0; _i < (ctx)->subsidiaries.num; ++_i) { \
67
      SqlFunctionCtx* __ctx = (ctx)->subsidiaries.pCtx[_i];    \
68
      if (__ctx->functionId == FUNCTION_TS_DUMMY) {            \
69
        __ctx->tag.i = (ts);                                   \
70
        __ctx->tag.nType = TSDB_DATA_TYPE_BIGINT;              \
71
      }                                                        \
72
      __ctx->fpSet.process(__ctx);                             \
73
    }                                                          \
74
  } while (0)
75

76
#define UPDATE_DATA(ctx, left, right, num, sign, _ts) \
77
  do {                                                \
78
    if (((left) < (right)) ^ (sign)) {                \
79
      (left) = (right);                               \
80
      DO_UPDATE_SUBSID_RES(ctx, _ts);                 \
81
      (num) += 1;                                     \
82
    }                                                 \
83
  } while (0)
84

85
#define LOOPCHECK_N(val, _col, ctx, _t, _nrow, _start, sign, num)        \
86
  do {                                                                   \
87
    _t* d = (_t*)((_col)->pData);                                        \
88
    for (int32_t i = (_start); i < (_nrow) + (_start); ++i) {            \
89
      if (((_col)->hasNull) && colDataIsNull_f((_col)->nullbitmap, i)) { \
90
        continue;                                                        \
91
      }                                                                  \
92
      TSKEY ts = (ctx)->ptsList != NULL ? GET_TS_DATA(ctx, i) : 0;       \
93
      UPDATE_DATA(ctx, val, d[i], num, sign, ts);                        \
94
    }                                                                    \
95
  } while (0)
96

97
#define LIST_ADD_N(_res, _col, _start, _rows, _t, numOfElem)             \
98
  do {                                                                   \
99
    _t* d = (_t*)(_col->pData);                                          \
100
    for (int32_t i = (_start); i < (_rows) + (_start); ++i) {            \
101
      if (((_col)->hasNull) && colDataIsNull_f((_col)->nullbitmap, i)) { \
102
        continue;                                                        \
103
      };                                                                 \
104
      (_res) += (d)[i];                                                  \
105
      (numOfElem)++;                                                     \
106
    }                                                                    \
107
  } while (0)
108

109
#define LIST_ADD_DECIMAL_N(_res, _col, _start, _rows, _t, numOfElem)                                  \
110
  do {                                                                                                \
111
    _t*                d = (_t*)(_col->pData);                                                        \
112
    const SDecimalOps* pOps = getDecimalOps(TSDB_DATA_TYPE_DECIMAL);                                  \
113
    for (int32_t i = (_start); i < (_rows) + (_start); ++i) {                                         \
114
      if (((_col)->hasNull) && colDataIsNull_f((_col)->nullbitmap, i)) {                              \
115
        continue;                                                                                     \
116
      };                                                                                              \
117
      overflow = overflow || decimal128AddCheckOverflow((Decimal*)_res, d + i, DECIMAL_WORD_NUM(_t)); \
118
      if (overflow) break;                                                                            \
119
      pOps->add(_res, d + i, DECIMAL_WORD_NUM(_t));                                                   \
120
      (numOfElem)++;                                                                                  \
121
    }                                                                                                 \
122
  } while (0)
123

124
#define LIST_SUB_N(_res, _col, _start, _rows, _t, numOfElem)             \
125
  do {                                                                   \
126
    _t* d = (_t*)(_col->pData);                                          \
127
    for (int32_t i = (_start); i < (_rows) + (_start); ++i) {            \
128
      if (((_col)->hasNull) && colDataIsNull_f((_col)->nullbitmap, i)) { \
129
        continue;                                                        \
130
      };                                                                 \
131
      (_res) -= (d)[i];                                                  \
132
      (numOfElem)++;                                                     \
133
    }                                                                    \
134
  } while (0)
135

136
//#define LIST_AVG_N(sumT, T)                                               \
137
//  do {                                                                    \
138
//    T* plist = (T*)pCol->pData;                                           \
139
//    for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) { \
140
//      if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {        \
141
//        continue;                                                         \
142
//      }                                                                   \
143
//                                                                          \
144
//      numOfElem += 1;                                                     \
145
//      pAvgRes->count -= 1;                                                \
146
//      sumT -= plist[i];                                                   \
147
//    }                                                                     \
148
//  } while (0)
149

150
#define LIST_STDDEV_SUB_N(sumT, T)                                 \
151
  do {                                                             \
152
    T* plist = (T*)pCol->pData;                                    \
153
    for (int32_t i = start; i < numOfRows + start; ++i) {          \
154
      if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) { \
155
        continue;                                                  \
156
      }                                                            \
157
      numOfElem += 1;                                              \
158
      pStddevRes->count -= 1;                                      \
159
      sumT -= plist[i];                                            \
160
      pStddevRes->quadraticISum -= (int64_t)(plist[i] * plist[i]); \
161
    }                                                              \
162
  } while (0)
163

164
#define LEASTSQR_CAL(p, x, y, index, step) \
165
  do {                                     \
166
    (p)[0][0] += (double)(x) * (x);        \
167
    (p)[0][1] += (double)(x);              \
168
    (p)[0][2] += (double)(x) * (y)[index]; \
169
    (p)[1][2] += (y)[index];               \
170
    (x) += step;                           \
171
  } while (0)
172

173
#define STATE_COMP(_op, _lval, _param) STATE_COMP_IMPL(_op, _lval, GET_STATE_VAL(_param))
174

175
#define GET_STATE_VAL(param) ((param.nType == TSDB_DATA_TYPE_BIGINT) ? (param.i) : (param.d))
176

177
#define STATE_COMP_IMPL(_op, _lval, _rval) \
178
  do {                                     \
179
    switch (_op) {                         \
180
      case STATE_OPER_LT:                  \
181
        return ((_lval) < (_rval));        \
182
        break;                             \
183
      case STATE_OPER_GT:                  \
184
        return ((_lval) > (_rval));        \
185
        break;                             \
186
      case STATE_OPER_LE:                  \
187
        return ((_lval) <= (_rval));       \
188
        break;                             \
189
      case STATE_OPER_GE:                  \
190
        return ((_lval) >= (_rval));       \
191
        break;                             \
192
      case STATE_OPER_NE:                  \
193
        return ((_lval) != (_rval));       \
194
        break;                             \
195
      case STATE_OPER_EQ:                  \
196
        return ((_lval) == (_rval));       \
197
        break;                             \
198
      default:                             \
199
        break;                             \
200
    }                                      \
201
  } while (0)
202

203
#define INIT_INTP_POINT(_p, _k, _v) \
204
  do {                              \
205
    (_p).key = (_k);                \
206
    (_p).val = (_v);                \
207
  } while (0)
208

209
void funcInputUpdate(SqlFunctionCtx* pCtx) {
16,368,469✔
210
  SFuncInputRowIter* pIter = &pCtx->rowIter;
16,368,469✔
211

212
  if (!pCtx->bInputFinished) {
16,368,469!
213
    pIter->pInput = &pCtx->input;
16,368,563✔
214
    pIter->tsList = (TSKEY*)pIter->pInput->pPTS->pData;
16,368,563✔
215
    pIter->pDataCol = pIter->pInput->pData[0];
16,368,563✔
216
    pIter->pPkCol = pIter->pInput->pPrimaryKey;
16,368,563✔
217
    pIter->rowIndex = pIter->pInput->startRowIndex;
16,368,563✔
218
    pIter->inputEndIndex = pIter->rowIndex + pIter->pInput->numOfRows - 1;
16,368,563✔
219
    pIter->pSrcBlock = pCtx->pSrcBlock;
16,368,563✔
220
    if (!pIter->hasGroupId || pIter->groupId != pIter->pSrcBlock->info.id.groupId) {
16,368,563✔
221
      pIter->hasGroupId = true;
214,438✔
222
      pIter->groupId = pIter->pSrcBlock->info.id.groupId;
214,438✔
223
      pIter->hasPrev = false;
214,438✔
224
    }
225
  } else {
UNCOV
226
    pIter->finalRow = true;
×
227
  }
228
}
16,368,469✔
229

UNCOV
230
int32_t funcInputGetNextRowDescPk(SFuncInputRowIter* pIter, SFuncInputRow* pRow, bool* res) {
×
231
  if (pIter->finalRow) {
×
232
    if (pIter->hasPrev) {
×
233
      pRow->ts = pIter->prevBlockTsEnd;
×
234
      pRow->isDataNull = pIter->prevIsDataNull;
×
235
      pRow->pData = pIter->pPrevData;
×
236
      pRow->block = pIter->pPrevRowBlock;
×
UNCOV
237
      pRow->rowIndex = 0;
×
238

239
      pIter->hasPrev = false;
×
UNCOV
240
      *res = true;
×
241
      return TSDB_CODE_SUCCESS;
×
242
    } else {
243
      *res = false;
×
244
      return TSDB_CODE_SUCCESS;
×
245
    }
246
  }
247
  if (pIter->hasPrev) {
×
UNCOV
248
    if (pIter->prevBlockTsEnd == pIter->tsList[pIter->inputEndIndex]) {
×
249
      blockDataDestroy(pIter->pPrevRowBlock);
×
250
      int32_t code = blockDataExtractBlock(pIter->pSrcBlock, pIter->inputEndIndex, 1, &pIter->pPrevRowBlock);
×
251
      if (code) {
×
252
        return code;
×
253
      }
254

255
      pIter->prevIsDataNull = colDataIsNull_f(pIter->pDataCol->nullbitmap, pIter->inputEndIndex);
×
256

UNCOV
257
      pIter->pPrevData = taosMemoryMalloc(pIter->pDataCol->info.bytes);
×
258
      if (NULL == pIter->pPrevData) {
×
259
        qError("out of memory when function get input row.");
×
260
        return terrno;
×
261
      }
UNCOV
262
      char* srcData = colDataGetData(pIter->pDataCol, pIter->inputEndIndex);
×
263
      (void)memcpy(pIter->pPrevData, srcData, pIter->pDataCol->info.bytes);
×
264

265
      pIter->pPrevPk = taosMemoryMalloc(pIter->pPkCol->info.bytes);
×
UNCOV
266
      if (NULL == pIter->pPrevPk) {
×
267
        qError("out of memory when function get input row.");
×
268
        taosMemoryFree(pIter->pPrevData);
×
269
        return terrno;
×
270
      }
271
      char* pkData = colDataGetData(pIter->pPkCol, pIter->inputEndIndex);
×
272
      (void)memcpy(pIter->pPrevPk, pkData, pIter->pPkCol->info.bytes);
×
273

274
      code = blockDataExtractBlock(pIter->pSrcBlock, pIter->inputEndIndex, 1, &pIter->pPrevRowBlock);
×
275
      pIter->hasPrev = true;
×
276
      *res = false;
×
277
      return code;
×
278
    } else {
279
      int32_t idx = pIter->rowIndex;
×
UNCOV
280
      while (pIter->tsList[idx] == pIter->prevBlockTsEnd) {
×
281
        ++idx;
×
282
      }
283
      pRow->ts = pIter->prevBlockTsEnd;
×
284
      if (idx == pIter->pInput->startRowIndex) {
×
UNCOV
285
        pRow->isDataNull = pIter->prevIsDataNull;
×
UNCOV
286
        pRow->pData = pIter->pPrevData;
×
287
        pRow->block = pIter->pPrevRowBlock;
×
288
        pRow->rowIndex = 0;
×
289
      } else {
290
        pRow->ts = pIter->tsList[idx - 1];
×
291
        pRow->isDataNull = colDataIsNull_f(pIter->pDataCol->nullbitmap, idx - 1);
×
UNCOV
292
        pRow->pData = colDataGetData(pIter->pDataCol, idx - 1);
×
293
        pRow->pPk = colDataGetData(pIter->pPkCol, idx - 1);
×
294
        pRow->block = pIter->pSrcBlock;
×
295
        pRow->rowIndex = idx - 1;
×
296
      }
297
      pIter->hasPrev = false;
×
UNCOV
298
      pIter->rowIndex = idx;
×
299
      *res = true;
×
300
      return TSDB_CODE_SUCCESS;
×
301
    }
302
  } else {
303
    TSKEY tsEnd = pIter->tsList[pIter->inputEndIndex];
×
304
    if (pIter->tsList[pIter->rowIndex] != tsEnd) {
×
305
      int32_t idx = pIter->rowIndex;
×
306
      while (pIter->tsList[idx + 1] == pIter->tsList[pIter->rowIndex]) {
×
307
        ++idx;
×
308
      }
309
      pRow->ts = pIter->tsList[idx];
×
UNCOV
310
      pRow->isDataNull = colDataIsNull_f(pIter->pDataCol->nullbitmap, idx);
×
311
      pRow->pData = colDataGetData(pIter->pDataCol, idx);
×
312
      pRow->pPk = colDataGetData(pIter->pPkCol, idx);
×
313
      pRow->block = pIter->pSrcBlock;
×
314

315
      pIter->rowIndex = idx + 1;
×
316
      *res = true;
×
317
      return TSDB_CODE_SUCCESS;
×
318
    } else {
319
      pIter->hasPrev = true;
×
UNCOV
320
      pIter->prevBlockTsEnd = tsEnd;
×
321
      pIter->prevIsDataNull = colDataIsNull_f(pIter->pDataCol->nullbitmap, pIter->inputEndIndex);
×
322
      pIter->pPrevData = taosMemoryMalloc(pIter->pDataCol->info.bytes);
×
323
      if (NULL == pIter->pPrevData) {
×
UNCOV
324
        qError("out of memory when function get input row.");
×
UNCOV
325
        return terrno;
×
326
      }
UNCOV
327
      (void)memcpy(pIter->pPrevData, colDataGetData(pIter->pDataCol, pIter->inputEndIndex),
×
UNCOV
328
                   pIter->pDataCol->info.bytes);
×
UNCOV
329
      pIter->pPrevPk = taosMemoryMalloc(pIter->pPkCol->info.bytes);
×
UNCOV
330
      if (NULL == pIter->pPrevPk) {
×
UNCOV
331
        qError("out of memory when function get input row.");
×
UNCOV
332
        taosMemoryFree(pIter->pPrevData);
×
UNCOV
333
        return terrno;
×
334
      }
UNCOV
335
      (void)memcpy(pIter->pPrevPk, colDataGetData(pIter->pPkCol, pIter->inputEndIndex), pIter->pPkCol->info.bytes);
×
336

UNCOV
337
      int32_t code = blockDataExtractBlock(pIter->pSrcBlock, pIter->inputEndIndex, 1, &pIter->pPrevRowBlock);
×
UNCOV
338
      *res = false;
×
UNCOV
339
      return code;
×
340
    }
341
  }
342
}
343

344
static void forwardToNextDiffTsRow(SFuncInputRowIter* pIter, int32_t rowIndex) {
162✔
345
  int32_t idx = rowIndex + 1;
162✔
346
  while (idx <= pIter->inputEndIndex && pIter->tsList[idx] == pIter->tsList[rowIndex]) {
364!
347
    ++idx;
202✔
348
  }
349
  pIter->rowIndex = idx;
162✔
350
}
162✔
351

352
static void setInputRowInfo(SFuncInputRow* pRow, SFuncInputRowIter* pIter, int32_t rowIndex, bool setPk) {
1,278,947,781✔
353
  pRow->ts = pIter->tsList[rowIndex];
1,278,947,781✔
354
  pRow->ts = pIter->tsList[rowIndex];
1,278,947,781✔
355
  pRow->isDataNull = colDataIsNull_f(pIter->pDataCol->nullbitmap, rowIndex);
1,278,947,781✔
356
  pRow->pData = colDataGetData(pIter->pDataCol, rowIndex);
1,278,947,781!
357
  pRow->pPk = setPk ? colDataGetData(pIter->pPkCol, rowIndex) : NULL;
1,278,947,781!
358
  pRow->block = pIter->pSrcBlock;
1,278,947,781✔
359
  pRow->rowIndex = rowIndex;
1,278,947,781✔
360
}
1,278,947,781✔
361

362
bool funcInputGetNextRowAscPk(SFuncInputRowIter* pIter, SFuncInputRow* pRow) {
332✔
363
  if (pIter->hasPrev) {
332!
UNCOV
364
    if (pIter->prevBlockTsEnd == pIter->tsList[pIter->inputEndIndex]) {
×
UNCOV
365
      pIter->hasPrev = true;
×
UNCOV
366
      return false;
×
367
    } else {
UNCOV
368
      int32_t idx = pIter->rowIndex;
×
UNCOV
369
      while (pIter->tsList[idx] == pIter->prevBlockTsEnd) {
×
UNCOV
370
        ++idx;
×
371
      }
372

UNCOV
373
      pIter->hasPrev = false;
×
UNCOV
374
      setInputRowInfo(pRow, pIter, idx, true);
×
UNCOV
375
      forwardToNextDiffTsRow(pIter, idx);
×
UNCOV
376
      return true;
×
377
    }
378
  } else {
379
    if (pIter->rowIndex <= pIter->inputEndIndex) {
332✔
380
      setInputRowInfo(pRow, pIter, pIter->rowIndex, true);
250✔
381

382
      TSKEY tsEnd = pIter->tsList[pIter->inputEndIndex];
250✔
383
      if (pIter->tsList[pIter->rowIndex] != tsEnd) {
250✔
384
        forwardToNextDiffTsRow(pIter, pIter->rowIndex);
162✔
385
      } else {
386
        pIter->rowIndex = pIter->inputEndIndex + 1;
88✔
387
      }
388
      return true;
250✔
389
    } else {
390
      TSKEY tsEnd = pIter->tsList[pIter->inputEndIndex];
82✔
391
      pIter->hasPrev = true;
82✔
392
      pIter->prevBlockTsEnd = tsEnd;
82✔
393
      return false;
82✔
394
    }
395
  }
396
}
397

398
bool funcInputGetNextRowNoPk(SFuncInputRowIter* pIter, SFuncInputRow* pRow) {
1,295,256,858✔
399
  if (pIter->rowIndex <= pIter->inputEndIndex) {
1,295,256,858✔
400
    setInputRowInfo(pRow, pIter, pIter->rowIndex, false);
1,278,963,381✔
401
    ++pIter->rowIndex;
1,279,022,723✔
402
    return true;
1,279,022,723✔
403
  } else {
404
    return false;
16,293,477✔
405
  }
406
}
407

408
int32_t funcInputGetNextRow(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, bool* res) {
1,295,236,313✔
409
  SFuncInputRowIter* pIter = &pCtx->rowIter;
1,295,236,313✔
410
  if (pCtx->hasPrimaryKey) {
1,295,236,313✔
411
    if (pCtx->order == TSDB_ORDER_ASC) {
332!
412
      *res = funcInputGetNextRowAscPk(pIter, pRow);
332✔
413
      return TSDB_CODE_SUCCESS;
332✔
414
    } else {
UNCOV
415
      return funcInputGetNextRowDescPk(pIter, pRow, res);
×
416
    }
417
  } else {
418
    *res = funcInputGetNextRowNoPk(pIter, pRow);
1,295,235,981✔
419
    return TSDB_CODE_SUCCESS;
1,295,224,813✔
420
  }
421
  return TSDB_CODE_SUCCESS;
422
}
423

424
// This function append the selectivity to subsidiaries function context directly, without fetching data
425
// from intermediate disk based buf page
426
int32_t appendSelectivityCols(SqlFunctionCtx* pCtx, SSDataBlock* pSrcBlock, int32_t rowIndex, int32_t pos) {
25,996,834✔
427
  if (pCtx->subsidiaries.num <= 0) {
25,996,834!
UNCOV
428
    return TSDB_CODE_SUCCESS;
×
429
  }
430

431
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
51,993,624✔
432
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
25,996,828✔
433

434
    // get data from source col
435
    SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
25,996,828✔
436
    int32_t      srcSlotId = pFuncParam->pCol->slotId;
25,996,828✔
437

438
    SColumnInfoData* pSrcCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
25,996,828✔
439
    if (NULL == pSrcCol) {
25,996,757!
UNCOV
440
      return TSDB_CODE_OUT_OF_RANGE;
×
441
    }
442

443
    char* pData = colDataGetData(pSrcCol, rowIndex);
25,996,757!
444

445
    // append to dest col
446
    int32_t dstSlotId = pc->pExpr->base.resSchema.slotId;
25,996,757✔
447

448
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
25,996,757✔
449
    if (NULL == pDstCol) {
25,996,719!
UNCOV
450
      return TSDB_CODE_OUT_OF_RANGE;
×
451
    }
452
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
51,993,438✔
453
      colDataSetNULL(pDstCol, pos);
20!
454
    } else {
455
      int32_t code = colDataSetVal(pDstCol, pos, pData, false);
25,996,699✔
456
      if (TSDB_CODE_SUCCESS != code) {
25,996,770!
UNCOV
457
        return code;
×
458
      }
459
    }
460
  }
461
  return TSDB_CODE_SUCCESS;
25,996,796✔
462
}
463

464
bool funcInputGetNextRowIndex(SInputColumnInfoData* pInput, int32_t from, bool firstOccur, int32_t* pRowIndex,
465
                              int32_t* nextFrom);
466

467
static bool firstLastTransferInfoImpl(SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst);
468

469
int32_t functionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
697,557,693✔
470
  if (pResultInfo->initialized) {
697,557,693✔
471
    return TSDB_CODE_SUCCESS;  // already initialized
62,489✔
472
  }
473

474
  if (pCtx->pOutput != NULL) {
697,495,204!
UNCOV
475
    (void)memset(pCtx->pOutput, 0, (size_t)pCtx->resDataInfo.bytes);
×
476
  }
477

478
  initResultRowEntry(pResultInfo, pCtx->resDataInfo.interBufSize);
697,495,204✔
479
  return TSDB_CODE_SUCCESS;
697,495,204✔
480
}
481

482
int32_t functionFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
166,291,373✔
483
  int32_t          code = TSDB_CODE_SUCCESS;
166,291,373✔
484
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
166,291,373✔
485
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
166,291,373✔
486
  if (NULL == pCol) {
165,993,180!
UNCOV
487
    return TSDB_CODE_OUT_OF_RANGE;
×
488
  }
489
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
165,993,180✔
490
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
165,993,180✔
491

492
  char* in = GET_ROWCELL_INTERBUF(pResInfo);
165,993,180✔
493
  code = colDataSetVal(pCol, pBlock->info.rows, in, pResInfo->isNullRes);
165,993,180✔
494

495
  return code;
167,099,717✔
496
}
497

498
int32_t firstCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
3✔
499
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
3✔
500
  SFirstLastRes*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
3✔
501
  int32_t              bytes = pDBuf->bytes;
3✔
502

503
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
3✔
504
  SFirstLastRes*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
3✔
505

506
  pDBuf->hasResult = firstLastTransferInfoImpl(pSBuf, pDBuf, true);
3✔
507

508
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
3✔
509
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
3✔
510
  return TSDB_CODE_SUCCESS;
3✔
511
}
512

513
int32_t functionFinalizeWithResultBuf(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, char* finalResult) {
39✔
514
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
39✔
515
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
39✔
516
  if (NULL == pCol) {
39!
UNCOV
517
    return TSDB_CODE_OUT_OF_RANGE;
×
518
  }
519
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
39✔
520
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
39✔
521

522
  char*   in = finalResult;
39✔
523
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, in, pResInfo->isNullRes);
39✔
524

525
  return code;
39✔
526
}
527

528
EFuncDataRequired countDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
219,457✔
529
  SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0);
219,457✔
530
  if (QUERY_NODE_COLUMN == nodeType(pParam) && PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pParam)->colId) {
219,486!
531
    return FUNC_DATA_REQUIRED_NOT_LOAD;
162,810✔
532
  }
533
  return FUNC_DATA_REQUIRED_SMA_LOAD;
56,676✔
534
}
535

536
bool getCountFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
1,799,616✔
537
  pEnv->calcMemSize = sizeof(int64_t);
1,799,616✔
538
  return true;
1,799,616✔
539
}
540

541
static int64_t getNumOfElems(SqlFunctionCtx* pCtx) {
109,787,105✔
542
  int64_t numOfElem = 0;
109,787,105✔
543

544
  /*
545
   * 1. column data missing (schema modified) causes pInputCol->hasNull == true. pInput->colDataSMAIsSet == true;
546
   * 2. for general non-primary key columns, pInputCol->hasNull may be true or false, pInput->colDataSMAIsSet == true;
547
   * 3. for primary key column, pInputCol->hasNull always be false, pInput->colDataSMAIsSet == false;
548
   */
549
  SInputColumnInfoData* pInput = &pCtx->input;
109,787,105✔
550
  SColumnInfoData*      pInputCol = pInput->pData[0];
109,787,105✔
551
  if (1 == pInput->numOfRows && pInput->blankFill) {
109,787,105✔
552
    return 0;
455,725✔
553
  }
554
  if (pInput->colDataSMAIsSet && pInput->totalRows == pInput->numOfRows) {
109,331,380!
555
    numOfElem = pInput->numOfRows - pInput->pColumnDataAgg[0]->numOfNull;
2,910✔
556
  } else {
557
    if (pInputCol->hasNull) {
109,328,470✔
558
      for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
328,303,269✔
559
        if (colDataIsNull(pInputCol, pInput->totalRows, i, NULL)) {
599,514,552!
560
          continue;
1,865,403✔
561
        }
562
        numOfElem += 1;
297,891,873✔
563
      }
564
    } else {
565
      // when counting on the primary time stamp column and no statistics data is presented, use the size value
566
      // directly.
567
      numOfElem = pInput->numOfRows;
80,782,477✔
568
    }
569
  }
570
  return numOfElem;
109,331,380✔
571
}
572

573
/*
574
 * count function does need the finalize, if data is missing, the default value, which is 0, is used
575
 * count function does not use the pCtx->interResBuf to keep the intermediate buffer
576
 */
577
int32_t countFunction(SqlFunctionCtx* pCtx) {
109,953,469✔
578
  int64_t numOfElem = 0;
109,953,469✔
579

580
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
109,953,469✔
581
  SInputColumnInfoData* pInput = &pCtx->input;
109,953,469✔
582

583
  int32_t type = pInput->pData[0]->info.type;
109,953,469✔
584

585
  char*   buf = GET_ROWCELL_INTERBUF(pResInfo);
109,953,469✔
586
  int64_t val = *((int64_t*)buf);
109,953,469✔
587
  if (IS_NULL_TYPE(type)) {
109,953,469✔
588
    // select count(NULL) returns 0
589
    numOfElem = 1;
139,216✔
590
    val += 0;
139,216✔
591
  } else {
592
    numOfElem = getNumOfElems(pCtx);
109,814,253✔
593
    val += numOfElem;
109,623,413✔
594
  }
595
  taosSetInt64Aligned((int64_t*)buf, val);
596

597
  if (tsCountAlwaysReturnValue) {
109,762,629!
598
    pResInfo->numOfRes = 1;
109,840,132✔
599
  } else {
UNCOV
600
    SET_VAL(pResInfo, val, 1);
×
601
  }
602

603
  return TSDB_CODE_SUCCESS;
109,762,629✔
604
}
605

606
#ifdef BUILD_NO_CALL
607
int32_t countInvertFunction(SqlFunctionCtx* pCtx) {
608
  int64_t numOfElem = getNumOfElems(pCtx);
609

610
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
611
  char*                buf = GET_ROWCELL_INTERBUF(pResInfo);
612
  *((int64_t*)buf) -= numOfElem;
613

614
  SET_VAL(pResInfo, *((int64_t*)buf), 1);
615
  return TSDB_CODE_SUCCESS;
616
}
617
#endif
618

619
int32_t combineFunction(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
22✔
620
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
22✔
621
  char*                pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
22✔
622

623
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
22✔
624
  char*                pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
22✔
625
  *((int64_t*)pDBuf) += *((int64_t*)pSBuf);
22✔
626

627
  SET_VAL(pDResInfo, *((int64_t*)pDBuf), 1);
22!
628
  return TSDB_CODE_SUCCESS;
22✔
629
}
630

631
int32_t sumFunction(SqlFunctionCtx* pCtx) {
84,963,954✔
632
  int32_t numOfElem = 0;
84,963,954✔
633

634
  // Only the pre-computing information loaded and actual data does not loaded
635
  SInputColumnInfoData* pInput = &pCtx->input;
84,963,954✔
636
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
84,963,954✔
637
  int32_t               type = pInput->pData[0]->info.type;
84,963,954✔
638
  pCtx->inputType = type;
84,963,954✔
639

640
  void* pSumRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
84,963,954✔
641
  SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, type);
84,963,954!
642

643
  if (IS_NULL_TYPE(type)) {
84,963,954✔
644
    numOfElem = 0;
200✔
645
    goto _sum_over;
200✔
646
  }
647

648
  if (pInput->colDataSMAIsSet) {
84,963,754✔
649
    numOfElem = pInput->numOfRows - pAgg->numOfNull;
231✔
650

651
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
231!
652
      SUM_RES_INC_ISUM(pSumRes, pAgg->sum);
215✔
653
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
16!
UNCOV
654
      SUM_RES_INC_USUM(pSumRes, pAgg->sum);
×
655
    } else if (IS_FLOAT_TYPE(type)) {
16!
UNCOV
656
      SUM_RES_INC_DSUM(pSumRes, GET_DOUBLE_VAL((const char*)&(pAgg->sum)));
×
657
    } else if (IS_DECIMAL_TYPE(type)) {
16!
658
      SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, TSDB_DATA_TYPE_DECIMAL);
16!
659
      const SDecimalOps* pOps = getDecimalOps(TSDB_DATA_TYPE_DECIMAL);
16✔
660
      if (pAgg->overflow || decimal128AddCheckOverflow((Decimal*)&SUM_RES_GET_DECIMAL_SUM(pSumRes),
28!
661
                                                       &pAgg->decimal128Sum, DECIMAL_WORD_NUM(Decimal))) {
12✔
662
        return TSDB_CODE_DECIMAL_OVERFLOW;
4✔
663
      }
664
      pOps->add(&SUM_RES_GET_DECIMAL_SUM(pSumRes), &pAgg->decimal128Sum, DECIMAL_WORD_NUM(Decimal));
12✔
665
    }
666
  } else {  // computing based on the true data block
667
    SColumnInfoData* pCol = pInput->pData[0];
84,963,523✔
668

669
    int32_t start = pInput->startRowIndex;
84,963,523✔
670
    int32_t numOfRows = pInput->numOfRows;
84,963,523✔
671

672
    if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
84,963,523!
673
      if (type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_BOOL) {
84,110,774!
674
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int8_t, numOfElem);
1,501,939✔
675
      } else if (type == TSDB_DATA_TYPE_SMALLINT) {
83,782,808✔
676
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int16_t, numOfElem);
5,897,408✔
677
      } else if (type == TSDB_DATA_TYPE_INT) {
81,831,058✔
678
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int32_t, numOfElem);
331,172,092✔
679
      } else if (type == TSDB_DATA_TYPE_BIGINT) {
21,269,656!
680
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int64_t, numOfElem);
76,205,080✔
681
      }
682
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
852,749✔
683
      if (type == TSDB_DATA_TYPE_UTINYINT) {
105✔
684
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint8_t, numOfElem);
50,015!
685
      } else if (type == TSDB_DATA_TYPE_USMALLINT) {
90✔
686
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint16_t, numOfElem);
50,023✔
687
      } else if (type == TSDB_DATA_TYPE_UINT) {
74✔
688
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint32_t, numOfElem);
50,015!
689
      } else if (type == TSDB_DATA_TYPE_UBIGINT) {
59!
690
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint64_t, numOfElem);
50,592✔
691
      }
692
    } else if (type == TSDB_DATA_TYPE_DOUBLE) {
852,644✔
693
      LIST_ADD_N(SUM_RES_GET_DSUM(pSumRes), pCol, start, numOfRows, double, numOfElem);
2,202,129✔
694
    } else if (type == TSDB_DATA_TYPE_FLOAT) {
768,165✔
695
      LIST_ADD_N(SUM_RES_GET_DSUM(pSumRes), pCol, start, numOfRows, float, numOfElem);
1,745,728✔
696
    } else if (IS_DECIMAL_TYPE(type)) {
2,403!
697
      SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, TSDB_DATA_TYPE_DECIMAL);
2,412!
698
      int32_t overflow = false;
2,412✔
699
      if (TSDB_DATA_TYPE_DECIMAL64 == type) {
2,412!
UNCOV
700
        LIST_ADD_DECIMAL_N(&SUM_RES_GET_DECIMAL_SUM(pSumRes), pCol, start, numOfRows, Decimal64, numOfElem);
×
701
      } else if (TSDB_DATA_TYPE_DECIMAL == type) {
2,412!
702
        LIST_ADD_DECIMAL_N(&SUM_RES_GET_DECIMAL_SUM(pSumRes), pCol, start, numOfRows, Decimal128, numOfElem);
42,824!
703
      }
704
      if (overflow) return TSDB_CODE_DECIMAL_OVERFLOW;
2,412!
705
    }
706
  }
707

708
  // check for overflow
709
  if (IS_FLOAT_TYPE(type) && (isinf(SUM_RES_GET_DSUM(pSumRes)) || isnan(SUM_RES_GET_DSUM(pSumRes)))) {
84,963,750!
UNCOV
710
    numOfElem = 0;
×
711
  }
712

713
_sum_over:
85,299,689✔
714
  if (numOfElem == 0) {
84,963,950✔
715
    if (tsCountAlwaysReturnValue && pCtx->pExpr->pExpr->_function.pFunctNode->hasOriginalFunc &&
92,609✔
716
        fmIsCountLikeFunc(pCtx->pExpr->pExpr->_function.pFunctNode->originalFuncId)) {
11,430✔
717
      numOfElem = 1;
18✔
718
    }
719
  }
720
  // data in the check operation are all null, not output
721
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
84,963,950✔
722
  return TSDB_CODE_SUCCESS;
84,963,950✔
723
}
724

725
#ifdef BUILD_NO_CALL
726
int32_t sumInvertFunction(SqlFunctionCtx* pCtx) {
727
  int32_t numOfElem = 0;
728

729
  // Only the pre-computing information loaded and actual data does not loaded
730
  SInputColumnInfoData* pInput = &pCtx->input;
731
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
732
  int32_t               type = pInput->pData[0]->info.type;
733

734
  SSumRes* pSumRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
735

736
  if (pInput->colDataSMAIsSet) {
737
    numOfElem = pInput->numOfRows - pAgg->numOfNull;
738

739
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
740
      pSumRes->isum -= pAgg->sum;
741
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
742
      pSumRes->usum -= pAgg->sum;
743
    } else if (IS_FLOAT_TYPE(type)) {
744
      pSumRes->dsum -= GET_DOUBLE_VAL((const char*)&(pAgg->sum));
745
    }
746
  } else {  // computing based on the true data block
747
    SColumnInfoData* pCol = pInput->pData[0];
748

749
    int32_t start = pInput->startRowIndex;
750
    int32_t numOfRows = pInput->numOfRows;
751

752
    if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
753
      if (type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_BOOL) {
754
        LIST_SUB_N(pSumRes->isum, pCol, start, numOfRows, int8_t, numOfElem);
755
      } else if (type == TSDB_DATA_TYPE_SMALLINT) {
756
        LIST_SUB_N(pSumRes->isum, pCol, start, numOfRows, int16_t, numOfElem);
757
      } else if (type == TSDB_DATA_TYPE_INT) {
758
        LIST_SUB_N(pSumRes->isum, pCol, start, numOfRows, int32_t, numOfElem);
759
      } else if (type == TSDB_DATA_TYPE_BIGINT) {
760
        LIST_SUB_N(pSumRes->isum, pCol, start, numOfRows, int64_t, numOfElem);
761
      }
762
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
763
      if (type == TSDB_DATA_TYPE_UTINYINT) {
764
        LIST_SUB_N(pSumRes->usum, pCol, start, numOfRows, uint8_t, numOfElem);
765
      } else if (type == TSDB_DATA_TYPE_USMALLINT) {
766
        LIST_SUB_N(pSumRes->usum, pCol, start, numOfRows, uint16_t, numOfElem);
767
      } else if (type == TSDB_DATA_TYPE_UINT) {
768
        LIST_SUB_N(pSumRes->usum, pCol, start, numOfRows, uint32_t, numOfElem);
769
      } else if (type == TSDB_DATA_TYPE_UBIGINT) {
770
        LIST_SUB_N(pSumRes->usum, pCol, start, numOfRows, uint64_t, numOfElem);
771
      }
772
    } else if (type == TSDB_DATA_TYPE_DOUBLE) {
773
      LIST_SUB_N(pSumRes->dsum, pCol, start, numOfRows, double, numOfElem);
774
    } else if (type == TSDB_DATA_TYPE_FLOAT) {
775
      LIST_SUB_N(pSumRes->dsum, pCol, start, numOfRows, float, numOfElem);
776
    }
777
  }
778

779
  // data in the check operation are all null, not output
780
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
781
  return TSDB_CODE_SUCCESS;
782
}
783
#endif
784

785
int32_t sumCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
38✔
786
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
38✔
787
  void*                pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
38✔
788
  int16_t              type = SUM_RES_GET_TYPE(pDBuf, pDestCtx->inputType);
38!
789

790
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
38✔
791
  void*                pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
38✔
792
  type = (type == TSDB_DATA_TYPE_NULL) ? SUM_RES_GET_TYPE(pSBuf, pDestCtx->inputType) : type;
38!
793

794
  if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
38!
795
    SUM_RES_INC_ISUM(pDBuf, SUM_RES_GET_ISUM(pSBuf));
34✔
796
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
4!
UNCOV
797
    SUM_RES_INC_USUM(pDBuf, SUM_RES_GET_USUM(pSBuf));
×
798
  } else if (IS_DECIMAL_TYPE(type)) {
8!
799
    bool overflow = false;
4✔
800
    SUM_RES_INC_DECIMAL_SUM(pDBuf, &SUM_RES_GET_DECIMAL_SUM(pSBuf), type);
4!
UNCOV
801
  } else if (type == TSDB_DATA_TYPE_DOUBLE || type == TSDB_DATA_TYPE_FLOAT) {
×
UNCOV
802
    SUM_RES_INC_DSUM(pDBuf, SUM_RES_GET_DSUM(pSBuf));
×
803
  }
804
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
38✔
805
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
38✔
806
  return TSDB_CODE_SUCCESS;
38✔
807
}
808

809
bool getSumFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
231,083✔
810
  pEnv->calcMemSize = SUM_RES_GET_SIZE(pFunc->node.resType.type);
231,083!
811
  return true;
231,083✔
812
}
813

814
static bool funcNotSupportStringSma(SFunctionNode* pFunc) {
179,589✔
815
  SNode* pParam;
816
  switch (pFunc->funcType) {
179,589!
817
    case FUNCTION_TYPE_MAX:
179,589✔
818
    case FUNCTION_TYPE_MIN:
819
    case FUNCTION_TYPE_SUM:
820
    case FUNCTION_TYPE_AVG:
821
    case FUNCTION_TYPE_AVG_PARTIAL:
822
    case FUNCTION_TYPE_PERCENTILE:
823
    case FUNCTION_TYPE_SPREAD:
824
    case FUNCTION_TYPE_SPREAD_PARTIAL:
825
    case FUNCTION_TYPE_SPREAD_MERGE:
826
    case FUNCTION_TYPE_TWA:
827
    case FUNCTION_TYPE_ELAPSED:
828
      pParam = nodesListGetNode(pFunc->pParameterList, 0);
179,589✔
829
      if (pParam && nodesIsExprNode(pParam) && (IS_VAR_DATA_TYPE(((SExprNode*)pParam)->resType.type))) {
179,589!
830
        return true;
86✔
831
      }
832
      break;
179,503✔
UNCOV
833
    default:
×
UNCOV
834
      break;
×
835
  }
836
  return false;
179,503✔
837
}
838

839
EFuncDataRequired statisDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
179,589✔
840
  if (funcNotSupportStringSma(pFunc)) {
179,589✔
841
    return FUNC_DATA_REQUIRED_DATA_LOAD;
86✔
842
  }
843
  return FUNC_DATA_REQUIRED_SMA_LOAD;
179,503✔
844
}
845

846
int32_t minmaxFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
64,089,258✔
847
  if (pResultInfo->initialized) {
64,089,258!
UNCOV
848
    return TSDB_CODE_SUCCESS;
×
849
  }
850
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
64,089,258!
UNCOV
851
    return TSDB_CODE_FUNC_SETUP_ERROR;  // not initialized since it has been initialized
×
852
  }
853

854
  SMinmaxResInfo* buf = GET_ROWCELL_INTERBUF(pResultInfo);
64,109,533✔
855
  buf->assign = false;
64,109,533✔
856
  buf->tuplePos.pageId = -1;
64,109,533✔
857

858
  buf->nullTupleSaved = false;
64,109,533✔
859
  buf->nullTuplePos.pageId = -1;
64,109,533✔
860
  buf->str = NULL;
64,109,533✔
861
  return TSDB_CODE_SUCCESS;
64,109,533✔
862
}
863

864
bool getMinmaxFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
427,412✔
865
  COMPILE_TIME_ASSERT(sizeof(SMinmaxResInfo) == sizeof(SOldMinMaxResInfo));
866
  pEnv->calcMemSize = sizeof(SMinmaxResInfo);
427,412✔
867
  return true;
427,412✔
868
}
869

870
int32_t minFunction(SqlFunctionCtx* pCtx) {
33,839,887✔
871
  int32_t numOfElems = 0;
33,839,887✔
872
  int32_t code = doMinMaxHelper(pCtx, 1, &numOfElems);
33,839,887✔
873
  if (code != TSDB_CODE_SUCCESS) {
33,984,361!
UNCOV
874
    return code;
×
875
  }
876
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
33,984,361✔
877
  return TSDB_CODE_SUCCESS;
33,984,361✔
878
}
879

880
int32_t maxFunction(SqlFunctionCtx* pCtx) {
39,568,232✔
881
  int32_t numOfElems = 0;
39,568,232✔
882
  int32_t code = doMinMaxHelper(pCtx, 0, &numOfElems);
39,568,232✔
883
  if (code != TSDB_CODE_SUCCESS) {
39,686,447!
UNCOV
884
    return code;
×
885
  }
886
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
39,686,447✔
887
  return TSDB_CODE_SUCCESS;
39,686,447✔
888
}
889

890
static int32_t setNullSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t rowIndex);
891
static int32_t setSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, const STuplePos* pTuplePos,
892
                                   int32_t rowIndex);
893

894
int32_t minmaxFunctionFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
62,601,304✔
895
  int32_t code = TSDB_CODE_SUCCESS;
62,601,304✔
896

897
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
62,601,304✔
898
  SMinmaxResInfo*      pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
62,601,304✔
899

900
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
62,601,304✔
901
  int32_t currentRow = pBlock->info.rows;
62,601,304✔
902

903
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
62,601,304✔
904
  if (NULL == pCol) {
62,620,163!
UNCOV
905
    return TSDB_CODE_OUT_OF_RANGE;
×
906
  }
907
  pEntryInfo->isNullRes = (pEntryInfo->numOfRes == 0) ? 1 : 0;
62,620,163✔
908

909
  // NOTE: do nothing change it, for performance issue
910
  if (!pEntryInfo->isNullRes) {
62,620,163✔
911
    switch (pCol->info.type) {
55,134,384!
912
      case TSDB_DATA_TYPE_UBIGINT:
11,137,124✔
913
      case TSDB_DATA_TYPE_BIGINT:
914
        ((int64_t*)pCol->pData)[currentRow] = pRes->v;
11,137,124✔
915
        break;
11,137,124✔
916
      case TSDB_DATA_TYPE_UINT:
23,507,875✔
917
      case TSDB_DATA_TYPE_INT:
918
        colDataSetInt32(pCol, currentRow, (int32_t*)&pRes->v);
23,507,875✔
919
        break;
23,507,875✔
920
      case TSDB_DATA_TYPE_USMALLINT:
232,582✔
921
      case TSDB_DATA_TYPE_SMALLINT:
922
        colDataSetInt16(pCol, currentRow, (int16_t*)&pRes->v);
232,582✔
923
        break;
232,582✔
924
      case TSDB_DATA_TYPE_BOOL:
210,456✔
925
      case TSDB_DATA_TYPE_UTINYINT:
926
      case TSDB_DATA_TYPE_TINYINT:
927
        colDataSetInt8(pCol, currentRow, (int8_t*)&pRes->v);
210,456✔
928
        break;
210,456✔
929
      case TSDB_DATA_TYPE_DOUBLE:
9,373,028✔
930
        colDataSetDouble(pCol, currentRow, (double*)&pRes->v);
9,373,028✔
931
        break;
9,373,028✔
932
      case TSDB_DATA_TYPE_FLOAT: {
5,868,901✔
933
        float v = GET_FLOAT_VAL(&pRes->v);
5,868,901✔
934
        colDataSetFloat(pCol, currentRow, &v);
5,868,901✔
935
        break;
5,868,901✔
936
      }
937
      case TSDB_DATA_TYPE_VARBINARY:
4,866,392✔
938
      case TSDB_DATA_TYPE_VARCHAR:
939
      case TSDB_DATA_TYPE_NCHAR: {
940
        code = colDataSetVal(pCol, currentRow, pRes->str, false);
4,866,392✔
941
        if (TSDB_CODE_SUCCESS != code) {
4,866,393!
UNCOV
942
          return code;
×
943
        }
944
        break;
4,866,393✔
945
      }
946
      case TSDB_DATA_TYPE_DECIMAL64:
32✔
947
        code = colDataSetVal(pCol, currentRow, (const char*)&pRes->v, false);
32✔
948
        break;
32✔
949
      case TSDB_DATA_TYPE_DECIMAL:
768✔
950
        code = colDataSetVal(pCol, currentRow, (void*)pRes->dec, false);
768✔
951
        break;
768✔
952
    }
953
  } else {
954
    colDataSetNULL(pCol, currentRow);
7,485,779!
955
  }
956

957
  if (IS_VAR_DATA_TYPE(pCol->info.type)) taosMemoryFreeClear(pRes->str);
62,620,164!
958
  if (pCtx->subsidiaries.num > 0) {
62,620,164✔
959
    if (pEntryInfo->numOfRes > 0) {
18,683,659✔
960
      code = setSelectivityValue(pCtx, pBlock, &pRes->tuplePos, currentRow);
18,681,588✔
961
    } else {
962
      code = setNullSelectivityValue(pCtx, pBlock, currentRow);
2,071✔
963
    }
964
  }
965

966
  return code;
62,644,723✔
967
}
968

969
int32_t setNullSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t rowIndex) {
2,413,603✔
970
  if (pCtx->subsidiaries.num <= 0) {
2,413,603✔
971
    return TSDB_CODE_SUCCESS;
2,411,546✔
972
  }
973

974
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
5,665✔
975
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
3,608✔
976
    int32_t         dstSlotId = pc->pExpr->base.resSchema.slotId;
3,608✔
977

978
    SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
3,608✔
979
    if (NULL == pDstCol) {
3,608!
UNCOV
980
      return terrno;
×
981
    }
982
    colDataSetNULL(pDstCol, rowIndex);
3,608✔
983
  }
984

985
  return TSDB_CODE_SUCCESS;
2,057✔
986
}
987

988
int32_t setSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, const STuplePos* pTuplePos, int32_t rowIndex) {
254,354,858✔
989
  if (pCtx->subsidiaries.num <= 0) {
254,354,858✔
990
    return TSDB_CODE_SUCCESS;
111,866,662✔
991
  }
992

993
  if ((pCtx->saveHandle.pBuf != NULL && pTuplePos->pageId != -1) ||
142,488,196!
UNCOV
994
      (pCtx->saveHandle.pState && pTuplePos->streamTupleKey.ts > 0)) {
×
995
    int32_t numOfCols = pCtx->subsidiaries.num;
142,490,851✔
996
    char*   p = NULL;
142,490,851✔
997
    int32_t code = loadTupleData(pCtx, pTuplePos, &p);
142,490,851✔
998
    if (p == NULL || TSDB_CODE_SUCCESS != code) {
142,802,676!
UNCOV
999
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
×
1000
             pTuplePos->streamTupleKey.groupId, pTuplePos->streamTupleKey.ts);
UNCOV
1001
      return TSDB_CODE_NOT_FOUND;
×
1002
    }
1003

1004
    bool* nullList = (bool*)p;
142,811,824✔
1005
    char* pStart = (char*)(nullList + numOfCols * sizeof(bool));
142,811,824✔
1006

1007
    // todo set the offset value to optimize the performance.
1008
    for (int32_t j = 0; j < numOfCols; ++j) {
285,477,957✔
1009
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
142,824,480✔
1010
      int32_t         dstSlotId = pc->pExpr->base.resSchema.slotId;
142,824,480✔
1011

1012
      SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
142,824,480✔
1013
      if (NULL == pDstCol) {
142,776,560!
UNCOV
1014
        return terrno;
×
1015
      }
1016
      if (nullList[j]) {
142,780,350✔
1017
        colDataSetNULL(pDstCol, rowIndex);
142!
1018
      } else {
1019
        code = colDataSetValOrCover(pDstCol, rowIndex, pStart, false);
142,780,208✔
1020
        if (TSDB_CODE_SUCCESS != code) {
142,665,991!
1021
          return code;
×
1022
        }
1023
      }
1024
      pStart += pDstCol->info.bytes;
142,666,133✔
1025
    }
1026
  }
1027

1028
  return TSDB_CODE_SUCCESS;
142,650,822✔
1029
}
1030

1031
// This function append the selectivity to subsidiaries function context directly, without fetching data
1032
// from intermediate disk based buf page
1033
int32_t appendSelectivityValue(SqlFunctionCtx* pCtx, int32_t rowIndex, int32_t pos) {
56,057,285✔
1034
  if (pCtx->subsidiaries.num <= 0) {
56,057,285!
UNCOV
1035
    return TSDB_CODE_SUCCESS;
×
1036
  }
1037

1038
  int32_t code = TSDB_CODE_SUCCESS;
56,057,285✔
1039
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
112,111,381✔
1040
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
56,060,174✔
1041

1042
    // get data from source col
1043
    SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
56,060,174✔
1044
    int32_t      srcSlotId = pFuncParam->pCol->slotId;
56,060,174✔
1045

1046
    SColumnInfoData* pSrcCol = taosArrayGet(pCtx->pSrcBlock->pDataBlock, srcSlotId);
56,060,174✔
1047
    if (NULL == pSrcCol) {
56,057,008!
UNCOV
1048
      return TSDB_CODE_OUT_OF_RANGE;
×
1049
    }
1050

1051
    char* pData = colDataGetData(pSrcCol, rowIndex);
56,057,008!
1052

1053
    // append to dest col
1054
    int32_t dstSlotId = pc->pExpr->base.resSchema.slotId;
56,057,008✔
1055

1056
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
56,057,008✔
1057
    if (NULL == pDstCol) {
56,048,329!
UNCOV
1058
      return TSDB_CODE_OUT_OF_RANGE;
×
1059
    }
1060

1061
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
112,096,658✔
1062
      colDataSetNULL(pDstCol, pos);
392✔
1063
    } else {
1064
      code = colDataSetVal(pDstCol, pos, pData, false);
56,047,937✔
1065
      if (TSDB_CODE_SUCCESS != code) {
56,053,704!
UNCOV
1066
        return code;
×
1067
      }
1068
    }
1069
  }
1070
  return code;
56,051,207✔
1071
}
1072

1073
void replaceTupleData(STuplePos* pDestPos, STuplePos* pSourcePos) { *pDestPos = *pSourcePos; }
30✔
1074

1075
#define COMPARE_MINMAX_DATA(type) (((*(type*)&pDBuf->v) < (*(type*)&pSBuf->v)) ^ isMinFunc)
1076
int32_t minMaxCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx, int32_t isMinFunc) {
66✔
1077
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
66✔
1078
  SMinmaxResInfo*      pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
66✔
1079

1080
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
66✔
1081
  SMinmaxResInfo*      pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
66✔
1082
  int16_t              type = pDBuf->type == TSDB_DATA_TYPE_NULL ? pSBuf->type : pDBuf->type;
66✔
1083

1084
  switch (type) {
66!
1085
    case TSDB_DATA_TYPE_UBIGINT:
×
1086
    case TSDB_DATA_TYPE_BIGINT:
UNCOV
1087
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int64_t) || !pDBuf->assign)) {
×
1088
        pDBuf->v = pSBuf->v;
×
UNCOV
1089
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
UNCOV
1090
        pDBuf->assign = true;
×
1091
      }
UNCOV
1092
      break;
×
1093
    case TSDB_DATA_TYPE_UINT:
47✔
1094
    case TSDB_DATA_TYPE_INT:
1095
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int32_t) || !pDBuf->assign)) {
47!
1096
        pDBuf->v = pSBuf->v;
25✔
1097
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
25✔
1098
        pDBuf->assign = true;
25✔
1099
      }
1100
      break;
47✔
UNCOV
1101
    case TSDB_DATA_TYPE_USMALLINT:
×
1102
    case TSDB_DATA_TYPE_SMALLINT:
UNCOV
1103
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int16_t) || !pDBuf->assign)) {
×
UNCOV
1104
        pDBuf->v = pSBuf->v;
×
UNCOV
1105
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
UNCOV
1106
        pDBuf->assign = true;
×
1107
      }
UNCOV
1108
      break;
×
UNCOV
1109
    case TSDB_DATA_TYPE_BOOL:
×
1110
    case TSDB_DATA_TYPE_UTINYINT:
1111
    case TSDB_DATA_TYPE_TINYINT:
UNCOV
1112
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int8_t) || !pDBuf->assign)) {
×
UNCOV
1113
        pDBuf->v = pSBuf->v;
×
1114
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
UNCOV
1115
        pDBuf->assign = true;
×
1116
      }
UNCOV
1117
      break;
×
1118
    case TSDB_DATA_TYPE_DOUBLE:
3✔
1119
    case TSDB_DATA_TYPE_FLOAT: {
1120
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(double) || !pDBuf->assign)) {
3!
1121
        pDBuf->v = pSBuf->v;
1✔
1122
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
1✔
1123
        pDBuf->assign = true;
1✔
1124
      }
1125
      break;
3✔
1126
    }
1127
    case TSDB_DATA_TYPE_DECIMAL64: {
8✔
1128
      const SDecimalOps* pOps = getDecimalOps(type);
8✔
1129
      if (pSBuf->assign && ((pOps->lt(&pDBuf->v, &pSBuf->v, DECIMAL_WORD_NUM(Decimal64)) ^ isMinFunc) || !pDBuf->assign)) {
8!
1130
        pDBuf->v = pSBuf->v;
2✔
1131
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
2✔
1132
        pDBuf->assign = true;
2✔
1133
      }
1134
    } break;
8✔
1135
    case TSDB_DATA_TYPE_DECIMAL: {
8✔
1136
      const SDecimalOps* pOps = getDecimalOps(type);
8✔
1137
      if (pSBuf->assign && (pOps->lt(pDBuf->dec, pSBuf->dec, DECIMAL_WORD_NUM(Decimal)) ^ isMinFunc) || !pDBuf->assign) {
8!
1138
        memcpy(pDBuf->dec, pSBuf->dec, DECIMAL128_BYTES);
2✔
1139
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
2✔
1140
        pDBuf->assign = true;
2✔
1141
      }
1142
    } break;
8✔
UNCOV
1143
    default:
×
UNCOV
1144
      if (pSBuf->assign && (strcmp(pDBuf->str, pSBuf->str) || !pDBuf->assign)) {
×
UNCOV
1145
        memcpy(pDBuf->str, pSBuf->str, varDataLen(pSBuf->str));
×
UNCOV
1146
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
UNCOV
1147
        pDBuf->assign = true;
×
1148
      }
UNCOV
1149
      break;
×
1150
  }
1151
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
66✔
1152
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
66✔
1153
  return TSDB_CODE_SUCCESS;
66✔
1154
}
1155

1156
int32_t minCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
19✔
1157
  return minMaxCombine(pDestCtx, pSourceCtx, 1);
19✔
1158
}
1159
int32_t maxCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
47✔
1160
  return minMaxCombine(pDestCtx, pSourceCtx, 0);
47✔
1161
}
1162

1163
int32_t getStdInfoSize() { return (int32_t)sizeof(SStdRes); }
786,494✔
1164

1165
bool getStdFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
153,829✔
1166
  pEnv->calcMemSize = sizeof(SStdRes);
153,829✔
1167
  return true;
153,829✔
1168
}
1169

1170
int32_t stdFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
5,644,422✔
1171
  if (pResultInfo->initialized) {
5,644,422!
UNCOV
1172
    return TSDB_CODE_SUCCESS;
×
1173
  }
1174
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
5,644,422!
UNCOV
1175
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1176
  }
1177

1178
  SStdRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
5,644,455✔
1179
  (void)memset(pRes, 0, sizeof(SStdRes));
5,644,455✔
1180
  return TSDB_CODE_SUCCESS;
5,644,455✔
1181
}
1182

1183
int32_t stdFunction(SqlFunctionCtx* pCtx) {
4,892,112✔
1184
  int32_t numOfElem = 0;
4,892,112✔
1185

1186
  // Only the pre-computing information loaded and actual data does not loaded
1187
  SInputColumnInfoData* pInput = &pCtx->input;
4,892,112✔
1188
  int32_t               type = pInput->pData[0]->info.type;
4,892,112✔
1189

1190
  SStdRes* pStdRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4,892,112✔
1191
  pStdRes->type = type;
4,892,112✔
1192

1193
  // computing based on the true data block
1194
  SColumnInfoData* pCol = pInput->pData[0];
4,892,112✔
1195

1196
  int32_t start = pInput->startRowIndex;
4,892,112✔
1197
  int32_t numOfRows = pInput->numOfRows;
4,892,112✔
1198

1199
  if (IS_NULL_TYPE(type)) {
4,892,112✔
1200
    numOfElem = 0;
131✔
1201
    goto _stddev_over;
131✔
1202
  }
1203

1204
  switch (type) {
4,891,981!
1205
    case TSDB_DATA_TYPE_TINYINT: {
17,155✔
1206
      int8_t* plist = (int8_t*)pCol->pData;
17,155✔
1207
      for (int32_t i = start; i < numOfRows + start; ++i) {
706,886✔
1208
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
689,731✔
1209
          continue;
106,910✔
1210
        }
1211

1212
        numOfElem += 1;
582,821✔
1213
        pStdRes->count += 1;
582,821✔
1214
        pStdRes->isum += plist[i];
582,821✔
1215
        pStdRes->quadraticISum += plist[i] * plist[i];
582,821✔
1216
      }
1217

1218
      break;
17,155✔
1219
    }
1220

1221
    case TSDB_DATA_TYPE_SMALLINT: {
2,246,750✔
1222
      int16_t* plist = (int16_t*)pCol->pData;
2,246,750✔
1223
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
7,863,407✔
1224
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
5,616,657✔
1225
          continue;
113,338✔
1226
        }
1227

1228
        numOfElem += 1;
5,503,319✔
1229
        pStdRes->count += 1;
5,503,319✔
1230
        pStdRes->isum += plist[i];
5,503,319✔
1231
        pStdRes->quadraticISum += plist[i] * plist[i];
5,503,319✔
1232
      }
1233
      break;
2,246,750✔
1234
    }
1235

1236
    case TSDB_DATA_TYPE_INT: {
22,427✔
1237
      int32_t* plist = (int32_t*)pCol->pData;
22,427✔
1238
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
332,296✔
1239
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
309,869✔
1240
          continue;
98,553✔
1241
        }
1242

1243
        numOfElem += 1;
211,316✔
1244
        pStdRes->count += 1;
211,316✔
1245
        pStdRes->isum += plist[i];
211,316✔
1246
        pStdRes->quadraticISum += plist[i] * plist[i];
211,316✔
1247
      }
1248

1249
      break;
22,427✔
1250
    }
1251

1252
    case TSDB_DATA_TYPE_BIGINT: {
21,393✔
1253
      int64_t* plist = (int64_t*)pCol->pData;
21,393✔
1254
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
740,295✔
1255
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
718,902✔
1256
          continue;
27,169✔
1257
        }
1258

1259
        numOfElem += 1;
691,733✔
1260
        pStdRes->count += 1;
691,733✔
1261
        pStdRes->isum += plist[i];
691,733✔
1262
        pStdRes->quadraticISum += plist[i] * plist[i];
691,733✔
1263
      }
1264
      break;
21,393✔
1265
    }
1266

1267
    case TSDB_DATA_TYPE_UTINYINT: {
1✔
1268
      uint8_t* plist = (uint8_t*)pCol->pData;
1✔
1269
      for (int32_t i = start; i < numOfRows + start; ++i) {
8✔
1270
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
7!
1271
          continue;
4✔
1272
        }
1273

1274
        numOfElem += 1;
3✔
1275
        pStdRes->count += 1;
3✔
1276
        pStdRes->usum += plist[i];
3✔
1277
        pStdRes->quadraticUSum += plist[i] * plist[i];
3✔
1278
      }
1279

1280
      break;
1✔
1281
    }
1282

UNCOV
1283
    case TSDB_DATA_TYPE_USMALLINT: {
×
UNCOV
1284
      uint16_t* plist = (uint16_t*)pCol->pData;
×
UNCOV
1285
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
×
UNCOV
1286
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
×
UNCOV
1287
          continue;
×
1288
        }
1289

UNCOV
1290
        numOfElem += 1;
×
UNCOV
1291
        pStdRes->count += 1;
×
UNCOV
1292
        pStdRes->usum += plist[i];
×
UNCOV
1293
        pStdRes->quadraticUSum += plist[i] * plist[i];
×
1294
      }
UNCOV
1295
      break;
×
1296
    }
1297

1298
    case TSDB_DATA_TYPE_UINT: {
1✔
1299
      uint32_t* plist = (uint32_t*)pCol->pData;
1✔
1300
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
6✔
1301
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
5!
UNCOV
1302
          continue;
×
1303
        }
1304

1305
        numOfElem += 1;
5✔
1306
        pStdRes->count += 1;
5✔
1307
        pStdRes->usum += plist[i];
5✔
1308
        pStdRes->quadraticUSum += plist[i] * plist[i];
5✔
1309
      }
1310

1311
      break;
1✔
1312
    }
1313

UNCOV
1314
    case TSDB_DATA_TYPE_UBIGINT: {
×
UNCOV
1315
      uint64_t* plist = (uint64_t*)pCol->pData;
×
UNCOV
1316
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
×
UNCOV
1317
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
×
UNCOV
1318
          continue;
×
1319
        }
1320

UNCOV
1321
        numOfElem += 1;
×
UNCOV
1322
        pStdRes->count += 1;
×
UNCOV
1323
        pStdRes->usum += plist[i];
×
UNCOV
1324
        pStdRes->quadraticUSum += plist[i] * plist[i];
×
1325
      }
UNCOV
1326
      break;
×
1327
    }
1328

1329
    case TSDB_DATA_TYPE_FLOAT: {
2,534,702✔
1330
      float* plist = (float*)pCol->pData;
2,534,702✔
1331
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
10,519,091✔
1332
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
7,984,389✔
1333
          continue;
23,748✔
1334
        }
1335

1336
        numOfElem += 1;
7,960,641✔
1337
        pStdRes->count += 1;
7,960,641✔
1338
        pStdRes->dsum += plist[i];
7,960,641✔
1339
        pStdRes->quadraticDSum += plist[i] * plist[i];
7,960,641✔
1340
      }
1341
      break;
2,534,702✔
1342
    }
1343

1344
    case TSDB_DATA_TYPE_DOUBLE: {
49,575✔
1345
      double* plist = (double*)pCol->pData;
49,575✔
1346
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
2,316,637✔
1347
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
2,267,062✔
1348
          continue;
670,276✔
1349
        }
1350

1351
        numOfElem += 1;
1,596,786✔
1352
        pStdRes->count += 1;
1,596,786✔
1353
        pStdRes->dsum += plist[i];
1,596,786✔
1354
        pStdRes->quadraticDSum += plist[i] * plist[i];
1,596,786✔
1355
      }
1356
      break;
49,575✔
1357
    }
1358

UNCOV
1359
    default:
×
UNCOV
1360
      break;
×
1361
  }
1362

1363
_stddev_over:
4,892,112✔
1364
  // data in the check operation are all null, not output
1365
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
4,892,112✔
1366
  return TSDB_CODE_SUCCESS;
4,892,112✔
1367
}
1368

1369
static void stdTransferInfo(SStdRes* pInput, SStdRes* pOutput) {
784,981✔
1370
  if (IS_NULL_TYPE(pInput->type)) {
784,981✔
1371
    return;
80✔
1372
  }
1373
  pOutput->type = pInput->type;
784,901✔
1374
  if (IS_SIGNED_NUMERIC_TYPE(pOutput->type)) {
784,901!
1375
    pOutput->quadraticISum += pInput->quadraticISum;
782,651✔
1376
    pOutput->isum += pInput->isum;
782,651✔
1377
  } else if (IS_UNSIGNED_NUMERIC_TYPE(pOutput->type)) {
2,250!
1378
    pOutput->quadraticUSum += pInput->quadraticUSum;
1✔
1379
    pOutput->usum += pInput->usum;
1✔
1380
  } else {
1381
    pOutput->quadraticDSum += pInput->quadraticDSum;
2,249✔
1382
    pOutput->dsum += pInput->dsum;
2,249✔
1383
  }
1384

1385
  pOutput->count += pInput->count;
784,901✔
1386
}
1387

1388
int32_t stdFunctionMerge(SqlFunctionCtx* pCtx) {
784,882✔
1389
  SInputColumnInfoData* pInput = &pCtx->input;
784,882✔
1390
  SColumnInfoData*      pCol = pInput->pData[0];
784,882✔
1391

1392
  if (IS_NULL_TYPE(pCol->info.type)) {
784,882!
UNCOV
1393
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
UNCOV
1394
    return TSDB_CODE_SUCCESS;
×
1395
  }
1396

1397
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
784,882!
UNCOV
1398
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
1399
  }
1400

1401
  SStdRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
784,882✔
1402

1403
  for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
1,569,860✔
1404
    if (colDataIsNull_s(pCol, i)) continue;
1,569,956!
1405
    char*    data = colDataGetData(pCol, i);
784,978!
1406
    SStdRes* pInputInfo = (SStdRes*)varDataVal(data);
784,978✔
1407
    stdTransferInfo(pInputInfo, pInfo);
784,978✔
1408
  }
1409

1410
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
784,882✔
1411
  return TSDB_CODE_SUCCESS;
784,882✔
1412
}
1413

1414
#ifdef BUILD_NO_CALL
1415
int32_t stdInvertFunction(SqlFunctionCtx* pCtx) {
1416
  int32_t numOfElem = 0;
1417

1418
  // Only the pre-computing information loaded and actual data does not loaded
1419
  SInputColumnInfoData* pInput = &pCtx->input;
1420
  int32_t               type = pInput->pData[0]->info.type;
1421

1422
  SStdRes* pStdRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1423

1424
  // computing based on the true data block
1425
  SColumnInfoData* pCol = pInput->pData[0];
1426

1427
  int32_t start = pInput->startRowIndex;
1428
  int32_t numOfRows = pInput->numOfRows;
1429

1430
  switch (type) {
1431
    case TSDB_DATA_TYPE_TINYINT: {
1432
      LIST_STDDEV_SUB_N(pStdRes->isum, int8_t);
1433
      break;
1434
    }
1435
    case TSDB_DATA_TYPE_SMALLINT: {
1436
      LIST_STDDEV_SUB_N(pStdRes->isum, int16_t);
1437
      break;
1438
    }
1439
    case TSDB_DATA_TYPE_INT: {
1440
      LIST_STDDEV_SUB_N(pStdRes->isum, int32_t);
1441
      break;
1442
    }
1443
    case TSDB_DATA_TYPE_BIGINT: {
1444
      LIST_STDDEV_SUB_N(pStdRes->isum, int64_t);
1445
      break;
1446
    }
1447
    case TSDB_DATA_TYPE_UTINYINT: {
1448
      LIST_STDDEV_SUB_N(pStdRes->isum, uint8_t);
1449
      break;
1450
    }
1451
    case TSDB_DATA_TYPE_USMALLINT: {
1452
      LIST_STDDEV_SUB_N(pStdRes->isum, uint16_t);
1453
      break;
1454
    }
1455
    case TSDB_DATA_TYPE_UINT: {
1456
      LIST_STDDEV_SUB_N(pStdRes->isum, uint32_t);
1457
      break;
1458
    }
1459
    case TSDB_DATA_TYPE_UBIGINT: {
1460
      LIST_STDDEV_SUB_N(pStdRes->isum, uint64_t);
1461
      break;
1462
    }
1463
    case TSDB_DATA_TYPE_FLOAT: {
1464
      LIST_STDDEV_SUB_N(pStdRes->dsum, float);
1465
      break;
1466
    }
1467
    case TSDB_DATA_TYPE_DOUBLE: {
1468
      LIST_STDDEV_SUB_N(pStdRes->dsum, double);
1469
      break;
1470
    }
1471
    default:
1472
      break;
1473
  }
1474

1475
  // data in the check operation are all null, not output
1476
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
1477
  return TSDB_CODE_SUCCESS;
1478
}
1479
#endif
1480

1481
int32_t stddevFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
4,833,332✔
1482
  SInputColumnInfoData* pInput = &pCtx->input;
4,833,332✔
1483
  SStdRes*              pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4,833,332✔
1484
  int32_t               type = pStddevRes->type;
4,833,332✔
1485
  double                avg;
1486

1487
  if (pStddevRes->count == 0) {
4,833,332✔
1488
    GET_RES_INFO(pCtx)->numOfRes = 0;
56,490✔
1489
    return functionFinalize(pCtx, pBlock);
56,490✔
1490
  }
1491

1492
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
4,776,842!
1493
    avg = pStddevRes->isum / ((double)pStddevRes->count);
2,223,476✔
1494
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticISum / ((double)pStddevRes->count) - avg * avg));
2,223,476✔
1495
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
2,553,366!
1496
    avg = pStddevRes->usum / ((double)pStddevRes->count);
2✔
1497
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticUSum / ((double)pStddevRes->count) - avg * avg));
2✔
1498
  } else {
1499
    avg = pStddevRes->dsum / ((double)pStddevRes->count);
2,553,364✔
1500
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticDSum / ((double)pStddevRes->count) - avg * avg));
2,553,364✔
1501
  }
1502

1503
  // check for overflow
1504
  if (isinf(pStddevRes->result) || isnan(pStddevRes->result)) {
4,776,842!
UNCOV
1505
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1506
  }
1507

1508
  return functionFinalize(pCtx, pBlock);
4,776,842✔
1509
}
1510

UNCOV
1511
int32_t stdvarFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
UNCOV
1512
  SInputColumnInfoData* pInput = &pCtx->input;
×
UNCOV
1513
  SStdRes*              pStdvarRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
UNCOV
1514
  int32_t               type = pStdvarRes->type;
×
1515
  double                avg;
1516

UNCOV
1517
  if (pStdvarRes->count == 0) {
×
UNCOV
1518
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
UNCOV
1519
    return functionFinalize(pCtx, pBlock);
×
1520
  }
1521

UNCOV
1522
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
×
UNCOV
1523
    avg = pStdvarRes->isum / ((double)pStdvarRes->count);
×
UNCOV
1524
    pStdvarRes->result = fabs(pStdvarRes->quadraticISum / ((double)pStdvarRes->count) - avg * avg);
×
UNCOV
1525
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
UNCOV
1526
    avg = pStdvarRes->usum / ((double)pStdvarRes->count);
×
1527
    pStdvarRes->result = fabs(pStdvarRes->quadraticUSum / ((double)pStdvarRes->count) - avg * avg);
×
1528
  } else {
UNCOV
1529
    avg = pStdvarRes->dsum / ((double)pStdvarRes->count);
×
1530
    pStdvarRes->result = fabs(pStdvarRes->quadraticDSum / ((double)pStdvarRes->count) - avg * avg);
×
1531
  }
1532

1533
  // check for overflow
UNCOV
1534
  if (isinf(pStdvarRes->result) || isnan(pStdvarRes->result)) {
×
UNCOV
1535
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1536
  }
1537

UNCOV
1538
  return functionFinalize(pCtx, pBlock);
×
1539
}
1540

1541
int32_t stdPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
784,884✔
1542
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
784,884✔
1543
  SStdRes*             pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
784,884✔
1544
  int32_t              resultBytes = getStdInfoSize();
784,884✔
1545
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
784,883!
1546

1547
  if (NULL == res) {
784,886!
UNCOV
1548
    return terrno;
×
1549
  }
1550
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
784,886✔
1551
  varDataSetLen(res, resultBytes);
784,886✔
1552

1553
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
784,886✔
1554
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
784,886✔
1555
  if (NULL == pCol) {
784,886!
UNCOV
1556
    taosMemoryFree(res);
×
UNCOV
1557
    return TSDB_CODE_OUT_OF_RANGE;
×
1558
  }
1559

1560
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
784,886✔
1561

1562
  taosMemoryFree(res);
784,886!
1563
  return code;
784,886✔
1564
}
1565

1566
int32_t stdCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
3✔
1567
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
3✔
1568
  SStdRes*             pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
3✔
1569

1570
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
3✔
1571
  SStdRes*             pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
3✔
1572
  int16_t              type = pDBuf->type == TSDB_DATA_TYPE_NULL ? pSBuf->type : pDBuf->type;
3!
1573

1574
  stdTransferInfo(pSBuf, pDBuf);
3✔
1575

1576
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
3✔
1577
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
3✔
1578
  return TSDB_CODE_SUCCESS;
3✔
1579
}
1580

1581
bool getLeastSQRFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
42,801✔
1582
  pEnv->calcMemSize = sizeof(SLeastSQRInfo);
42,801✔
1583
  return true;
42,801✔
1584
}
1585

1586
int32_t leastSQRFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
4,228,866✔
1587
  if (pResultInfo->initialized) {
4,228,866!
UNCOV
1588
    return TSDB_CODE_SUCCESS;
×
1589
  }
1590
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
4,228,866!
UNCOV
1591
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1592
  }
1593

1594
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
4,228,868✔
1595

1596
  GET_TYPED_DATA(pInfo->startVal, double, pCtx->param[1].param.nType, &pCtx->param[1].param.i,
4,228,868!
1597
                 typeGetTypeModFromCol(pCtx->param[1].pCol));
1598
  GET_TYPED_DATA(pInfo->stepVal, double, pCtx->param[2].param.nType, &pCtx->param[2].param.i,
4,228,860!
1599
                 typeGetTypeModFromCol(pCtx->param[2].pCol));
1600
  return TSDB_CODE_SUCCESS;
4,228,862✔
1601
}
1602

1603
int32_t leastSQRFunction(SqlFunctionCtx* pCtx) {
4,232,063✔
1604
  int32_t numOfElem = 0;
4,232,063✔
1605

1606
  SInputColumnInfoData* pInput = &pCtx->input;
4,232,063✔
1607
  int32_t               type = pInput->pData[0]->info.type;
4,232,063✔
1608

1609
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4,232,063✔
1610

1611
  SColumnInfoData* pCol = pInput->pData[0];
4,232,063✔
1612

1613
  double(*param)[3] = pInfo->matrix;
4,232,063✔
1614
  double x = pInfo->startVal;
4,232,063✔
1615

1616
  int32_t start = pInput->startRowIndex;
4,232,063✔
1617
  int32_t numOfRows = pInput->numOfRows;
4,232,063✔
1618

1619
  switch (type) {
4,232,063!
1620
    case TSDB_DATA_TYPE_TINYINT: {
4,830✔
1621
      int8_t* plist = (int8_t*)pCol->pData;
4,830✔
1622
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
154,736✔
1623
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
149,906✔
1624
          continue;
139,942✔
1625
        }
1626
        numOfElem++;
9,964✔
1627
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
9,964✔
1628
      }
1629
      break;
4,830✔
1630
    }
1631
    case TSDB_DATA_TYPE_SMALLINT: {
5,082✔
1632
      int16_t* plist = (int16_t*)pCol->pData;
5,082✔
1633
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
409,485✔
1634
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
404,403✔
1635
          continue;
138,955✔
1636
        }
1637

1638
        numOfElem++;
265,448✔
1639
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
265,448✔
1640
      }
1641
      break;
5,082✔
1642
    }
1643

1644
    case TSDB_DATA_TYPE_INT: {
19,374✔
1645
      int32_t* plist = (int32_t*)pCol->pData;
19,374✔
1646
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
479,400✔
1647
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
460,026✔
1648
          continue;
151,600✔
1649
        }
1650

1651
        numOfElem++;
308,426✔
1652
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
308,426✔
1653
      }
1654
      break;
19,374✔
1655
    }
1656

1657
    case TSDB_DATA_TYPE_BIGINT: {
4,185,563✔
1658
      int64_t* plist = (int64_t*)pCol->pData;
4,185,563✔
1659
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
12,712,974✔
1660
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
8,527,411✔
1661
          continue;
1,436✔
1662
        }
1663

1664
        numOfElem++;
8,525,975✔
1665
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
8,525,975✔
1666
      }
1667
      break;
4,185,563✔
1668
    }
1669

1670
    case TSDB_DATA_TYPE_UTINYINT: {
78✔
1671
      uint8_t* plist = (uint8_t*)pCol->pData;
78✔
1672
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
330✔
1673
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
252!
1674
          continue;
66✔
1675
        }
1676
        numOfElem++;
186✔
1677
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
186✔
1678
      }
1679
      break;
78✔
1680
    }
1681
    case TSDB_DATA_TYPE_USMALLINT: {
78✔
1682
      uint16_t* plist = (uint16_t*)pCol->pData;
78✔
1683
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
330✔
1684
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
252!
1685
          continue;
60✔
1686
        }
1687

1688
        numOfElem++;
192✔
1689
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
192✔
1690
      }
1691
      break;
78✔
1692
    }
1693

1694
    case TSDB_DATA_TYPE_UINT: {
78✔
1695
      uint32_t* plist = (uint32_t*)pCol->pData;
78✔
1696
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
330✔
1697
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
252!
1698
          continue;
60✔
1699
        }
1700

1701
        numOfElem++;
192✔
1702
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
192✔
1703
      }
1704
      break;
78✔
1705
    }
1706

1707
    case TSDB_DATA_TYPE_UBIGINT: {
78✔
1708
      uint64_t* plist = (uint64_t*)pCol->pData;
78✔
1709
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
330✔
1710
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
252!
1711
          continue;
60✔
1712
        }
1713

1714
        numOfElem++;
192✔
1715
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
192✔
1716
      }
1717
      break;
78✔
1718
    }
1719

1720
    case TSDB_DATA_TYPE_FLOAT: {
6,422✔
1721
      float* plist = (float*)pCol->pData;
6,422✔
1722
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
336,755✔
1723
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
330,333✔
1724
          continue;
2,836✔
1725
        }
1726

1727
        numOfElem++;
327,497✔
1728
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
327,497✔
1729
      }
1730
      break;
6,422✔
1731
    }
1732

1733
    case TSDB_DATA_TYPE_DOUBLE: {
10,477✔
1734
      double* plist = (double*)pCol->pData;
10,477✔
1735
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
166,973✔
1736
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
156,496✔
1737
          continue;
150,116✔
1738
        }
1739

1740
        numOfElem++;
6,380✔
1741
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
6,380✔
1742
      }
1743
      break;
10,477✔
1744
    }
UNCOV
1745
    case TSDB_DATA_TYPE_NULL: {
×
UNCOV
1746
      GET_RES_INFO(pCtx)->isNullRes = 1;
×
UNCOV
1747
      numOfElem = 1;
×
UNCOV
1748
      break;
×
1749
    }
1750

1751
    default:
3✔
1752
      break;
3✔
1753
  }
1754

1755
  pInfo->startVal = x;
4,232,063✔
1756
  pInfo->num += numOfElem;
4,232,063✔
1757

1758
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
4,232,063✔
1759

1760
  return TSDB_CODE_SUCCESS;
4,232,063✔
1761
}
1762

1763
int32_t leastSQRFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
4,218,180✔
1764
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
4,218,180✔
1765
  SLeastSQRInfo*       pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4,218,180✔
1766
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
4,218,180✔
1767
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
4,218,180✔
1768

1769
  if (NULL == pCol) {
4,218,180!
1770
    return TSDB_CODE_OUT_OF_RANGE;
×
1771
  }
1772
  int32_t currentRow = pBlock->info.rows;
4,218,180✔
1773

1774
  if (0 == pInfo->num) {
4,218,180✔
1775
    colDataSetNULL(pCol, currentRow);
24,080!
1776
    return TSDB_CODE_SUCCESS;
24,080✔
1777
  }
1778

1779
  double(*param)[3] = pInfo->matrix;
4,194,100✔
1780

1781
  param[1][1] = (double)pInfo->num;
4,194,100✔
1782
  param[1][0] = param[0][1];
4,194,100✔
1783

1784
  double param00 = param[0][0] - param[1][0] * (param[0][1] / param[1][1]);
4,194,100✔
1785
  double param02 = param[0][2] - param[1][2] * (param[0][1] / param[1][1]);
4,194,100✔
1786

1787
  if (0 == param00) {
4,194,100✔
1788
    colDataSetNULL(pCol, currentRow);
3,795,995!
1789
    return TSDB_CODE_SUCCESS;
3,795,995✔
1790
  }
1791

1792
  // param[0][1] = 0;
1793
  double param12 = param[1][2] - param02 * (param[1][0] / param00);
398,105✔
1794
  // param[1][0] = 0;
1795
  param02 /= param00;
398,105✔
1796

1797
  param12 /= param[1][1];
398,105✔
1798

1799
  char buf[LEASTSQUARES_BUFF_LENGTH] = {0};
398,105✔
1800
  char slopBuf[64] = {0};
398,105✔
1801
  char interceptBuf[64] = {0};
398,105✔
1802
  int  n = tsnprintf(slopBuf, 64, "%.6lf", param02);
398,105✔
1803
  if (n > LEASTSQUARES_DOUBLE_ITEM_LENGTH) {
398,111✔
1804
    (void)snprintf(slopBuf, 64, "%." DOUBLE_PRECISION_DIGITS, param02);
6✔
1805
  }
1806
  n = tsnprintf(interceptBuf, 64, "%.6lf", param12);
398,111✔
1807
  if (n > LEASTSQUARES_DOUBLE_ITEM_LENGTH) {
398,111✔
1808
    (void)snprintf(interceptBuf, 64, "%." DOUBLE_PRECISION_DIGITS, param12);
369,833✔
1809
  }
1810
  size_t len =
398,111✔
1811
      snprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE, "{slop:%s, intercept:%s}", slopBuf, interceptBuf);
398,111✔
1812
  varDataSetLen(buf, len);
398,111✔
1813

1814
  int32_t code = colDataSetVal(pCol, currentRow, buf, pResInfo->isNullRes);
398,111✔
1815

1816
  return code;
398,111✔
1817
}
1818

UNCOV
1819
int32_t leastSQRCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
UNCOV
1820
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
UNCOV
1821
  SLeastSQRInfo*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
UNCOV
1822
  int32_t              type = pDestCtx->input.pData[0]->info.type;
×
UNCOV
1823
  double(*pDparam)[3] = pDBuf->matrix;
×
1824

UNCOV
1825
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
UNCOV
1826
  SLeastSQRInfo*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
UNCOV
1827
  double(*pSparam)[3] = pSBuf->matrix;
×
UNCOV
1828
  for (int32_t i = 0; i < pSBuf->num; i++) {
×
UNCOV
1829
    pDparam[0][0] += pDBuf->startVal * pDBuf->startVal;
×
UNCOV
1830
    pDparam[0][1] += pDBuf->startVal;
×
UNCOV
1831
    pDBuf->startVal += pDBuf->stepVal;
×
1832
  }
UNCOV
1833
  pDparam[0][2] += pSparam[0][2] + pDBuf->num * pDBuf->stepVal * pSparam[1][2];
×
1834
  pDparam[1][2] += pSparam[1][2];
×
UNCOV
1835
  pDBuf->num += pSBuf->num;
×
UNCOV
1836
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
UNCOV
1837
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
UNCOV
1838
  return TSDB_CODE_SUCCESS;
×
1839
}
1840

1841
bool getPercentileFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
629✔
1842
  pEnv->calcMemSize = sizeof(SPercentileInfo);
629✔
1843
  return true;
629✔
1844
}
1845

1846
int32_t percentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
58,047✔
1847
  if (pResultInfo->initialized) {
58,047!
UNCOV
1848
    return TSDB_CODE_SUCCESS;
×
1849
  }
1850
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
58,047!
1851
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1852
  }
1853

1854
  // in the first round, get the min-max value of all involved data
1855
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
58,047✔
1856
  SET_DOUBLE_VAL(&pInfo->minval, DBL_MAX);
58,047✔
1857
  SET_DOUBLE_VAL(&pInfo->maxval, -DBL_MAX);
58,047✔
1858
  pInfo->numOfElems = 0;
58,047✔
1859

1860
  return TSDB_CODE_SUCCESS;
58,047✔
1861
}
1862

UNCOV
1863
void percentileFunctionCleanupExt(SqlFunctionCtx* pCtx) {
×
UNCOV
1864
  if (pCtx == NULL || GET_RES_INFO(pCtx) == NULL || GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)) == NULL) {
×
UNCOV
1865
    return;
×
1866
  }
UNCOV
1867
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
UNCOV
1868
  if (pInfo->pMemBucket != NULL) {
×
UNCOV
1869
    tMemBucketDestroy(&(pInfo->pMemBucket));
×
UNCOV
1870
    pInfo->pMemBucket = NULL;
×
1871
  }
1872
}
1873

1874
int32_t percentileFunction(SqlFunctionCtx* pCtx) {
2,192,214✔
1875
  int32_t              code = TSDB_CODE_SUCCESS;
2,192,214✔
1876
  int32_t              numOfElems = 0;
2,192,214✔
1877
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,192,214✔
1878

1879
  SInputColumnInfoData* pInput = &pCtx->input;
2,192,214✔
1880
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
2,192,214✔
1881

1882
  SColumnInfoData* pCol = pInput->pData[0];
2,192,214✔
1883
  int32_t          type = pCol->info.type;
2,192,214✔
1884

1885
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,192,214✔
1886
  if (pCtx->scanFlag == MAIN_SCAN && pInfo->stage == 0) {
2,192,214✔
1887
    pInfo->stage += 1;
58,047✔
1888

1889
    // all data are null, set it completed
1890
    if (pInfo->numOfElems == 0) {
58,047✔
1891
      pResInfo->complete = true;
1,408✔
1892
      return TSDB_CODE_SUCCESS;
1,408✔
1893
    } else {
1894
      code = tMemBucketCreate(pCol->info.bytes, type, typeGetTypeModFromColInfo(&pCol->info), pInfo->minval, pInfo->maxval, pCtx->hasWindowOrGroup,
56,639✔
1895
                              &pInfo->pMemBucket, pInfo->numOfElems);
56,639✔
1896
      if (TSDB_CODE_SUCCESS != code) {
56,639!
UNCOV
1897
        return code;
×
1898
      }
1899
    }
1900
  }
1901

1902
  // the first stage, only acquire the min/max value
1903
  if (pInfo->stage == 0) {
2,190,806✔
1904
    if (pCtx->input.colDataSMAIsSet) {
1,096,107✔
1905
      double tmin = 0.0, tmax = 0.0;
1,034,208✔
1906
      if (IS_SIGNED_NUMERIC_TYPE(type)) {
1,034,208!
UNCOV
1907
        tmin = (double)GET_INT64_VAL(&pAgg->min);
×
UNCOV
1908
        tmax = (double)GET_INT64_VAL(&pAgg->max);
×
1909
      } else if (IS_FLOAT_TYPE(type)) {
1,034,208!
1910
        tmin = GET_DOUBLE_VAL(&pAgg->min);
1,034,208✔
1911
        tmax = GET_DOUBLE_VAL(&pAgg->max);
1,034,208✔
UNCOV
1912
      } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
UNCOV
1913
        tmin = (double)GET_UINT64_VAL(&pAgg->min);
×
UNCOV
1914
        tmax = (double)GET_UINT64_VAL(&pAgg->max);
×
1915
      }
1916

1917
      if (GET_DOUBLE_VAL(&pInfo->minval) > tmin) {
1,034,208✔
1918
        SET_DOUBLE_VAL(&pInfo->minval, tmin);
14✔
1919
      }
1920

1921
      if (GET_DOUBLE_VAL(&pInfo->maxval) < tmax) {
1,034,208✔
1922
        SET_DOUBLE_VAL(&pInfo->maxval, tmax);
14✔
1923
      }
1924

1925
      pInfo->numOfElems += (pInput->numOfRows - pAgg->numOfNull);
1,034,208✔
1926
    } else {
1927
      // check the valid data one by one
1928
      int32_t start = pInput->startRowIndex;
61,899✔
1929
      for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
12,106,622✔
1930
        if (colDataIsNull_f(pCol->nullbitmap, i)) {
12,044,723✔
1931
          continue;
2,200✔
1932
        }
1933

1934
        char* data = colDataGetData(pCol, i);
12,042,523!
1935

1936
        double v = 0;
12,042,523✔
1937
        GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
12,042,523!
1938
        if (v < GET_DOUBLE_VAL(&pInfo->minval)) {
12,042,523✔
1939
          SET_DOUBLE_VAL(&pInfo->minval, v);
56,865✔
1940
        }
1941

1942
        if (v > GET_DOUBLE_VAL(&pInfo->maxval)) {
12,042,523✔
1943
          SET_DOUBLE_VAL(&pInfo->maxval, v);
462,175✔
1944
        }
1945

1946
        pInfo->numOfElems += 1;
12,042,523✔
1947
      }
1948
    }
1949
  } else {
1950
    // the second stage, calculate the true percentile value
1951
    int32_t start = pInput->startRowIndex;
1,094,699✔
1952
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
2,147,483,647✔
1953
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
2,147,483,647!
UNCOV
1954
        continue;
×
1955
      }
1956

1957
      char* data = colDataGetData(pCol, i);
2,147,483,647!
1958
      numOfElems += 1;
2,147,483,647✔
1959
      code = tMemBucketPut(pInfo->pMemBucket, data, 1);
2,147,483,647✔
1960
      if (code != TSDB_CODE_SUCCESS) {
2,147,483,647!
UNCOV
1961
        tMemBucketDestroy(&(pInfo->pMemBucket));
×
UNCOV
1962
        return code;
×
1963
      }
1964
    }
1965

1966
    SET_VAL(pResInfo, numOfElems, 1);
1,094,699!
1967
  }
1968

1969
  pCtx->needCleanup = true;
2,190,806✔
1970
  return TSDB_CODE_SUCCESS;
2,190,806✔
1971
}
1972

1973
int32_t percentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
58,047✔
1974
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
58,047✔
1975
  SPercentileInfo*     ppInfo = (SPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
58,047✔
1976

1977
  int32_t code = 0;
58,047✔
1978
  double  v = 0;
58,047✔
1979

1980
  tMemBucket** pMemBucket = &ppInfo->pMemBucket;
58,047✔
1981
  if ((*pMemBucket) != NULL && (*pMemBucket)->total > 0) {  // check for null
58,047!
1982
    if (pCtx->numOfParams > 2) {
56,639✔
1983
      char buf[3200] = {0};
22✔
1984
      // max length of double num is 317, e.g. use %.6lf to print -1.0e+308, consider the comma and bracket, 3200 is
1985
      // enough.
1986
      size_t len = 1;
22✔
1987

1988
      varDataVal(buf)[0] = '[';
22✔
1989
      for (int32_t i = 1; i < pCtx->numOfParams; ++i) {
210✔
1990
        SVariant* pVal = &pCtx->param[i].param;
188✔
1991

1992
        GET_TYPED_DATA(v, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[i].pCol));
188!
1993

1994
        code = getPercentile((*pMemBucket), v, &ppInfo->result);
188✔
1995
        if (code != TSDB_CODE_SUCCESS) {
188!
UNCOV
1996
          goto _fin_error;
×
1997
        }
1998

1999
        if (i == pCtx->numOfParams - 1) {
188✔
2000
          len += tsnprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf]", ppInfo->result);
22✔
2001
        } else {
2002
          len += tsnprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf, ", ppInfo->result);
166✔
2003
        }
2004
      }
2005

2006
      int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
22✔
2007
      SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
22✔
2008
      if (NULL == pCol) {
22!
UNCOV
2009
        code = terrno;
×
UNCOV
2010
        goto _fin_error;
×
2011
      }
2012

2013
      varDataSetLen(buf, len);
22✔
2014
      code = colDataSetVal(pCol, pBlock->info.rows, buf, false);
22✔
2015
      if (code != TSDB_CODE_SUCCESS) {
22!
UNCOV
2016
        goto _fin_error;
×
2017
      }
2018

2019
      tMemBucketDestroy(pMemBucket);
22✔
2020
      return TSDB_CODE_SUCCESS;
22✔
2021
    } else {
2022
      SVariant* pVal = &pCtx->param[1].param;
56,617✔
2023

2024
      GET_TYPED_DATA(v, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[1].pCol));
56,617!
2025

2026
      code = getPercentile((*pMemBucket), v, &ppInfo->result);
56,617✔
2027
      if (code != TSDB_CODE_SUCCESS) {
56,617!
UNCOV
2028
        goto _fin_error;
×
2029
      }
2030

2031
      tMemBucketDestroy(pMemBucket);
56,617✔
2032
      return functionFinalize(pCtx, pBlock);
56,617✔
2033
    }
2034
  } else {
2035
    return functionFinalize(pCtx, pBlock);
1,408✔
2036
  }
2037

UNCOV
2038
_fin_error:
×
2039

UNCOV
2040
  tMemBucketDestroy(pMemBucket);
×
UNCOV
2041
  return code;
×
2042
}
2043

2044
bool getApercentileFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
75,107✔
2045
  int32_t bytesHist =
75,107✔
2046
      (int32_t)(sizeof(SAPercentileInfo) + sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
2047
  int32_t bytesDigest = (int32_t)(sizeof(SAPercentileInfo) + TDIGEST_SIZE(COMPRESSION));
75,107✔
2048
  pEnv->calcMemSize = TMAX(bytesHist, bytesDigest);
75,107✔
2049
  return true;
75,107✔
2050
}
2051

2052
int32_t getApercentileMaxSize() {
10,098✔
2053
  int32_t bytesHist =
10,098✔
2054
      (int32_t)(sizeof(SAPercentileInfo) + sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
2055
  int32_t bytesDigest = (int32_t)(sizeof(SAPercentileInfo) + TDIGEST_SIZE(COMPRESSION));
10,098✔
2056
  return TMAX(bytesHist, bytesDigest);
10,098✔
2057
}
2058

2059
static int8_t getApercentileAlgo(char* algoStr) {
25,512✔
2060
  int8_t algoType;
2061
  if (strcasecmp(algoStr, "default") == 0) {
25,512✔
2062
    algoType = APERCT_ALGO_DEFAULT;
11,149✔
2063
  } else if (strcasecmp(algoStr, "t-digest") == 0) {
14,363✔
2064
    algoType = APERCT_ALGO_TDIGEST;
14,357✔
2065
  } else {
2066
    algoType = APERCT_ALGO_UNKNOWN;
6✔
2067
  }
2068

2069
  return algoType;
25,512✔
2070
}
2071

2072
static void buildHistogramInfo(SAPercentileInfo* pInfo) {
934,595✔
2073
  pInfo->pHisto = (SHistogramInfo*)((char*)pInfo + sizeof(SAPercentileInfo));
934,595✔
2074
  pInfo->pHisto->elems = (SHistBin*)((char*)pInfo->pHisto + sizeof(SHistogramInfo));
934,595✔
2075
}
934,595✔
2076

2077
static void buildTDigestInfo(SAPercentileInfo* pInfo) {
29,551✔
2078
  pInfo->pTDigest = (TDigest*)((char*)pInfo + sizeof(SAPercentileInfo));
29,551✔
2079
}
29,551✔
2080

2081
int32_t apercentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
327,153✔
2082
  if (pResultInfo->initialized) {
327,153!
UNCOV
2083
    return TSDB_CODE_SUCCESS;
×
2084
  }
2085
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
327,153!
UNCOV
2086
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
2087
  }
2088

2089
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
327,168✔
2090

2091
  SVariant* pVal = &pCtx->param[1].param;
327,168✔
2092
  pInfo->percent = 0;
327,168✔
2093
  GET_TYPED_DATA(pInfo->percent, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[1].pCol));
327,168!
2094

2095
  if (pCtx->numOfParams == 2) {
327,180✔
2096
    pInfo->algo = APERCT_ALGO_DEFAULT;
301,668✔
2097
  } else if (pCtx->numOfParams == 3) {
25,512!
2098
    pInfo->algo = getApercentileAlgo(varDataVal(pCtx->param[2].param.pz));
25,512✔
2099
    if (pInfo->algo == APERCT_ALGO_UNKNOWN) {
25,505!
UNCOV
2100
      return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
2101
    }
2102
  }
2103

2104
  char* tmp = (char*)pInfo + sizeof(SAPercentileInfo);
327,173✔
2105
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
327,173✔
2106
    pInfo->pTDigest = tdigestNewFrom(tmp, COMPRESSION);
14,359✔
2107
  } else {
2108
    buildHistogramInfo(pInfo);
312,814✔
2109
    pInfo->pHisto = tHistogramCreateFrom(tmp, MAX_HISTOGRAM_BIN);
312,826✔
2110
    qDebug("%s set up histogram, numOfElems:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
312,836✔
2111
           pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2112
  }
2113

2114
  return TSDB_CODE_SUCCESS;
327,198✔
2115
}
2116

2117
int32_t apercentileFunction(SqlFunctionCtx* pCtx) {
333,136✔
2118
  int32_t               numOfElems = 0;
333,136✔
2119
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
333,136✔
2120
  SInputColumnInfoData* pInput = &pCtx->input;
333,136✔
2121

2122
  SColumnInfoData* pCol = pInput->pData[0];
333,136✔
2123
  int32_t          type = pCol->info.type;
333,136✔
2124

2125
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
333,136✔
2126

2127
  int32_t start = pInput->startRowIndex;
333,136✔
2128
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
333,136✔
2129
    buildTDigestInfo(pInfo);
14,348✔
2130
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
14,346✔
2131
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
2,151,974✔
2132
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
2,137,618✔
2133
        continue;
283,937✔
2134
      }
2135
      numOfElems += 1;
1,853,681✔
2136
      char* data = colDataGetData(pCol, i);
1,853,681!
2137

2138
      double  v = 0;  // value
1,853,681✔
2139
      int64_t w = 1;  // weigth
1,853,681✔
2140
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
1,853,681!
2141
      int32_t code = tdigestAdd(pInfo->pTDigest, v, w);
1,853,681✔
2142
      if (code != TSDB_CODE_SUCCESS) {
1,853,692!
UNCOV
2143
        return code;
×
2144
      }
2145
    }
2146
  } else {
2147
    // might be a race condition here that pHisto can be overwritten or setup function
2148
    // has not been called, need to relink the buffer pHisto points to.
2149
    buildHistogramInfo(pInfo);
318,788✔
2150
    qDebug("%s before add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
318,758✔
2151
           __FUNCTION__, numOfElems, pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto,
2152
           pInfo->pHisto->elems);
2153
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
3,629,812✔
2154
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
3,311,086✔
2155
        continue;
834,982✔
2156
      }
2157
      numOfElems += 1;
2,476,104✔
2158
      char* data = colDataGetData(pCol, i);
2,476,104!
2159

2160
      double v = 0;
2,476,104✔
2161
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
2,476,104!
2162
      int32_t code = tHistogramAdd(&pInfo->pHisto, v);
2,476,104✔
2163
      if (code != TSDB_CODE_SUCCESS) {
2,476,068!
UNCOV
2164
        return code;
×
2165
      }
2166
    }
2167

2168
    qDebug("%s after add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
318,726✔
2169
           __FUNCTION__, numOfElems, pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto,
2170
           pInfo->pHisto->elems);
2171
  }
2172

2173
  SET_VAL(pResInfo, numOfElems, 1);
333,133✔
2174
  return TSDB_CODE_SUCCESS;
333,133✔
2175
}
2176

2177
static int32_t apercentileTransferInfo(SAPercentileInfo* pInput, SAPercentileInfo* pOutput, bool* hasRes) {
8,708✔
2178
  pOutput->percent = pInput->percent;
8,708✔
2179
  pOutput->algo = pInput->algo;
8,708✔
2180
  if (pOutput->algo == APERCT_ALGO_TDIGEST) {
8,708✔
2181
    buildTDigestInfo(pInput);
848✔
2182
    tdigestAutoFill(pInput->pTDigest, COMPRESSION);
848✔
2183

2184
    if (pInput->pTDigest->num_centroids == 0 && pInput->pTDigest->num_buffered_pts == 0) {
848✔
2185
      return TSDB_CODE_SUCCESS;
1✔
2186
    }
2187

2188
    if (hasRes) {
847✔
2189
      *hasRes = true;
845✔
2190
    }
2191

2192
    buildTDigestInfo(pOutput);
847✔
2193
    TDigest* pTDigest = pOutput->pTDigest;
847✔
2194
    tdigestAutoFill(pTDigest, COMPRESSION);
847✔
2195

2196
    if (pTDigest->num_centroids <= 0 && pTDigest->num_buffered_pts == 0) {
847!
2197
      (void)memcpy(pTDigest, pInput->pTDigest, (size_t)TDIGEST_SIZE(COMPRESSION));
845✔
2198
      tdigestAutoFill(pTDigest, COMPRESSION);
845✔
2199
    } else {
2200
      int32_t code = tdigestMerge(pTDigest, pInput->pTDigest);
2✔
2201
      if (TSDB_CODE_SUCCESS != code) {
2!
UNCOV
2202
        return code;
×
2203
      }
2204
    }
2205
  } else {
2206
    buildHistogramInfo(pInput);
7,860✔
2207
    if (pInput->pHisto->numOfElems <= 0) {
7,860✔
2208
      return TSDB_CODE_SUCCESS;
190✔
2209
    }
2210

2211
    if (hasRes) {
7,670✔
2212
      *hasRes = true;
7,668✔
2213
    }
2214

2215
    buildHistogramInfo(pOutput);
7,670✔
2216
    SHistogramInfo* pHisto = pOutput->pHisto;
7,670✔
2217

2218
    if (pHisto->numOfElems <= 0) {
7,670✔
2219
      (void)memcpy(pHisto, pInput->pHisto, sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
7,316✔
2220
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
7,316✔
2221

2222
      qDebug("%s merge histo, total:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems, pHisto->numOfEntries,
7,316✔
2223
             pHisto);
2224
    } else {
2225
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
354✔
2226
      qDebug("%s input histogram, elem:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems,
354✔
2227
             pHisto->numOfEntries, pInput->pHisto);
2228

2229
      SHistogramInfo* pRes = NULL;
354✔
2230
      int32_t         code = tHistogramMerge(pHisto, pInput->pHisto, MAX_HISTOGRAM_BIN, &pRes);
354✔
2231
      if (TSDB_CODE_SUCCESS != code) {
354!
UNCOV
2232
        tHistogramDestroy(&pRes);
×
UNCOV
2233
        return code;
×
2234
      }
2235
      (void)memcpy(pHisto, pRes, sizeof(SHistogramInfo) + sizeof(SHistBin) * MAX_HISTOGRAM_BIN);
354✔
2236
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
354✔
2237

2238
      qDebug("%s merge histo, total:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems, pHisto->numOfEntries,
354✔
2239
             pHisto);
2240
      tHistogramDestroy(&pRes);
354✔
2241
    }
2242
  }
2243
  return TSDB_CODE_SUCCESS;
8,517✔
2244
}
2245

2246
int32_t apercentileFunctionMerge(SqlFunctionCtx* pCtx) {
8,610✔
2247
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
8,610✔
2248

2249
  SInputColumnInfoData* pInput = &pCtx->input;
8,610✔
2250

2251
  SColumnInfoData* pCol = pInput->pData[0];
8,610✔
2252
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
8,610!
UNCOV
2253
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
2254
  }
2255

2256
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
8,610✔
2257

2258
  qDebug("%s total %" PRId64 " rows will merge, %p", __FUNCTION__, pInput->numOfRows, pInfo->pHisto);
8,610✔
2259

2260
  bool    hasRes = false;
8,610✔
2261
  int32_t start = pInput->startRowIndex;
8,610✔
2262
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
17,314✔
2263
    char* data = colDataGetData(pCol, i);
8,704!
2264

2265
    SAPercentileInfo* pInputInfo = (SAPercentileInfo*)varDataVal(data);
8,704✔
2266
    int32_t           code = apercentileTransferInfo(pInputInfo, pInfo, &hasRes);
8,704✔
2267
    if (TSDB_CODE_SUCCESS != code) {
8,704!
UNCOV
2268
      return code;
×
2269
    }
2270
  }
2271

2272
  if (pInfo->algo != APERCT_ALGO_TDIGEST) {
8,610✔
2273
    buildHistogramInfo(pInfo);
7,764✔
2274
    qDebug("%s after merge, total:%" PRId64 ", numOfEntry:%d, %p", __FUNCTION__, pInfo->pHisto->numOfElems,
7,764✔
2275
           pInfo->pHisto->numOfEntries, pInfo->pHisto);
2276
  }
2277

2278
  SET_VAL(pResInfo, hasRes ? 1 : 0, 1);
8,610✔
2279
  return TSDB_CODE_SUCCESS;
8,610✔
2280
}
2281

2282
int32_t apercentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
293,259✔
2283
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
293,259✔
2284
  SAPercentileInfo*    pInfo = (SAPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
293,259✔
2285

2286
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
293,259✔
2287
    buildTDigestInfo(pInfo);
13,513✔
2288
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
13,513✔
2289
    if (pInfo->pTDigest->size > 0) {
13,514!
2290
      pInfo->result = tdigestQuantile(pInfo->pTDigest, pInfo->percent / 100);
13,514✔
2291
    } else {  // no need to free
2292
      // setNull(pCtx->pOutput, pCtx->outputType, pCtx->outputBytes);
UNCOV
2293
      return TSDB_CODE_SUCCESS;
×
2294
    }
2295
  } else {
2296
    buildHistogramInfo(pInfo);
279,746✔
2297
    if (pInfo->pHisto->numOfElems > 0) {
279,739✔
2298
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
230,560✔
2299
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2300

2301
      double  ratio[] = {pInfo->percent};
230,560✔
2302
      double* res = NULL;
230,560✔
2303
      int32_t code = tHistogramUniform(pInfo->pHisto, ratio, 1, &res);
230,560✔
2304
      if (TSDB_CODE_SUCCESS != code) {
230,555!
UNCOV
2305
        taosMemoryFree(res);
×
UNCOV
2306
        return code;
×
2307
      }
2308
      pInfo->result = *res;
230,555✔
2309
      // memcpy(pCtx->pOutput, res, sizeof(double));
2310
      taosMemoryFree(res);
230,555✔
2311
    } else {  // no need to free
2312
      // setNull(pCtx->pOutput, pCtx->outputType, pCtx->outputBytes);
2313
      // return TSDB_CODE_SUCCESS;
2314
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d. result is null", __FUNCTION__,
49,179✔
2315
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries);
2316
    }
2317
  }
2318

2319
  return functionFinalize(pCtx, pBlock);
293,250✔
2320
}
2321

2322
int32_t apercentilePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
8,372✔
2323
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
8,372✔
2324
  SAPercentileInfo*    pInfo = (SAPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
8,372✔
2325

2326
  int32_t resultBytes = getApercentileMaxSize();
8,372✔
2327
  char*   res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
8,372!
2328
  if (NULL == res) {
8,372!
UNCOV
2329
    return terrno;
×
2330
  }
2331

2332
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
8,372✔
2333
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
846✔
2334
    varDataSetLen(res, resultBytes);
846✔
2335
  } else {
2336
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
7,526✔
2337
    varDataSetLen(res, resultBytes);
7,526✔
2338
  }
2339

2340
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
8,372✔
2341
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
8,372✔
2342
  if (NULL == pCol) {
8,371!
UNCOV
2343
    taosMemoryFree(res);
×
UNCOV
2344
    return TSDB_CODE_OUT_OF_RANGE;
×
2345
  }
2346

2347
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
8,371✔
2348

2349
  taosMemoryFree(res);
8,372!
2350
  return code;
8,372✔
2351
}
2352

2353
int32_t apercentileCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
4✔
2354
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
4✔
2355
  SAPercentileInfo*    pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
4✔
2356

2357
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
4✔
2358
  SAPercentileInfo*    pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
4✔
2359

2360
  qDebug("%s start to combine apercentile, %p", __FUNCTION__, pDBuf->pHisto);
4!
2361

2362
  int32_t code = apercentileTransferInfo(pSBuf, pDBuf, NULL);
4✔
2363
  if (TSDB_CODE_SUCCESS != code) {
4!
UNCOV
2364
    return code;
×
2365
  }
2366
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
4✔
2367
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
4✔
2368
  return TSDB_CODE_SUCCESS;
4✔
2369
}
2370

2371
// TODO: change this function when block data info pks changed
2372
static int32_t comparePkDataWithSValue(int8_t pkType, char* pkData, SValue* pVal, int32_t order) {
11✔
2373
  char numVal[8] = {0};
11✔
2374
  switch (pkType) {
11!
2375
    case TSDB_DATA_TYPE_INT:
11✔
2376
      *(int32_t*)numVal = (int32_t)VALUE_GET_TRIVIAL_DATUM(pVal);
11✔
2377
      break;
11✔
UNCOV
2378
    case TSDB_DATA_TYPE_UINT:
×
UNCOV
2379
      *(uint32_t*)numVal = (uint32_t)VALUE_GET_TRIVIAL_DATUM(pVal);
×
UNCOV
2380
      break;
×
UNCOV
2381
    case TSDB_DATA_TYPE_BIGINT:
×
2382
      *(int64_t*)numVal = (int64_t)VALUE_GET_TRIVIAL_DATUM(pVal);
×
UNCOV
2383
      break;
×
UNCOV
2384
    case TSDB_DATA_TYPE_UBIGINT:
×
UNCOV
2385
      *(uint64_t*)numVal = (uint64_t)VALUE_GET_TRIVIAL_DATUM(pVal);
×
UNCOV
2386
      break;
×
UNCOV
2387
    default:
×
UNCOV
2388
      break;
×
2389
  }
2390
  char*         blockData = (IS_NUMERIC_TYPE(pkType)) ? (char*)numVal : (char*)pVal->pData;
11!
2391
  __compar_fn_t fn = getKeyComparFunc(pkType, order);
11✔
2392
  return fn(pkData, blockData);
11✔
2393
}
2394

2395
EFuncDataRequired firstDynDataReq(void* pRes, SDataBlockInfo* pBlockInfo) {
4,164✔
2396
  SResultRowEntryInfo* pEntry = (SResultRowEntryInfo*)pRes;
4,164✔
2397

2398
  // not initialized yet, data is required
2399
  if (pEntry == NULL) {
4,164!
UNCOV
2400
    return FUNC_DATA_REQUIRED_DATA_LOAD;
×
2401
  }
2402

2403
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
4,164✔
2404
  if (pResult->hasResult) {
4,164✔
2405
    if (pResult->pkBytes > 0) {
4,091✔
2406
      pResult->pkData = pResult->buf + pResult->bytes;
6✔
2407
    } else {
2408
      pResult->pkData = NULL;
4,085✔
2409
    }
2410
    if (pResult->ts < pBlockInfo->window.skey) {
4,091✔
2411
      return FUNC_DATA_REQUIRED_NOT_LOAD;
2,847✔
2412
    } else if (pResult->ts == pBlockInfo->window.skey) {
1,244✔
2413
      if (NULL == pResult->pkData) {
245✔
2414
        return FUNC_DATA_REQUIRED_NOT_LOAD;
239✔
2415
      }
2416
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 0, TSDB_ORDER_ASC) < 0) {
6!
2417
        return FUNC_DATA_REQUIRED_NOT_LOAD;
6✔
2418
      }
2419
    }
2420
    return FUNC_DATA_REQUIRED_DATA_LOAD;
999✔
2421
  } else {
2422
    return FUNC_DATA_REQUIRED_DATA_LOAD;
73✔
2423
  }
2424
}
2425

2426
EFuncDataRequired lastDynDataReq(void* pRes, SDataBlockInfo* pBlockInfo) {
9,507✔
2427
  SResultRowEntryInfo* pEntry = (SResultRowEntryInfo*)pRes;
9,507✔
2428

2429
  // not initialized yet, data is required
2430
  if (pEntry == NULL) {
9,507!
UNCOV
2431
    return FUNC_DATA_REQUIRED_DATA_LOAD;
×
2432
  }
2433

2434
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
9,507✔
2435
  if (pResult->hasResult) {
9,507✔
2436
    if (pResult->pkBytes > 0) {
9,432✔
2437
      pResult->pkData = pResult->buf + pResult->bytes;
5✔
2438
    } else {
2439
      pResult->pkData = NULL;
9,427✔
2440
    }
2441
    if (pResult->ts > pBlockInfo->window.ekey) {
9,432✔
2442
      return FUNC_DATA_REQUIRED_NOT_LOAD;
7,174✔
2443
    } else if (pResult->ts == pBlockInfo->window.ekey && pResult->pkData) {
2,258✔
2444
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 1, TSDB_ORDER_DESC) < 0) {
5!
UNCOV
2445
        return FUNC_DATA_REQUIRED_NOT_LOAD;
×
2446
      }
2447
    }
2448
    return FUNC_DATA_REQUIRED_DATA_LOAD;
2,258✔
2449
  } else {
2450
    return FUNC_DATA_REQUIRED_DATA_LOAD;
75✔
2451
  }
2452
}
2453

2454
// TODO modify it to include primary key bytes
2455
int32_t getFirstLastInfoSize(int32_t resBytes, int32_t pkBytes) { return sizeof(SFirstLastRes) + resBytes + pkBytes; }
70,334,203✔
2456

2457
bool getFirstLastFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
1,812,694✔
2458
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
1,812,694✔
2459
  // TODO: change SFunctionNode to add pk info
2460
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
1,813,750✔
2461
  pEnv->calcMemSize = getFirstLastInfoSize(pNode->node.resType.bytes, pkBytes);
1,813,750✔
2462
  return true;
1,813,678✔
2463
}
2464

2465
bool getSelectivityFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
1,190,774✔
2466
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
1,190,774✔
2467
  pEnv->calcMemSize = pNode->node.resType.bytes;
1,191,351✔
2468
  return true;
1,191,351✔
2469
}
2470

2471
bool getGroupKeyFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
250,587✔
2472
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
250,587✔
2473
  pEnv->calcMemSize = sizeof(SGroupKeyInfo) + pNode->node.resType.bytes;
250,896✔
2474
  return true;
250,896✔
2475
}
2476

2477
static FORCE_INLINE TSKEY getRowPTs(SColumnInfoData* pTsColInfo, int32_t rowIndex) {
2478
  if (pTsColInfo == NULL || pTsColInfo->pData == NULL) {
360,903,779!
UNCOV
2479
    return 0;
×
2480
  }
2481

2482
  return *(TSKEY*)colDataGetData(pTsColInfo, rowIndex);
360,980,080!
2483
}
2484

2485
int32_t firstLastFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
24,732,053✔
2486
  if (pResInfo->initialized) {
24,732,053!
2487
    return TSDB_CODE_SUCCESS;
×
2488
  }
2489
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
24,732,053!
UNCOV
2490
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
2491
  }
2492

2493
  SFirstLastRes*        pRes = GET_ROWCELL_INTERBUF(pResInfo);
24,732,565✔
2494
  pRes->nullTupleSaved = false;
24,732,565✔
2495
  pRes->nullTuplePos.pageId = -1;
24,732,565✔
2496
  return TSDB_CODE_SUCCESS;
24,732,565✔
2497
}
2498

2499
static int32_t prepareBuf(SqlFunctionCtx* pCtx) {
186,839,914✔
2500
  if (pCtx->subsidiaries.rowLen == 0) {
186,839,914✔
2501
    int32_t rowLen = 0;
655,811✔
2502
    for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
1,317,772✔
2503
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
661,961✔
2504
      rowLen += pc->pExpr->base.resSchema.bytes;
661,961✔
2505
    }
2506

2507
    pCtx->subsidiaries.rowLen = rowLen + pCtx->subsidiaries.num * sizeof(bool);
655,811✔
2508
    pCtx->subsidiaries.buf = taosMemoryMalloc(pCtx->subsidiaries.rowLen);
655,811!
2509
    if (NULL == pCtx->subsidiaries.buf) {
662,961!
UNCOV
2510
      return terrno;
×
2511
    }
2512
  }
2513
  return TSDB_CODE_SUCCESS;
186,847,064✔
2514
}
2515

2516
static int32_t firstlastSaveTupleData(const SSDataBlock* pSrcBlock, int32_t rowIndex, SqlFunctionCtx* pCtx,
226,633,438✔
2517
                                      SFirstLastRes* pInfo, bool noElements) {
2518
  int32_t code = TSDB_CODE_SUCCESS;
226,633,438✔
2519

2520
  if (pCtx->subsidiaries.num <= 0) {
226,633,438✔
2521
    return TSDB_CODE_SUCCESS;
110,903,334✔
2522
  }
2523

2524
  if (!pInfo->hasResult) {
115,730,104✔
2525
    code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
87,320,556✔
2526
  } else if (!noElements) {
28,409,548!
2527
    code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
28,482,709✔
2528
  } else { } // dothing
2529

2530
  return code;
115,690,184✔
2531
}
2532

2533
static int32_t doSaveCurrentVal(SqlFunctionCtx* pCtx, int32_t rowIndex, int64_t currentTs, char* pkData, int32_t type,
113,303,000✔
2534
                                char* pData) {
2535
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
113,303,000✔
2536
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
113,303,000✔
2537

2538
  if (IS_VAR_DATA_TYPE(type)) {
113,303,000!
2539
    if (type == TSDB_DATA_TYPE_JSON) {
6,546,489!
2540
      pInfo->bytes = getJsonValueLen(pData);
×
2541
    } else {
2542
      pInfo->bytes = varDataTLen(pData);
6,546,489✔
2543
    }
2544
  }
2545

2546
  (void)memcpy(pInfo->buf, pData, pInfo->bytes);
113,303,000✔
2547
  if (pkData != NULL) {
113,303,000✔
2548
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
30,118!
2549
      if (pInfo->pkType == TSDB_DATA_TYPE_JSON) {
24!
UNCOV
2550
        pInfo->pkBytes = getJsonValueLen(pkData);
×
2551
      } else {
2552
        pInfo->pkBytes = varDataTLen(pkData);
24✔
2553
      }
2554
    }
2555
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
30,118✔
2556
    pInfo->pkData = pInfo->buf + pInfo->bytes;
30,118✔
2557
  }
2558

2559
  pInfo->ts = currentTs;
113,303,000✔
2560
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
113,303,000✔
2561
  if (code != TSDB_CODE_SUCCESS) {
113,265,974!
UNCOV
2562
    return code;
×
2563
  }
2564

2565
  pInfo->hasResult = true;
113,265,974✔
2566
  return TSDB_CODE_SUCCESS;
113,265,974✔
2567
}
2568

2569
// This ordinary first function does not care if current scan is ascending order or descending order scan
2570
// the OPTIMIZED version of first function will only handle the ascending order scan
2571
int32_t firstFunction(SqlFunctionCtx* pCtx) {
46,024,549✔
2572
  int32_t numOfElems = 0;
46,024,549✔
2573

2574
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
46,024,549✔
2575
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
46,024,549✔
2576

2577
  SInputColumnInfoData* pInput = &pCtx->input;
46,024,549✔
2578
  SColumnInfoData*      pInputCol = pInput->pData[0];
46,024,549✔
2579

2580
  pInfo->bytes = pInputCol->info.bytes;
46,024,549✔
2581

2582
  if (IS_NULL_TYPE(pInputCol->info.type)) {
46,024,549✔
2583
    return TSDB_CODE_SUCCESS;
5,006✔
2584
  }
2585

2586
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
46,019,543✔
2587
  pInfo->pkType = -1;
46,019,543✔
2588
  __compar_fn_t pkCompareFn = NULL;
46,019,543✔
2589
  if (pCtx->hasPrimaryKey) {
46,019,543✔
2590
    pInfo->pkType = pkCol->info.type;
51✔
2591
    pInfo->pkBytes = pkCol->info.bytes;
51✔
2592
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_ASC);
51✔
2593
  }
2594

2595
  // All null data column, return directly.
2596
  if (pInput->colDataSMAIsSet && (pInput->pColumnDataAgg[0]->numOfNull == pInput->totalRows) &&
46,051,358!
UNCOV
2597
      pInputCol->hasNull == true) {
×
2598
    // save selectivity value for column consisted of all null values
UNCOV
2599
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
×
UNCOV
2600
    if (code != TSDB_CODE_SUCCESS) {
×
UNCOV
2601
      return code;
×
2602
    }
UNCOV
2603
    pInfo->nullTupleSaved = true;
×
UNCOV
2604
    return TSDB_CODE_SUCCESS;
×
2605
  }
2606

2607
  SColumnDataAgg* pColAgg = (pInput->colDataSMAIsSet) ? pInput->pColumnDataAgg[0] : NULL;
46,051,358!
2608

2609
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
46,051,358!
2610
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
46,051,358!
2611

2612
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
46,051,358✔
2613

2614
  //  please ref. to the comment in lastRowFunction for the reason why disabling the opt version of last/first
2615
  //  function. we will use this opt implementation in an new version that is only available in scan subplan
2616
#if 0
2617
  if (blockDataOrder == TSDB_ORDER_ASC) {
2618
    // filter according to current result firstly
2619
    if (pResInfo->numOfRes > 0) {
2620
      if (pInfo->ts < startKey) {
2621
        return TSDB_CODE_SUCCESS;
2622
      }
2623
    }
2624

2625
    for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
2626
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2627
        continue;
2628
      }
2629

2630
      numOfElems++;
2631

2632
      char* data = colDataGetData(pInputCol, i);
2633
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2634
      if (pResInfo->numOfRes == 0 || pInfo->ts > cts) {
2635
        doSaveCurrentVal(pCtx, i, cts, pInputCol->info.type, data);
2636
        break;
2637
      }
2638
    }
2639
  } else {
2640
    // in case of descending order time stamp serial, which usually happens as the results of the nest query,
2641
    // all data needs to be check.
2642
    if (pResInfo->numOfRes > 0) {
2643
      if (pInfo->ts < endKey) {
2644
        return TSDB_CODE_SUCCESS;
2645
      }
2646
    }
2647

2648
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
2649
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2650
        continue;
2651
      }
2652

2653
      numOfElems++;
2654

2655
      char* data = colDataGetData(pInputCol, i);
2656
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2657

2658
      if (pResInfo->numOfRes == 0 || pInfo->ts > cts) {
2659
        doSaveCurrentVal(pCtx, i, cts, pInputCol->info.type, data);
2660
        break;
2661
      }
2662
    }
2663
  }
2664
#else
2665
  int64_t* pts = (int64_t*)pInput->pPTS->pData;
46,051,358✔
2666

2667
  int     from = -1;
46,051,358✔
2668
  int32_t i = -1;
46,051,358✔
2669
  while (funcInputGetNextRowIndex(pInput, from, true, &i, &from)) {
138,446,497✔
2670
    if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
121,773,519!
2671
      continue;
71,902✔
2672
    }
2673

2674
    numOfElems++;
92,351,498✔
2675
    char* data = colDataGetData(pInputCol, i);
92,351,498!
2676
    char* pkData = NULL;
92,351,498✔
2677
    if (pCtx->hasPrimaryKey) {
92,351,498✔
2678
      pkData = colDataGetData(pkCol, i);
153!
2679
    }
2680
    TSKEY cts = pts[i];
92,351,498✔
2681
    if (pResInfo->numOfRes == 0 || pInfo->ts > cts ||
92,351,498✔
2682
        (pInfo->ts == cts && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
53,883,946!
2683
      int32_t code = doSaveCurrentVal(pCtx, i, cts, pkData, pInputCol->info.type, data);
38,467,552✔
2684
      if (code != TSDB_CODE_SUCCESS) {
38,439,291!
UNCOV
2685
        return code;
×
2686
      }
2687
      pResInfo->numOfRes = 1;
38,439,291✔
2688
    }
2689
  }
2690
#endif
2691

2692
  if (numOfElems == 0) {
45,599,061✔
2693
    // save selectivity value for column consisted of all null values
2694
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
24,196✔
2695
    if (code != TSDB_CODE_SUCCESS) {
24,196!
UNCOV
2696
      return code;
×
2697
    }
2698
    pInfo->nullTupleSaved = true;
24,196✔
2699
  }
2700
  SET_VAL(pResInfo, numOfElems, 1);
45,599,061✔
2701
  return TSDB_CODE_SUCCESS;
45,599,061✔
2702
}
2703

2704
int32_t lastFunction(SqlFunctionCtx* pCtx) {
55,846,515✔
2705
  int32_t numOfElems = 0;
55,846,515✔
2706

2707
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
55,846,515✔
2708
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
55,846,515✔
2709

2710
  SInputColumnInfoData* pInput = &pCtx->input;
55,846,515✔
2711
  SColumnInfoData*      pInputCol = pInput->pData[0];
55,846,515✔
2712

2713
  int32_t type = pInputCol->info.type;
55,846,515✔
2714
  int32_t bytes = pInputCol->info.bytes;
55,846,515✔
2715

2716
  if (IS_NULL_TYPE(type)) {
55,846,515✔
2717
    return TSDB_CODE_SUCCESS;
5,011✔
2718
  }
2719
  pInfo->bytes = bytes;
55,841,504✔
2720

2721
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
55,841,504✔
2722
  pInfo->pkType = -1;
55,841,504✔
2723
  __compar_fn_t pkCompareFn = NULL;
55,841,504✔
2724
  if (pCtx->hasPrimaryKey) {
55,841,504✔
2725
    pInfo->pkType = pkCol->info.type;
30,067✔
2726
    pInfo->pkBytes = pkCol->info.bytes;
30,067✔
2727
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
30,067✔
2728
  }
2729

2730
  // All null data column, return directly.
2731
  if (pInput->colDataSMAIsSet && (pInput->pColumnDataAgg[0]->numOfNull == pInput->totalRows) &&
55,924,657!
UNCOV
2732
      pInputCol->hasNull == true) {
×
2733
    // save selectivity value for column consisted of all null values
UNCOV
2734
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
×
UNCOV
2735
    if (code != TSDB_CODE_SUCCESS) {
×
UNCOV
2736
      return code;
×
2737
    }
UNCOV
2738
    pInfo->nullTupleSaved = true;
×
UNCOV
2739
    return TSDB_CODE_SUCCESS;
×
2740
  }
2741

2742
  SColumnDataAgg* pColAgg = (pInput->colDataSMAIsSet) ? pInput->pColumnDataAgg[0] : NULL;
55,924,657!
2743

2744
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
55,924,657!
2745
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
55,924,657!
2746

2747
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
55,924,657✔
2748

2749
  //  please ref. to the comment in lastRowFunction for the reason why disabling the opt version of last/first function.
2750
#if 0
2751
  if (blockDataOrder == TSDB_ORDER_ASC) {
2752
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
2753
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2754
        continue;
2755
      }
2756

2757
      numOfElems++;
2758

2759
      char* data = colDataGetData(pInputCol, i);
2760
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2761
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2762
        doSaveCurrentVal(pCtx, i, cts, type, data);
2763
      }
2764

2765
      break;
2766
    }
2767
  } else {  // descending order
2768
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
2769
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2770
        continue;
2771
      }
2772

2773
      numOfElems++;
2774

2775
      char* data = colDataGetData(pInputCol, i);
2776
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2777
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2778
        doSaveCurrentVal(pCtx, i, cts, type, data);
2779
      }
2780
      break;
2781
    }
2782
  }
2783
#else
2784
  int64_t* pts = (int64_t*)pInput->pPTS->pData;
55,924,657✔
2785

2786
#if 0
2787
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
2788
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2789
        continue;
2790
      }
2791

2792
      numOfElems++;
2793
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i]) {
2794
        char* data = colDataGetData(pInputCol, i);
2795
        doSaveCurrentVal(pCtx, i, pts[i], type, data);
2796
        pResInfo->numOfRes = 1;
2797
      }
2798
    }
2799
#else
2800

2801
  // todo refactor
2802
  if (!pInputCol->hasNull && !pCtx->hasPrimaryKey) {
91,788,681✔
2803
    numOfElems = 1;
35,931,542✔
2804

2805
    int32_t round = pInput->numOfRows >> 2;
35,931,542✔
2806
    int32_t reminder = pInput->numOfRows & 0x03;
35,931,542✔
2807

2808
    for (int32_t i = pInput->startRowIndex, tick = 0; tick < round; i += 4, tick += 1) {
60,793,571✔
2809
      int64_t cts = pts[i];
24,861,652✔
2810
      int32_t chosen = i;
24,861,652✔
2811

2812
      if (cts < pts[i + 1]) {
24,861,652✔
2813
        cts = pts[i + 1];
4,887,071✔
2814
        chosen = i + 1;
4,887,071✔
2815
      }
2816

2817
      if (cts < pts[i + 2]) {
24,861,652✔
2818
        cts = pts[i + 2];
4,885,886✔
2819
        chosen = i + 2;
4,885,886✔
2820
      }
2821

2822
      if (cts < pts[i + 3]) {
24,861,652✔
2823
        cts = pts[i + 3];
4,886,189✔
2824
        chosen = i + 3;
4,886,189✔
2825
      }
2826

2827
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
24,861,652✔
2828
        char*   data = colDataGetData(pInputCol, chosen);
4,987,537!
2829
        int32_t code = doSaveCurrentVal(pCtx, chosen, cts, NULL, type, data);
4,987,537✔
2830
        if (code != TSDB_CODE_SUCCESS) {
4,987,914!
UNCOV
2831
          return code;
×
2832
        }
2833
        pResInfo->numOfRes = 1;
4,987,914✔
2834
      }
2835
    }
2836

2837
    for (int32_t i = pInput->startRowIndex + round * 4; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
81,865,280✔
2838
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i]) {
46,001,256✔
2839
        char*   data = colDataGetData(pInputCol, i);
27,519,838!
2840
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], NULL, type, data);
27,519,838✔
2841
        if (code != TSDB_CODE_SUCCESS) {
27,451,943!
UNCOV
2842
          return code;
×
2843
        }
2844
        pResInfo->numOfRes = 1;
27,451,943✔
2845
      }
2846
    }
2847
  } else {
2848
    int     from = -1;
19,993,115✔
2849
    int32_t i = -1;
19,993,115✔
2850
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
181,477,840✔
2851
      if (colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
322,979,556✔
2852
        continue;
5,588,032✔
2853
      }
2854

2855
      numOfElems++;
155,901,746✔
2856
      char* pkData = NULL;
155,901,746✔
2857
      if (pCtx->hasPrimaryKey) {
155,901,746✔
2858
        pkData = colDataGetData(pkCol, i);
100,000,193!
2859
      }
2860
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i] ||
155,901,746✔
2861
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
113,621,378!
2862
        char*   data = colDataGetData(pInputCol, i);
42,333,206!
2863
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], pkData, type, data);
42,333,206✔
2864
        if (code != TSDB_CODE_SUCCESS) {
42,328,153!
2865
          return code;
×
2866
        }
2867
        pResInfo->numOfRes = 1;
42,328,153✔
2868
      }
2869
    }
2870
  }
2871
#endif
2872

2873
#endif
2874

2875
  // save selectivity value for column consisted of all null values
2876
  if (numOfElems == 0) {
56,058,855✔
2877
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
4,097,400✔
2878
    if (code != TSDB_CODE_SUCCESS) {
4,092,249!
UNCOV
2879
      return code;
×
2880
    }
2881
    pInfo->nullTupleSaved = true;
4,092,249✔
2882
  }
2883

2884
  return TSDB_CODE_SUCCESS;
56,053,704✔
2885
}
2886

2887
static bool firstLastTransferInfoImpl(SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst) {
64,286,337✔
2888
  if (!pInput->hasResult) {
64,286,337✔
2889
    return false;
2✔
2890
  }
2891
  __compar_fn_t pkCompareFn = NULL;
64,286,335✔
2892
  if (pInput->pkData) {
64,286,335✔
2893
    pkCompareFn = getKeyComparFunc(pInput->pkType, (isFirst) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC);
52✔
2894
  }
2895
  if (pOutput->hasResult) {
64,289,165✔
2896
    if (isFirst) {
23,599,281✔
2897
      if (pInput->ts > pOutput->ts ||
8,571,628✔
2898
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
8,571,178!
2899
        return false;
450✔
2900
      }
2901
    } else {
2902
      if (pInput->ts < pOutput->ts ||
15,027,653✔
2903
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
8,630,892!
2904
        return false;
6,397,125✔
2905
      }
2906
    }
2907
  }
2908

2909
  pOutput->isNull = pInput->isNull;
57,891,590✔
2910
  pOutput->ts = pInput->ts;
57,891,590✔
2911
  pOutput->bytes = pInput->bytes;
57,891,590✔
2912
  pOutput->pkType = pInput->pkType;
57,891,590✔
2913

2914
  (void)memcpy(pOutput->buf, pInput->buf, pOutput->bytes);
57,891,590✔
2915
  if (pInput->pkData) {
57,891,590✔
2916
    pOutput->pkBytes = pInput->pkBytes;
46✔
2917
    (void)memcpy(pOutput->buf + pOutput->bytes, pInput->pkData, pOutput->pkBytes);
46✔
2918
    pOutput->pkData = pOutput->buf + pOutput->bytes;
46✔
2919
  }
2920
  return true;
57,891,590✔
2921
}
2922

2923
static int32_t firstLastTransferInfo(SqlFunctionCtx* pCtx, SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst,
64,285,825✔
2924
                                     int32_t rowIndex) {
2925
  if (firstLastTransferInfoImpl(pInput, pOutput, isFirst)) {
64,285,825✔
2926
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pOutput, false);
57,889,642✔
2927
    if (TSDB_CODE_SUCCESS != code) {
57,886,504!
UNCOV
2928
      return code;
×
2929
    }
2930
    pOutput->hasResult = true;
57,886,504✔
2931
  }
2932
  return TSDB_CODE_SUCCESS;
64,282,726✔
2933
}
2934

2935
static int32_t firstLastFunctionMergeImpl(SqlFunctionCtx* pCtx, bool isFirstQuery) {
40,706,098✔
2936
  SInputColumnInfoData* pInput = &pCtx->input;
40,706,098✔
2937
  SColumnInfoData*      pCol = pInput->pData[0];
40,706,098✔
2938

2939
  if (IS_NULL_TYPE(pCol->info.type)) {
40,706,098!
UNCOV
2940
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
UNCOV
2941
    return TSDB_CODE_SUCCESS;
×
2942
  }
2943

2944
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
40,706,098!
UNCOV
2945
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
2946
  }
2947

2948
  SFirstLastRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
40,706,098✔
2949

2950
  int32_t start = pInput->startRowIndex;
40,706,098✔
2951
  int32_t numOfElems = 0;
40,706,098✔
2952

2953
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
107,273,260✔
2954
    if (colDataIsNull_s(pCol, i)) {
133,146,996✔
2955
      continue;
2,285,281✔
2956
    }
2957
    char*          data = colDataGetData(pCol, i);
64,288,217!
2958
    SFirstLastRes* pInputInfo = (SFirstLastRes*)varDataVal(data);
64,288,217✔
2959
    if (pCtx->hasPrimaryKey) {
64,288,217✔
2960
      pInputInfo->pkData = pInputInfo->buf + pInputInfo->bytes;
52✔
2961
    } else {
2962
      pInputInfo->pkData = NULL;
64,288,165✔
2963
    }
2964

2965
    int32_t code = firstLastTransferInfo(pCtx, pInputInfo, pInfo, isFirstQuery, i);
64,288,217✔
2966
    if (code != TSDB_CODE_SUCCESS) {
64,281,881!
UNCOV
2967
      return code;
×
2968
    }
2969
    if (!numOfElems) {
64,281,881✔
2970
      numOfElems = pInputInfo->hasResult ? 1 : 0;
40,696,306✔
2971
    }
2972
  }
2973

2974
  if (numOfElems == 0) {
40,699,762✔
2975
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
8,089✔
2976
    if (code != TSDB_CODE_SUCCESS) {
8,089!
UNCOV
2977
      return code;
×
2978
    }
2979
    pInfo->nullTupleSaved = true;
8,089✔
2980
  }
2981

2982
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
40,699,762✔
2983
  return TSDB_CODE_SUCCESS;
40,699,762✔
2984
}
2985

2986
int32_t firstFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, true); }
11,517,080✔
2987

2988
int32_t lastFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, false); }
29,190,642✔
2989

2990
int32_t firstLastFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
93,106,918✔
2991
  int32_t          code = TSDB_CODE_SUCCESS;
93,106,918✔
2992
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
93,106,918✔
2993
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
93,106,918✔
2994
  if (NULL == pCol) {
93,093,497!
UNCOV
2995
    return TSDB_CODE_OUT_OF_RANGE;
×
2996
  }
2997

2998
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
93,093,497✔
2999
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
93,093,497✔
3000

3001
  SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pResInfo);
93,093,497✔
3002

3003
  if (pResInfo->isNullRes) {
93,093,497✔
3004
    colDataSetNULL(pCol, pBlock->info.rows);
41,778✔
3005
    return setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
41,778✔
3006
  }
3007
  code = colDataSetVal(pCol, pBlock->info.rows, pRes->buf, pRes->isNull || pResInfo->isNullRes);
93,051,719!
3008
  if (TSDB_CODE_SUCCESS != code) {
93,019,686!
UNCOV
3009
    return code;
×
3010
  }
3011

3012
  // handle selectivity
3013
  code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
93,019,686✔
3014

3015
  return code;
93,002,876✔
3016
}
3017

3018
int32_t firstLastPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
68,511,114✔
3019
  int32_t code = TSDB_CODE_SUCCESS;
68,511,114✔
3020

3021
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
68,511,114✔
3022
  SFirstLastRes*       pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
68,511,114✔
3023

3024
  int32_t resultBytes = getFirstLastInfoSize(pRes->bytes, pRes->pkBytes);
68,511,114✔
3025

3026
  // todo check for failure
3027
  char* res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
68,471,827!
3028
  if (NULL == res) {
68,771,009!
UNCOV
3029
    return terrno;
×
3030
  }
3031
  (void)memcpy(varDataVal(res), pRes, resultBytes);
68,771,009✔
3032

3033
  varDataSetLen(res, resultBytes);
68,771,009✔
3034

3035
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
68,771,009✔
3036
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
68,771,009✔
3037
  if (NULL == pCol) {
68,685,853!
UNCOV
3038
    taosMemoryFree(res);
×
UNCOV
3039
    return TSDB_CODE_OUT_OF_RANGE;
×
3040
  }
3041

3042
  if (pEntryInfo->numOfRes == 0) {
68,703,158✔
3043
    colDataSetNULL(pCol, pBlock->info.rows);
2,371,670!
3044
    code = setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
2,371,670✔
3045
  } else {
3046
    code = colDataSetVal(pCol, pBlock->info.rows, res, false);
66,331,488✔
3047
    if (TSDB_CODE_SUCCESS != code) {
66,001,807!
UNCOV
3048
      taosMemoryFree(res);
×
UNCOV
3049
      return code;
×
3050
    }
3051
    code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
66,001,807✔
3052
  }
3053
  taosMemoryFree(res);
68,374,592!
3054
  return code;
68,846,327✔
3055
}
3056

3057
int32_t lastCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
11✔
3058
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
11✔
3059
  SFirstLastRes*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
11✔
3060
  int32_t              bytes = pDBuf->bytes;
11✔
3061

3062
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
11✔
3063
  SFirstLastRes*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
11✔
3064

3065
  pDBuf->hasResult = firstLastTransferInfoImpl(pSBuf, pDBuf, false);
11✔
3066
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
11✔
3067
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
11✔
3068
  return TSDB_CODE_SUCCESS;
11✔
3069
}
3070

3071
static int32_t doSaveLastrow(SqlFunctionCtx* pCtx, char* pData, int32_t rowIndex, int64_t cts, SFirstLastRes* pInfo) {
51,529,968✔
3072
  SInputColumnInfoData* pInput = &pCtx->input;
51,529,968✔
3073
  SColumnInfoData*      pInputCol = pInput->pData[0];
51,529,968✔
3074
  SColumnInfoData*      pkCol = pInput->pPrimaryKey;
51,529,968✔
3075

3076
  if (colDataIsNull_s(pInputCol, rowIndex)) {
103,059,936✔
3077
    pInfo->isNull = true;
7,736✔
3078
  } else {
3079
    pInfo->isNull = false;
51,522,232✔
3080

3081
    if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
51,522,232!
3082
      if (pInputCol->info.type == TSDB_DATA_TYPE_JSON) {
1,492!
UNCOV
3083
        pInfo->bytes = getJsonValueLen(pData);
×
3084
      } else {
3085
        pInfo->bytes = varDataTLen(pData);
1,492✔
3086
      }
3087
    }
3088

3089
    (void)memcpy(pInfo->buf, pData, pInfo->bytes);
51,522,232✔
3090
  }
3091

3092
  if (pCtx->hasPrimaryKey && !colDataIsNull_s(pkCol, rowIndex)) {
51,530,040!
3093
    char* pkData = colDataGetData(pkCol, rowIndex);
72!
3094
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
72!
3095
      if (pInfo->pkType == TSDB_DATA_TYPE_JSON) {
12!
UNCOV
3096
        pInfo->pkBytes = getJsonValueLen(pkData);
×
3097
      } else {
3098
        pInfo->pkBytes = varDataTLen(pkData);
12✔
3099
      }
3100
    }
3101
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
72✔
3102
    pInfo->pkData = pInfo->buf + pInfo->bytes;
72✔
3103
  }
3104
  pInfo->ts = cts;
51,529,968✔
3105
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
51,529,968✔
3106
  if (code != TSDB_CODE_SUCCESS) {
51,516,741!
UNCOV
3107
    return code;
×
3108
  }
3109

3110
  pInfo->hasResult = true;
51,516,741✔
3111

3112
  return TSDB_CODE_SUCCESS;
51,516,741✔
3113
}
3114

3115
int32_t lastRowFunction(SqlFunctionCtx* pCtx) {
52,155,268✔
3116
  int32_t numOfElems = 0;
52,155,268✔
3117

3118
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
52,155,268✔
3119
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
52,155,268✔
3120

3121
  SInputColumnInfoData* pInput = &pCtx->input;
52,155,268✔
3122
  SColumnInfoData*      pInputCol = pInput->pData[0];
52,155,268✔
3123

3124
  int32_t type = pInputCol->info.type;
52,155,268✔
3125
  int32_t bytes = pInputCol->info.bytes;
52,155,268✔
3126
  pInfo->bytes = bytes;
52,155,268✔
3127

3128
  if (IS_NULL_TYPE(type)) {
52,155,268✔
3129
    return TSDB_CODE_SUCCESS;
56✔
3130
  }
3131
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
52,155,212✔
3132
  pInfo->pkType = -1;
52,155,212✔
3133
  __compar_fn_t pkCompareFn = NULL;
52,155,212✔
3134
  if (pCtx->hasPrimaryKey) {
52,155,212✔
3135
    pInfo->pkType = pkCol->info.type;
57✔
3136
    pInfo->pkBytes = pkCol->info.bytes;
57✔
3137
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
57✔
3138
  }
3139
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
52,165,589✔
3140
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
52,165,589!
3141

3142
  if (pCtx->order == TSDB_ORDER_ASC && !pCtx->hasPrimaryKey) {
52,165,589!
3143
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
63,713,268!
3144
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
31,857,745✔
3145
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
31,857,745!
3146
      TSKEY cts = getRowPTs(pInput->pPTS, i);
31,857,745!
3147
      numOfElems++;
31,857,745✔
3148

3149
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
31,857,745✔
3150
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
31,254,488✔
3151
        if (code != TSDB_CODE_SUCCESS) return code;
31,252,402!
3152
      }
3153

3154
      break;
31,855,659✔
3155
    }
3156
  } else if (!pCtx->hasPrimaryKey && pCtx->order == TSDB_ORDER_DESC) {
20,307,980!
3157
    // the optimized version only valid if all tuples in one block are monotonious increasing or descreasing.
3158
    // this assumption is NOT always works if project operator exists in downstream.
3159
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
40,621,842!
3160
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
20,317,059✔
3161
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
20,317,059!
3162
      TSKEY cts = getRowPTs(pInput->pPTS, i);
20,317,059!
3163
      numOfElems++;
20,317,059✔
3164

3165
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
20,317,059!
3166
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
19,986,617✔
3167
        if (code != TSDB_CODE_SUCCESS) return code;
19,975,301!
3168
      }
3169
      break;
20,305,743✔
3170
    }
3171
  } else {
UNCOV
3172
    int64_t* pts = (int64_t*)pInput->pPTS->pData;
×
UNCOV
3173
    int      from = -1;
×
UNCOV
3174
    int32_t  i = -1;
×
3175
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
288,814✔
3176
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
296,933✔
3177
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
296,933!
3178
      TSKEY cts = pts[i];
296,933✔
3179

3180
      numOfElems++;
296,933✔
3181
      char* pkData = NULL;
296,933✔
3182
      if (pCtx->hasPrimaryKey) {
296,933✔
3183
        pkData = colDataGetData(pkCol, i);
171!
3184
      }
3185
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts ||
296,933✔
3186
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
9,798!
3187
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
287,141✔
3188
        if (code != TSDB_CODE_SUCCESS) {
287,141!
UNCOV
3189
          return code;
×
3190
        }
3191
        pResInfo->numOfRes = 1;
287,141✔
3192
      }
3193
    }
3194
  }
3195

3196
  SET_VAL(pResInfo, numOfElems, 1);
52,161,643!
3197
  return TSDB_CODE_SUCCESS;
52,161,643✔
3198
}
3199

3200
bool getDiffFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
38,412✔
3201
  pEnv->calcMemSize = sizeof(SDiffInfo);
38,412✔
3202
  return true;
38,412✔
3203
}
3204

3205
int32_t diffFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
1,554,793✔
3206
  if (pResInfo->initialized) {
1,554,793✔
3207
    return TSDB_CODE_SUCCESS;
1,474,541✔
3208
  }
3209
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
80,252!
3210
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3211
  }
3212
  SDiffInfo* pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
80,252✔
3213
  pDiffInfo->hasPrev = false;
80,252✔
3214
  pDiffInfo->isFirstRow = true;
80,252✔
3215
  pDiffInfo->prev.i64 = 0;
80,252✔
3216
  pDiffInfo->prevTs = -1;
80,252✔
3217
  if (pCtx->numOfParams > 1) {
80,252!
3218
    pDiffInfo->ignoreOption = pCtx->param[1].param.i;  // TODO set correct param
80,252✔
3219
  } else {
3220
    pDiffInfo->ignoreOption = 0;
×
3221
  }
3222
  return TSDB_CODE_SUCCESS;
80,252✔
3223
}
3224

3225
static int32_t doSetPrevVal(SDiffInfo* pDiffInfo, int32_t type, const char* pv, int64_t ts) {
1,557,165✔
3226
  switch (type) {
1,557,165!
3227
    case TSDB_DATA_TYPE_BOOL:
28✔
3228
      pDiffInfo->prev.i64 = *(bool*)pv ? 1 : 0;
28✔
3229
      break;
28✔
3230
    case TSDB_DATA_TYPE_UTINYINT:
82,381✔
3231
    case TSDB_DATA_TYPE_TINYINT:
3232
      pDiffInfo->prev.i64 = *(int8_t*)pv;
82,381✔
3233
      break;
82,381✔
3234
    case TSDB_DATA_TYPE_UINT:
118,589✔
3235
    case TSDB_DATA_TYPE_INT:
3236
      pDiffInfo->prev.i64 = *(int32_t*)pv;
118,589✔
3237
      break;
118,589✔
3238
    case TSDB_DATA_TYPE_USMALLINT:
1,145,506✔
3239
    case TSDB_DATA_TYPE_SMALLINT:
3240
      pDiffInfo->prev.i64 = *(int16_t*)pv;
1,145,506✔
3241
      break;
1,145,506✔
3242
    case TSDB_DATA_TYPE_TIMESTAMP:
232✔
3243
    case TSDB_DATA_TYPE_UBIGINT:
3244
    case TSDB_DATA_TYPE_BIGINT:
3245
      pDiffInfo->prev.i64 = *(int64_t*)pv;
232✔
3246
      break;
232✔
3247
    case TSDB_DATA_TYPE_FLOAT:
259✔
3248
      pDiffInfo->prev.d64 = *(float*)pv;
259✔
3249
      break;
259✔
3250
    case TSDB_DATA_TYPE_DOUBLE:
210,170✔
3251
      pDiffInfo->prev.d64 = *(double*)pv;
210,170✔
3252
      break;
210,170✔
UNCOV
3253
    default:
×
UNCOV
3254
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3255
  }
3256
  pDiffInfo->prevTs = ts;
1,557,165✔
3257
  pDiffInfo->hasPrev = true;
1,557,165✔
3258
  return TSDB_CODE_SUCCESS;
1,557,165✔
3259
}
3260

3261
static bool diffIsNegtive(SDiffInfo* pDiffInfo, int32_t type, const char* pv) {
6,941,798✔
3262
  switch (type) {
6,941,798!
UNCOV
3263
    case TSDB_DATA_TYPE_UINT: {
×
UNCOV
3264
      int64_t v = *(uint32_t*)pv;
×
UNCOV
3265
      return v < pDiffInfo->prev.i64;
×
3266
    }
3267
    case TSDB_DATA_TYPE_INT: {
419,809✔
3268
      int64_t v = *(int32_t*)pv;
419,809✔
3269
      return v < pDiffInfo->prev.i64;
419,809✔
3270
    }
UNCOV
3271
    case TSDB_DATA_TYPE_BOOL: {
×
UNCOV
3272
      int64_t v = *(bool*)pv;
×
UNCOV
3273
      return v < pDiffInfo->prev.i64;
×
3274
    }
UNCOV
3275
    case TSDB_DATA_TYPE_UTINYINT: {
×
UNCOV
3276
      int64_t v = *(uint8_t*)pv;
×
UNCOV
3277
      return v < pDiffInfo->prev.i64;
×
3278
    }
3279
    case TSDB_DATA_TYPE_TINYINT: {
281,171✔
3280
      int64_t v = *(int8_t*)pv;
281,171✔
3281
      return v < pDiffInfo->prev.i64;
281,171✔
3282
    }
UNCOV
3283
    case TSDB_DATA_TYPE_USMALLINT: {
×
UNCOV
3284
      int64_t v = *(uint16_t*)pv;
×
UNCOV
3285
      return v < pDiffInfo->prev.i64;
×
3286
    }
3287
    case TSDB_DATA_TYPE_SMALLINT: {
5,393,714✔
3288
      int64_t v = *(int16_t*)pv;
5,393,714✔
3289
      return v < pDiffInfo->prev.i64;
5,393,714✔
3290
    }
3291
    case TSDB_DATA_TYPE_UBIGINT: {
24✔
3292
      uint64_t v = *(uint64_t*)pv;
24✔
3293
      return v < (uint64_t)pDiffInfo->prev.i64;
24✔
3294
    }
3295
    case TSDB_DATA_TYPE_TIMESTAMP:
3,629✔
3296
    case TSDB_DATA_TYPE_BIGINT: {
3297
      int64_t v = *(int64_t*)pv;
3,629✔
3298
      return v < pDiffInfo->prev.i64;
3,629✔
3299
    }
3300
    case TSDB_DATA_TYPE_FLOAT: {
6,081✔
3301
      float v = *(float*)pv;
6,081✔
3302
      return v < pDiffInfo->prev.d64;
6,081✔
3303
    }
3304
    case TSDB_DATA_TYPE_DOUBLE: {
837,370✔
3305
      double v = *(double*)pv;
837,370✔
3306
      return v < pDiffInfo->prev.d64;
837,370✔
3307
    }
UNCOV
3308
    default:
×
UNCOV
3309
      return false;
×
3310
  }
3311

3312
  return false;
3313
}
3314

3315
static void tryToSetInt64(SDiffInfo* pDiffInfo, int32_t type, SColumnInfoData* pOutput, int64_t v, int32_t pos) {
1,240,303,720✔
3316
  bool isNegative = v < pDiffInfo->prev.i64;
1,240,303,720✔
3317
  if (type == TSDB_DATA_TYPE_UBIGINT) {
1,240,303,720✔
3318
    isNegative = (uint64_t)v < (uint64_t)pDiffInfo->prev.i64;
453✔
3319
  }
3320
  int64_t delta = v - pDiffInfo->prev.i64;
1,240,303,720✔
3321
  if (isNegative && ignoreNegative(pDiffInfo->ignoreOption)) {
1,240,303,720✔
3322
    colDataSetNull_f_s(pOutput, pos);
1,851,019✔
3323
    pOutput->hasNull = true;
1,851,019✔
3324
  } else {
3325
    colDataSetInt64(pOutput, pos, &delta);
1,238,452,701✔
3326
  }
3327
  pDiffInfo->prev.i64 = v;
1,240,303,720✔
3328
}
1,240,303,720✔
3329

3330
static void tryToSetDouble(SDiffInfo* pDiffInfo, SColumnInfoData* pOutput, double v, int32_t pos) {
1,136,779✔
3331
  double delta = v - pDiffInfo->prev.d64;
1,136,779✔
3332
  if (delta < 0 && ignoreNegative(pDiffInfo->ignoreOption)) {
1,136,779✔
3333
    colDataSetNull_f_s(pOutput, pos);
211,972✔
3334
  } else {
3335
    colDataSetDouble(pOutput, pos, &delta);
924,807✔
3336
  }
3337
  pDiffInfo->prev.d64 = v;
1,136,779✔
3338
}
1,136,779✔
3339

3340
static int32_t doHandleDiff(SDiffInfo* pDiffInfo, int32_t type, const char* pv, SColumnInfoData* pOutput, int32_t pos,
1,241,441,068✔
3341
                            int64_t ts) {
3342
  if (!pDiffInfo->hasPrev) {
1,241,441,068✔
3343
    colDataSetNull_f_s(pOutput, pos);
569✔
3344
    return doSetPrevVal(pDiffInfo, type, pv, ts);
569✔
3345
  }
3346
  pDiffInfo->prevTs = ts;
1,241,440,499✔
3347
  switch (type) {
1,241,440,499!
3348
    case TSDB_DATA_TYPE_UINT: {
411✔
3349
      int64_t v = *(uint32_t*)pv;
411✔
3350
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
411✔
3351
      break;
411✔
3352
    }
3353
    case TSDB_DATA_TYPE_INT: {
21,358,721✔
3354
      int64_t v = *(int32_t*)pv;
21,358,721✔
3355
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
21,358,721✔
3356
      break;
21,358,721✔
3357
    }
3358
    case TSDB_DATA_TYPE_BOOL: {
10,617✔
3359
      int64_t v = *(bool*)pv;
10,617✔
3360
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
10,617✔
3361
      break;
10,617✔
3362
    }
3363
    case TSDB_DATA_TYPE_UTINYINT: {
405✔
3364
      int64_t v = *(uint8_t*)pv;
405✔
3365
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
405✔
3366
      break;
405✔
3367
    }
3368
    case TSDB_DATA_TYPE_TINYINT: {
370,728✔
3369
      int64_t v = *(int8_t*)pv;
370,728✔
3370
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
370,728✔
3371
      break;
370,728✔
3372
    }
3373
    case TSDB_DATA_TYPE_USMALLINT: {
405✔
3374
      int64_t v = *(uint16_t*)pv;
405✔
3375
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
405✔
3376
      break;
405✔
3377
    }
3378
    case TSDB_DATA_TYPE_SMALLINT: {
5,549,216✔
3379
      int64_t v = *(int16_t*)pv;
5,549,216✔
3380
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
5,549,216✔
3381
      break;
5,549,216✔
3382
    }
3383
    case TSDB_DATA_TYPE_TIMESTAMP:
1,213,013,217✔
3384
    case TSDB_DATA_TYPE_UBIGINT:
3385
    case TSDB_DATA_TYPE_BIGINT: {
3386
      int64_t v = *(int64_t*)pv;
1,213,013,217✔
3387
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
1,213,013,217✔
3388
      break;
1,213,013,217✔
3389
    }
3390
    case TSDB_DATA_TYPE_FLOAT: {
48,537✔
3391
      double v = *(float*)pv;
48,537✔
3392
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
48,537✔
3393
      break;
48,537✔
3394
    }
3395
    case TSDB_DATA_TYPE_DOUBLE: {
1,088,242✔
3396
      double v = *(double*)pv;
1,088,242✔
3397
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
1,088,242✔
3398
      break;
1,088,242✔
3399
    }
UNCOV
3400
    default:
×
UNCOV
3401
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3402
  }
3403
  pDiffInfo->hasPrev = true;
1,241,440,499✔
3404
  return TSDB_CODE_SUCCESS;
1,241,440,499✔
3405
}
3406

3407
// TODO: the primary key compare can be skipped for ordered pk if knonwn before
3408
// TODO: for desc ordered, pk shall select the smallest one for one ts. if across block boundaries.
3409
bool funcInputGetNextRowIndex(SInputColumnInfoData* pInput, int32_t from, bool firstOccur, int32_t* pRowIndex,
319,710,069✔
3410
                              int32_t* nextFrom) {
3411
  if (pInput->pPrimaryKey == NULL) {
319,710,069✔
3412
    if (from == -1) {
219,726,073✔
3413
      from = pInput->startRowIndex;
67,084,619✔
3414
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
152,641,454✔
3415
      return false;
66,781,769✔
3416
    }
3417
    *pRowIndex = from;
152,944,304✔
3418
    *nextFrom = from + 1;
152,944,304✔
3419
    return true;
152,944,304✔
3420
  } else {
3421
    if (from == -1) {
99,983,996✔
3422
      from = pInput->startRowIndex;
30,175✔
3423
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
99,953,821✔
3424
      return false;
30,175✔
3425
    }
3426
    TSKEY*           tsList = (int64_t*)pInput->pPTS->pData;
99,953,821✔
3427
    SColumnInfoData* pkCol = pInput->pPrimaryKey;
99,953,821✔
3428
    int8_t           pkType = pkCol->info.type;
99,953,821✔
3429
    int32_t          order = (firstOccur) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
99,953,821✔
3430
    __compar_fn_t    compareFunc = getKeyComparFunc(pkType, order);
99,953,821✔
3431
    int32_t          select = from;
100,000,517✔
3432
    char*            val = colDataGetData(pkCol, select);
100,000,517!
3433
    while (from < pInput->numOfRows + pInput->startRowIndex - 1 && tsList[from + 1] == tsList[from]) {
100,001,072✔
3434
      char* val1 = colDataGetData(pkCol, from + 1);
555!
3435
      if (compareFunc(val1, val) < 0) {
555!
UNCOV
3436
        select = from + 1;
×
UNCOV
3437
        val = val1;
×
3438
      }
3439
      from = from + 1;
555✔
3440
    }
3441
    *pRowIndex = select;
100,000,517✔
3442
    *nextFrom = from + 1;
100,000,517✔
3443
    return true;
100,000,517✔
3444
  }
3445
}
3446

3447
bool getForecastConfEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
26✔
3448
  pEnv->calcMemSize = sizeof(float);
26✔
3449
  return true;
26✔
3450
}
3451

3452
int32_t diffResultIsNull(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
1,243,088,400✔
3453
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,243,088,400✔
3454
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,243,088,400✔
3455

3456
  if (pRow->isDataNull || !pDiffInfo->hasPrev) {
1,243,088,400✔
3457
    return true;
169,816✔
3458
  } else if (ignoreNegative(pDiffInfo->ignoreOption)) {
1,242,918,584✔
3459
    return diffIsNegtive(pDiffInfo, pCtx->input.pData[0]->info.type, pRow->pData);
6,941,798✔
3460
  }
3461
  return false;
1,235,976,786✔
3462
}
3463

3464
bool isFirstRow(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
1,241,597,150✔
3465
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,241,597,150✔
3466
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,241,597,150✔
3467
  return pDiffInfo->isFirstRow;
1,241,597,150✔
3468
}
3469

3470
int32_t trySetPreVal(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
1,558,368✔
3471
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,558,368✔
3472
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,558,368✔
3473
  pDiffInfo->isFirstRow = false;
1,558,368✔
3474
  if (pRow->isDataNull) {
1,558,368✔
3475
    return TSDB_CODE_SUCCESS;
1,772✔
3476
  }
3477

3478
  SInputColumnInfoData* pInput = &pCtx->input;
1,556,596✔
3479
  SColumnInfoData*      pInputCol = pInput->pData[0];
1,556,596✔
3480
  int8_t                inputType = pInputCol->info.type;
1,556,596✔
3481

3482
  char* pv = pRow->pData;
1,556,596✔
3483
  return doSetPrevVal(pDiffInfo, inputType, pv, pRow->ts);
1,556,596✔
3484
}
3485

3486
int32_t setDoDiffResult(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, int32_t pos) {
1,241,530,032✔
3487
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,241,530,032✔
3488
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,241,530,032✔
3489

3490
  SInputColumnInfoData* pInput = &pCtx->input;
1,241,530,032✔
3491
  SColumnInfoData*      pInputCol = pInput->pData[0];
1,241,530,032✔
3492
  int8_t                inputType = pInputCol->info.type;
1,241,530,032✔
3493
  SColumnInfoData*      pOutput = (SColumnInfoData*)pCtx->pOutput;
1,241,530,032✔
3494
  int32_t               code = TSDB_CODE_SUCCESS;
1,241,530,032✔
3495
  if (pRow->isDataNull) {
1,241,530,032✔
3496
    colDataSetNull_f_s(pOutput, pos);
88,943✔
3497
    pOutput->hasNull = true;
88,943✔
3498

3499
    // handle selectivity
3500
    if (pCtx->subsidiaries.num > 0) {
88,943✔
3501
      code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
149✔
3502
      if (code != TSDB_CODE_SUCCESS) {
149!
UNCOV
3503
        return code;
×
3504
      }
3505
    }
3506
    return TSDB_CODE_SUCCESS;
88,943✔
3507
  }
3508

3509
  char* pv = pRow->pData;
1,241,441,089✔
3510

3511
  if (pRow->ts == pDiffInfo->prevTs) {
1,241,441,089✔
3512
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
21✔
3513
  }
3514
  code = doHandleDiff(pDiffInfo, inputType, pv, pOutput, pos, pRow->ts);
1,241,441,068✔
3515
  if (code != TSDB_CODE_SUCCESS) {
1,241,441,068!
UNCOV
3516
    return code;
×
3517
  }
3518
  // handle selectivity
3519
  if (pCtx->subsidiaries.num > 0) {
1,241,441,068✔
3520
    code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
24,891,931✔
3521
    if (code != TSDB_CODE_SUCCESS) {
24,891,931!
3522
      return code;
×
3523
    }
3524
  }
3525

3526
  return TSDB_CODE_SUCCESS;
1,241,441,068✔
3527
}
3528

3529
int32_t diffFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; }
1,516,381✔
3530

3531
int32_t diffFunctionByRow(SArray* pCtxArray) {
1,516,225✔
3532
  int32_t code = TSDB_CODE_SUCCESS;
1,516,225✔
3533
  int     diffColNum = pCtxArray->size;
1,516,225✔
3534
  if (diffColNum == 0) {
1,516,225!
UNCOV
3535
    return TSDB_CODE_SUCCESS;
×
3536
  }
3537
  int32_t numOfElems = 0;
1,516,225✔
3538

3539
  SArray* pRows = taosArrayInit_s(sizeof(SFuncInputRow), diffColNum);
1,516,225✔
3540
  if (NULL == pRows) {
1,516,225!
3541
    return terrno;
×
3542
  }
3543

3544
  bool keepNull = false;
1,516,225✔
3545
  for (int i = 0; i < diffColNum; ++i) {
3,032,606✔
3546
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
1,516,381✔
3547
    if (NULL == pCtx) {
1,516,381!
UNCOV
3548
      code = terrno;
×
UNCOV
3549
      goto _exit;
×
3550
    }
3551
    funcInputUpdate(pCtx);
1,516,381✔
3552
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,516,381✔
3553
    SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,516,381✔
3554
    if (!ignoreNull(pDiffInfo->ignoreOption)) {
1,516,381✔
3555
      keepNull = true;
1,503,306✔
3556
    }
3557
  }
3558

3559
  SqlFunctionCtx* pCtx0 = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, 0);
1,516,225✔
3560
  SFuncInputRow*  pRow0 = (SFuncInputRow*)taosArrayGet(pRows, 0);
1,516,225✔
3561
  if (NULL == pCtx0 || NULL == pRow0) {
1,516,225!
3562
    code = terrno;
×
3563
    goto _exit;
×
3564
  }
3565
  int32_t startOffset = pCtx0->offset;
1,516,225✔
3566
  bool    result = false;
1,516,225✔
3567
  while (1) {
1,243,073,885✔
3568
    code = funcInputGetNextRow(pCtx0, pRow0, &result);
1,244,590,110✔
3569
    if (TSDB_CODE_SUCCESS != code) {
1,244,590,110!
UNCOV
3570
      goto _exit;
×
3571
    }
3572
    if (!result) {
1,244,590,110✔
3573
      break;
1,516,204✔
3574
    }
3575
    bool hasNotNullValue = !diffResultIsNull(pCtx0, pRow0);
1,243,073,906✔
3576
    for (int i = 1; i < diffColNum; ++i) {
1,243,088,400✔
3577
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
14,494✔
3578
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
14,494✔
3579
      if (NULL == pCtx || NULL == pRow) {
14,494!
UNCOV
3580
        code = terrno;
×
UNCOV
3581
        goto _exit;
×
3582
      }
3583
      code = funcInputGetNextRow(pCtx, pRow, &result);
14,494✔
3584
      if (TSDB_CODE_SUCCESS != code) {
14,494!
UNCOV
3585
        goto _exit;
×
3586
      }
3587
      if (!result) {
14,494!
3588
        // rows are not equal
UNCOV
3589
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
3590
        goto _exit;
×
3591
      }
3592
      if (!diffResultIsNull(pCtx, pRow)) {
14,494✔
3593
        hasNotNullValue = true;
14,052✔
3594
      }
3595
    }
3596
    int32_t pos = startOffset + numOfElems;
1,243,073,906✔
3597

3598
    bool newRow = false;
1,243,073,906✔
3599
    for (int i = 0; i < diffColNum; ++i) {
2,147,483,647✔
3600
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
1,243,088,400✔
3601
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
1,243,088,400✔
3602
      if (NULL == pCtx || NULL == pRow) {
1,243,088,400!
UNCOV
3603
        code = terrno;
×
UNCOV
3604
        goto _exit;
×
3605
      }
3606
      if ((keepNull || hasNotNullValue) && !isFirstRow(pCtx, pRow)) {
1,243,088,400✔
3607
        code = setDoDiffResult(pCtx, pRow, pos);
1,241,530,032✔
3608
        if (code != TSDB_CODE_SUCCESS) {
1,241,530,032✔
3609
          goto _exit;
21✔
3610
        }
3611
        newRow = true;
1,241,530,011✔
3612
      } else {
3613
        code = trySetPreVal(pCtx, pRow);
1,558,368✔
3614
        if (code != TSDB_CODE_SUCCESS) {
1,558,368!
UNCOV
3615
          goto _exit;
×
3616
        }
3617
      }
3618
    }
3619
    if (newRow) ++numOfElems;
1,243,073,885✔
3620
  }
3621

3622
  for (int i = 0; i < diffColNum; ++i) {
3,032,561✔
3623
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
1,516,357✔
3624
    if (NULL == pCtx) {
1,516,357!
UNCOV
3625
      code = terrno;
×
UNCOV
3626
      goto _exit;
×
3627
    }
3628
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,516,357✔
3629
    pResInfo->numOfRes = numOfElems;
1,516,357✔
3630
  }
3631

3632
_exit:
1,516,204✔
3633
  if (pRows) {
1,516,225!
3634
    taosArrayDestroy(pRows);
1,516,225✔
3635
    pRows = NULL;
1,516,225✔
3636
  }
3637
  return code;
1,516,225✔
3638
}
3639

UNCOV
3640
int32_t getTopBotInfoSize(int64_t numOfItems) { return sizeof(STopBotRes) + numOfItems * sizeof(STopBotResItem); }
×
3641

3642
bool getTopBotFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
81,862✔
3643
  SValueNode* pkNode = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
81,862✔
3644
  pEnv->calcMemSize = sizeof(STopBotRes) + pkNode->datum.i * sizeof(STopBotResItem);
81,887✔
3645
  return true;
81,887✔
3646
}
3647

3648
int32_t topBotFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
39,082,989✔
3649
  if (pResInfo->initialized) {
39,082,989!
UNCOV
3650
    return TSDB_CODE_SUCCESS;
×
3651
  }
3652
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
39,082,989!
UNCOV
3653
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3654
  }
3655

3656
  STopBotRes*           pRes = GET_ROWCELL_INTERBUF(pResInfo);
39,094,095✔
3657
  SInputColumnInfoData* pInput = &pCtx->input;
39,094,095✔
3658

3659
  pRes->maxSize = pCtx->param[1].param.i;
39,094,095✔
3660

3661
  pRes->nullTupleSaved = false;
39,094,095✔
3662
  pRes->nullTuplePos.pageId = -1;
39,094,095✔
3663
  return TSDB_CODE_SUCCESS;
39,094,095✔
3664
}
3665

3666
static STopBotRes* getTopBotOutputInfo(SqlFunctionCtx* pCtx) {
178,213,689✔
3667
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
178,213,689✔
3668
  STopBotRes*          pRes = GET_ROWCELL_INTERBUF(pResInfo);
178,213,689✔
3669
  pRes->pItems = (STopBotResItem*)((char*)pRes + sizeof(STopBotRes));
178,213,689✔
3670

3671
  return pRes;
178,213,689✔
3672
}
3673

3674
static int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock,
3675
                               uint16_t type, uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery);
3676

3677
static int32_t addResult(SqlFunctionCtx* pCtx, STopBotResItem* pSourceItem, int16_t type, bool isTopQuery);
3678

3679
int32_t topFunction(SqlFunctionCtx* pCtx) {
9,865,118✔
3680
  int32_t              numOfElems = 0;
9,865,118✔
3681
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
9,865,118✔
3682

3683
  SInputColumnInfoData* pInput = &pCtx->input;
9,865,118✔
3684
  SColumnInfoData*      pCol = pInput->pData[0];
9,865,118✔
3685

3686
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
9,865,118✔
3687
  pRes->type = pInput->pData[0]->info.type;
9,865,096✔
3688

3689
  int32_t start = pInput->startRowIndex;
9,865,096✔
3690
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
35,425,225✔
3691
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
25,559,700✔
3692
      continue;
30,498✔
3693
    }
3694

3695
    numOfElems++;
25,529,202✔
3696
    char*   data = colDataGetData(pCol, i);
25,529,202!
3697
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, true);
25,529,202✔
3698
    if (code != TSDB_CODE_SUCCESS) {
25,529,631!
UNCOV
3699
      return code;
×
3700
    }
3701
  }
3702

3703
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
9,865,525✔
3704
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
1,089✔
3705
    if (code != TSDB_CODE_SUCCESS) {
1,089!
UNCOV
3706
      return code;
×
3707
    }
3708
    pRes->nullTupleSaved = true;
1,089✔
3709
  }
3710
  return TSDB_CODE_SUCCESS;
9,865,525✔
3711
}
3712

3713
int32_t bottomFunction(SqlFunctionCtx* pCtx) {
29,851,107✔
3714
  int32_t              numOfElems = 0;
29,851,107✔
3715
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
29,851,107✔
3716

3717
  SInputColumnInfoData* pInput = &pCtx->input;
29,851,107✔
3718
  SColumnInfoData*      pCol = pInput->pData[0];
29,851,107✔
3719

3720
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
29,851,107✔
3721
  pRes->type = pInput->pData[0]->info.type;
29,852,109✔
3722

3723
  int32_t start = pInput->startRowIndex;
29,852,109✔
3724
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
103,974,080✔
3725
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
74,114,718✔
3726
      continue;
27,934✔
3727
    }
3728

3729
    numOfElems++;
74,086,784✔
3730
    char*   data = colDataGetData(pCol, i);
74,086,784!
3731
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, false);
74,086,784✔
3732
    if (code != TSDB_CODE_SUCCESS) {
74,094,037!
UNCOV
3733
      return code;
×
3734
    }
3735
  }
3736

3737
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
29,859,362✔
3738
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
3,109✔
3739
    if (code != TSDB_CODE_SUCCESS) {
3,109!
UNCOV
3740
      return code;
×
3741
    }
3742
    pRes->nullTupleSaved = true;
3,109✔
3743
  }
3744

3745
  return TSDB_CODE_SUCCESS;
29,859,362✔
3746
}
3747

3748
static int32_t topBotResComparFn(const void* p1, const void* p2, const void* param) {
381,513,102✔
3749
  uint16_t type = *(uint16_t*)param;
381,513,102✔
3750

3751
  STopBotResItem* val1 = (STopBotResItem*)p1;
381,513,102✔
3752
  STopBotResItem* val2 = (STopBotResItem*)p2;
381,513,102✔
3753

3754
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
381,513,102!
3755
    if (val1->v.i == val2->v.i) {
268,751,105✔
3756
      return 0;
169,705✔
3757
    }
3758

3759
    return (val1->v.i > val2->v.i) ? 1 : -1;
268,581,400✔
3760
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
112,761,997!
3761
    if (val1->v.u == val2->v.u) {
486,601✔
3762
      return 0;
106,748✔
3763
    }
3764

3765
    return (val1->v.u > val2->v.u) ? 1 : -1;
379,853✔
3766
  } else if (TSDB_DATA_TYPE_FLOAT == type) {
112,275,396✔
3767
    if (val1->v.f == val2->v.f) {
65,197,091✔
3768
      return 0;
63✔
3769
    }
3770

3771
    return (val1->v.f > val2->v.f) ? 1 : -1;
65,197,028✔
3772
  }
3773

3774
  if (val1->v.d == val2->v.d) {
47,078,305✔
3775
    return 0;
11✔
3776
  }
3777

3778
  return (val1->v.d > val2->v.d) ? 1 : -1;
47,078,294✔
3779
}
3780

3781
int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock, uint16_t type,
99,614,366✔
3782
                        uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery) {
3783
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
99,614,366✔
3784
  int32_t     code = TSDB_CODE_SUCCESS;
99,611,965✔
3785

3786
  SVariant val = {0};
99,611,965✔
3787
  TAOS_CHECK_RETURN(taosVariantCreateFromBinary(&val, pData, tDataTypes[type].bytes, type));
99,611,965!
3788

3789
  STopBotResItem* pItems = pRes->pItems;
99,627,412✔
3790

3791
  // not full yet
3792
  if (pEntryInfo->numOfRes < pRes->maxSize) {
99,627,412✔
3793
    STopBotResItem* pItem = &pItems[pEntryInfo->numOfRes];
63,035,440✔
3794
    pItem->v = val;
63,035,440✔
3795
    pItem->uid = uid;
63,035,440✔
3796

3797
    // save the data of this tuple
3798
    if (pCtx->subsidiaries.num > 0) {
63,035,440✔
3799
      code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
35,766,662✔
3800
      if (code != TSDB_CODE_SUCCESS) {
35,752,905!
UNCOV
3801
        return code;
×
3802
      }
3803
    }
3804
#ifdef BUF_PAGE_DEBUG
3805
    qDebug("page_saveTuple i:%d, item:%p,pageId:%d, offset:%d\n", pEntryInfo->numOfRes, pItem, pItem->tuplePos.pageId,
3806
           pItem->tuplePos.offset);
3807
#endif
3808
    // allocate the buffer and keep the data of this row into the new allocated buffer
3809
    pEntryInfo->numOfRes++;
63,021,683✔
3810
    code = taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type,
63,021,683✔
3811
                        topBotResComparFn, !isTopQuery);
63,021,683✔
3812
    if (code != TSDB_CODE_SUCCESS) {
63,038,552!
3813
      return code;
×
3814
    }
3815
  } else {  // replace the minimum value in the result
3816
    if ((isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i > pItems[0].v.i) ||
36,591,972!
3817
                        (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u > pItems[0].v.u) ||
9,439,193!
3818
                        (TSDB_DATA_TYPE_FLOAT == type && val.f > pItems[0].v.f) ||
9,384,640✔
3819
                        (TSDB_DATA_TYPE_DOUBLE == type && val.d > pItems[0].v.d))) ||
9,383,527✔
3820
        (!isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i < pItems[0].v.i) ||
34,012,189!
3821
                         (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u < pItems[0].v.u) ||
22,278,219!
3822
                         (TSDB_DATA_TYPE_FLOAT == type && val.f < pItems[0].v.f) ||
22,277,244✔
3823
                         (TSDB_DATA_TYPE_DOUBLE == type && val.d < pItems[0].v.d)))) {
20,184,989✔
3824
      // replace the old data and the coresponding tuple data
3825
      STopBotResItem* pItem = &pItems[0];
8,528,903✔
3826
      pItem->v = val;
8,528,903✔
3827
      pItem->uid = uid;
8,528,903✔
3828

3829
      // save the data of this tuple by over writing the old data
3830
      if (pCtx->subsidiaries.num > 0) {
8,528,903✔
3831
        code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
5,929,430✔
3832
        if (code != TSDB_CODE_SUCCESS) {
5,927,567!
UNCOV
3833
          return code;
×
3834
        }
3835
      }
3836
#ifdef BUF_PAGE_DEBUG
3837
      qDebug("page_copyTuple pageId:%d, offset:%d", pItem->tuplePos.pageId, pItem->tuplePos.offset);
3838
#endif
3839
      code = taosheapadjust((void*)pItems, sizeof(STopBotResItem), 0, pEntryInfo->numOfRes - 1, (const void*)&type,
8,527,040✔
3840
                            topBotResComparFn, NULL, !isTopQuery);
8,527,040✔
3841
      if (code != TSDB_CODE_SUCCESS) {
8,516,946!
UNCOV
3842
        return code;
×
3843
      }
3844
    }
3845
  }
3846

3847
  return TSDB_CODE_SUCCESS;
99,618,567✔
3848
}
3849

3850
/*
3851
 * +------------------------------------+--------------+--------------+
3852
 * |            null bitmap             |              |              |
3853
 * |(n columns, one bit for each column)| src column #1| src column #2|
3854
 * +------------------------------------+--------------+--------------+
3855
 */
3856
int32_t serializeTupleData(const SSDataBlock* pSrcBlock, int32_t rowIndex, SSubsidiaryResInfo* pSubsidiaryies,
186,829,954✔
3857
                           char* buf, char** res) {
3858
  char* nullList = buf;
186,829,954✔
3859
  char* pStart = (char*)(nullList + sizeof(bool) * pSubsidiaryies->num);
186,829,954✔
3860

3861
  int32_t offset = 0;
186,829,954✔
3862
  for (int32_t i = 0; i < pSubsidiaryies->num; ++i) {
373,626,650✔
3863
    SqlFunctionCtx* pc = pSubsidiaryies->pCtx[i];
186,870,679✔
3864

3865
    // group_key function has its own process function
3866
    // do not process there
3867
    if (fmIsGroupKeyFunc(pc->functionId)) {
186,870,679!
UNCOV
3868
      continue;
×
3869
    }
3870

3871
    SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
186,872,473✔
3872
    int32_t      srcSlotId = pFuncParam->pCol->slotId;
186,872,473✔
3873

3874
    SColumnInfoData* pCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
186,872,473✔
3875
    if (NULL == pCol) {
186,796,696!
UNCOV
3876
      return TSDB_CODE_OUT_OF_RANGE;
×
3877
    }
3878
    if ((nullList[i] = colDataIsNull_s(pCol, rowIndex)) == true) {
373,593,392✔
3879
      offset += pCol->info.bytes;
691✔
3880
      continue;
691✔
3881
    }
3882

3883
    char* p = colDataGetData(pCol, rowIndex);
186,796,005!
3884
    if (IS_VAR_DATA_TYPE(pCol->info.type)) {
186,796,005!
3885
      (void)memcpy(pStart + offset, p, (pCol->info.type == TSDB_DATA_TYPE_JSON) ? getJsonValueLen(p) : varDataTLen(p));
29,989!
3886
    } else {
3887
      (void)memcpy(pStart + offset, p, pCol->info.bytes);
186,766,016✔
3888
    }
3889

3890
    offset += pCol->info.bytes;
186,796,005✔
3891
  }
3892

3893
  *res = buf;
186,755,971✔
3894
  return TSDB_CODE_SUCCESS;
186,755,971✔
3895
}
3896

3897
static int32_t doSaveTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, SWinKey* key,
149,348,086✔
3898
                               STuplePos* pPos, SFunctionStateStore* pStore) {
3899
  STuplePos p = {0};
149,348,086✔
3900
  if (pHandle->pBuf != NULL) {
149,348,086✔
3901
    SFilePage* pPage = NULL;
149,289,509✔
3902

3903
    if (pHandle->currentPage == -1) {
149,289,509✔
3904
      pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
659,062✔
3905
      if (pPage == NULL) {
659,096!
UNCOV
3906
        return terrno;
×
3907
      }
3908
      pPage->num = sizeof(SFilePage);
659,097✔
3909
    } else {
3910
      pPage = getBufPage(pHandle->pBuf, pHandle->currentPage);
148,630,447✔
3911
      if (pPage == NULL) {
148,601,614!
UNCOV
3912
        return terrno;
×
3913
      }
3914
      if (pPage->num + length > getBufPageSize(pHandle->pBuf)) {
148,601,614✔
3915
        // current page is all used, let's prepare a new buffer page
3916
        releaseBufPage(pHandle->pBuf, pPage);
133,120✔
3917
        pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
133,120✔
3918
        if (pPage == NULL) {
133,120!
UNCOV
3919
          return terrno;
×
3920
        }
3921
        pPage->num = sizeof(SFilePage);
133,120✔
3922
      }
3923
    }
3924

3925
    p = (STuplePos){.pageId = pHandle->currentPage, .offset = pPage->num};
149,257,524✔
3926
    (void)memcpy(pPage->data + pPage->num, pBuf, length);
149,257,524✔
3927

3928
    pPage->num += length;
149,257,524✔
3929
    setBufPageDirty(pPage, true);
149,257,524✔
3930
    releaseBufPage(pHandle->pBuf, pPage);
149,233,696✔
3931
  } else {  // other tuple save policy
3932
    if (pStore->streamStateFuncPut(pHandle->pState, key, pBuf, length) >= 0) {
58,577!
3933
      p.streamTupleKey = *key;
71,760✔
3934
    }
3935
  }
3936

3937
  *pPos = p;
149,285,277✔
3938
  return TSDB_CODE_SUCCESS;
149,285,277✔
3939
}
3940

3941
int32_t saveTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
146,161,732✔
3942
  int32_t code = prepareBuf(pCtx);
146,161,732✔
3943
  if (TSDB_CODE_SUCCESS != code) {
146,162,301!
3944
    return code;
×
3945
  }
3946

3947
  SWinKey key = {0};
146,162,301✔
3948
  if (pCtx->saveHandle.pBuf == NULL) {
146,162,301✔
3949
    SColumnInfoData* pColInfo = taosArrayGet(pSrcBlock->pDataBlock, pCtx->saveHandle.pState->tsIndex);
71,764✔
3950
    if (NULL == pColInfo) {
71,763!
UNCOV
3951
      return TSDB_CODE_OUT_OF_RANGE;
×
3952
    }
3953
    if (pColInfo->info.type != TSDB_DATA_TYPE_TIMESTAMP) {
71,763!
UNCOV
3954
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3955
    }
3956
    key.groupId = pSrcBlock->info.id.groupId;
71,763✔
3957
    key.ts = *(int64_t*)colDataGetData(pColInfo, rowIndex);
71,763!
3958
  }
3959

3960
  char* buf = NULL;
146,162,300✔
3961
  code = serializeTupleData(pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
146,162,300✔
3962
  if (TSDB_CODE_SUCCESS != code) {
146,112,286!
UNCOV
3963
    return code;
×
3964
  }
3965
  return doSaveTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, &key, pPos, pCtx->pStore);
146,112,286✔
3966
}
3967

3968
static int32_t doUpdateTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, STuplePos* pPos,
40,709,866✔
3969
                                 SFunctionStateStore* pStore) {
3970
  if (pHandle->pBuf != NULL) {
40,709,866✔
3971
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
40,582,800✔
3972
    if (pPage == NULL) {
40,582,119!
UNCOV
3973
      return terrno;
×
3974
    }
3975
    (void)memcpy(pPage->data + pPos->offset, pBuf, length);
40,582,119✔
3976
    setBufPageDirty(pPage, true);
40,582,119✔
3977
    releaseBufPage(pHandle->pBuf, pPage);
40,579,126✔
3978
  } else {
3979
    int32_t code = pStore->streamStateFuncPut(pHandle->pState, &pPos->streamTupleKey, pBuf, length);
127,066✔
3980
    if (TSDB_CODE_SUCCESS != code) {
127,422!
UNCOV
3981
      return code;
×
3982
    }
3983
  }
3984

3985
  return TSDB_CODE_SUCCESS;
40,705,416✔
3986
}
3987

3988
int32_t updateTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
40,711,217✔
3989
  int32_t code = prepareBuf(pCtx);
40,711,217✔
3990
  if (TSDB_CODE_SUCCESS != code) {
40,710,742!
UNCOV
3991
    return code;
×
3992
  }
3993

3994
  char* buf = NULL;
40,710,742✔
3995
  code = serializeTupleData(pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
40,710,742✔
3996
  if (TSDB_CODE_SUCCESS != code) {
40,709,346!
UNCOV
3997
    return code;
×
3998
  }
3999
  return doUpdateTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, pPos, pCtx->pStore);
40,709,346✔
4000
}
4001

4002
static int32_t doLoadTupleData(SSerializeDataHandle* pHandle, const STuplePos* pPos, SFunctionStateStore* pStore,
142,812,942✔
4003
                               char** value) {
4004
  if (pHandle->pBuf != NULL) {
142,812,942✔
4005
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
142,747,612✔
4006
    if (pPage == NULL) {
142,756,658!
4007
      *value = NULL;
×
4008
      return terrno;
×
4009
    }
4010
    *value = pPage->data + pPos->offset;
142,756,658✔
4011
    releaseBufPage(pHandle->pBuf, pPage);
142,756,658✔
4012
    return TSDB_CODE_SUCCESS;
142,743,285✔
4013
  } else {
4014
    *value = NULL;
65,330✔
4015
    int32_t vLen;
4016
    int32_t code = pStore->streamStateFuncGet(pHandle->pState, &pPos->streamTupleKey, (void**)(value), &vLen);
65,330✔
4017
    if (TSDB_CODE_SUCCESS != code) {
73,233!
4018
      return code;
×
4019
    }
4020
    return TSDB_CODE_SUCCESS;
73,233✔
4021
  }
4022
}
4023

4024
int32_t loadTupleData(SqlFunctionCtx* pCtx, const STuplePos* pPos, char** value) {
142,703,871✔
4025
  return doLoadTupleData(&pCtx->saveHandle, pPos, pCtx->pStore, value);
142,703,871✔
4026
}
4027

4028
int32_t topBotFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
38,972,012✔
4029
  int32_t code = TSDB_CODE_SUCCESS;
38,972,012✔
4030

4031
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
38,972,012✔
4032
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
38,972,012✔
4033

4034
  int16_t type = pCtx->pExpr->base.resSchema.type;
38,972,377✔
4035
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
38,972,377✔
4036

4037
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
38,972,377✔
4038
  if (NULL == pCol) {
38,969,545!
UNCOV
4039
    return TSDB_CODE_OUT_OF_RANGE;
×
4040
  }
4041

4042
  // todo assign the tag value and the corresponding row data
4043
  int32_t currentRow = pBlock->info.rows;
38,969,545✔
4044
  if (pEntryInfo->numOfRes <= 0) {
38,969,545✔
4045
    colDataSetNULL(pCol, currentRow);
572!
4046
    code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, currentRow);
572✔
4047
    return code;
572✔
4048
  }
4049
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
101,810,546✔
4050
    STopBotResItem* pItem = &pRes->pItems[i];
62,846,730✔
4051
    code = colDataSetVal(pCol, currentRow, (const char*)&pItem->v.i, false);
62,846,730✔
4052
    if (TSDB_CODE_SUCCESS != code) {
62,852,153!
4053
      return code;
×
4054
    }
4055
#ifdef BUF_PAGE_DEBUG
4056
    qDebug("page_finalize i:%d,item:%p,pageId:%d, offset:%d\n", i, pItem, pItem->tuplePos.pageId,
4057
           pItem->tuplePos.offset);
4058
#endif
4059
    code = setSelectivityValue(pCtx, pBlock, &pRes->pItems[i].tuplePos, currentRow);
62,852,153✔
4060
    if (TSDB_CODE_SUCCESS != code) {
62,841,573!
UNCOV
4061
      return code;
×
4062
    }
4063
    currentRow += 1;
62,841,573✔
4064
  }
4065

4066
  return code;
38,963,816✔
4067
}
4068

4069
int32_t addResult(SqlFunctionCtx* pCtx, STopBotResItem* pSourceItem, int16_t type, bool isTopQuery) {
×
4070
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
×
4071
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
×
4072
  STopBotResItem*      pItems = pRes->pItems;
×
4073
  int32_t              code = TSDB_CODE_SUCCESS;
×
4074

4075
  // not full yet
4076
  if (pEntryInfo->numOfRes < pRes->maxSize) {
×
UNCOV
4077
    STopBotResItem* pItem = &pItems[pEntryInfo->numOfRes];
×
UNCOV
4078
    pItem->v = pSourceItem->v;
×
UNCOV
4079
    pItem->uid = pSourceItem->uid;
×
UNCOV
4080
    pItem->tuplePos.pageId = -1;
×
UNCOV
4081
    replaceTupleData(&pItem->tuplePos, &pSourceItem->tuplePos);
×
UNCOV
4082
    pEntryInfo->numOfRes++;
×
UNCOV
4083
    code = taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type,
×
UNCOV
4084
                        topBotResComparFn, !isTopQuery);
×
UNCOV
4085
    if (TSDB_CODE_SUCCESS != code) {
×
UNCOV
4086
      return code;
×
4087
    }
4088
  } else {  // replace the minimum value in the result
UNCOV
4089
    if ((isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && pSourceItem->v.i > pItems[0].v.i) ||
×
UNCOV
4090
                        (IS_UNSIGNED_NUMERIC_TYPE(type) && pSourceItem->v.u > pItems[0].v.u) ||
×
4091
                        (TSDB_DATA_TYPE_FLOAT == type && pSourceItem->v.f > pItems[0].v.f) ||
×
UNCOV
4092
                        (TSDB_DATA_TYPE_DOUBLE == type && pSourceItem->v.d > pItems[0].v.d))) ||
×
UNCOV
4093
        (!isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && pSourceItem->v.i < pItems[0].v.i) ||
×
UNCOV
4094
                         (IS_UNSIGNED_NUMERIC_TYPE(type) && pSourceItem->v.u < pItems[0].v.u) ||
×
UNCOV
4095
                         (TSDB_DATA_TYPE_FLOAT == type && pSourceItem->v.f < pItems[0].v.f) ||
×
UNCOV
4096
                         (TSDB_DATA_TYPE_DOUBLE == type && pSourceItem->v.d < pItems[0].v.d)))) {
×
4097
      // replace the old data and the coresponding tuple data
UNCOV
4098
      STopBotResItem* pItem = &pItems[0];
×
UNCOV
4099
      pItem->v = pSourceItem->v;
×
UNCOV
4100
      pItem->uid = pSourceItem->uid;
×
4101

4102
      // save the data of this tuple by over writing the old data
UNCOV
4103
      replaceTupleData(&pItem->tuplePos, &pSourceItem->tuplePos);
×
UNCOV
4104
      code = taosheapadjust((void*)pItems, sizeof(STopBotResItem), 0, pEntryInfo->numOfRes - 1, (const void*)&type,
×
UNCOV
4105
                            topBotResComparFn, NULL, !isTopQuery);
×
UNCOV
4106
      if (TSDB_CODE_SUCCESS != code) {
×
UNCOV
4107
        return code;
×
4108
      }
4109
    }
4110
  }
UNCOV
4111
  return code;
×
4112
}
4113

4114
int32_t topCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
UNCOV
4115
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4116
  STopBotRes*          pSBuf = getTopBotOutputInfo(pSourceCtx);
×
4117
  int16_t              type = pSBuf->type;
×
4118
  int32_t              code = TSDB_CODE_SUCCESS;
×
4119
  for (int32_t i = 0; i < pSResInfo->numOfRes; i++) {
×
4120
    code = addResult(pDestCtx, pSBuf->pItems + i, type, true);
×
4121
    if (TSDB_CODE_SUCCESS != code) {
×
4122
      return code;
×
4123
    }
4124
  }
4125
  return TSDB_CODE_SUCCESS;
×
4126
}
4127

4128
int32_t bottomCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4129
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
UNCOV
4130
  STopBotRes*          pSBuf = getTopBotOutputInfo(pSourceCtx);
×
UNCOV
4131
  int16_t              type = pSBuf->type;
×
4132
  int32_t              code = TSDB_CODE_SUCCESS;
×
4133
  for (int32_t i = 0; i < pSResInfo->numOfRes; i++) {
×
UNCOV
4134
    code = addResult(pDestCtx, pSBuf->pItems + i, type, false);
×
UNCOV
4135
    if (TSDB_CODE_SUCCESS != code) {
×
UNCOV
4136
      return code;
×
4137
    }
4138
  }
UNCOV
4139
  return TSDB_CODE_SUCCESS;
×
4140
}
4141

4142
int32_t getSpreadInfoSize() { return (int32_t)sizeof(SSpreadInfo); }
1,068,562✔
4143

4144
bool getSpreadFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
107,698✔
4145
  pEnv->calcMemSize = sizeof(SSpreadInfo);
107,698✔
4146
  return true;
107,698✔
4147
}
4148

4149
int32_t spreadFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
5,157,429✔
4150
  if (pResultInfo->initialized) {
5,157,429!
UNCOV
4151
    return TSDB_CODE_SUCCESS;
×
4152
  }
4153
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
5,157,429!
UNCOV
4154
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4155
  }
4156

4157
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
5,157,451✔
4158
  SET_DOUBLE_VAL(&pInfo->min, DBL_MAX);
5,157,451✔
4159
  SET_DOUBLE_VAL(&pInfo->max, -DBL_MAX);
5,157,451✔
4160
  pInfo->hasResult = false;
5,157,451✔
4161
  return TSDB_CODE_SUCCESS;
5,157,451✔
4162
}
4163

4164
int32_t spreadFunction(SqlFunctionCtx* pCtx) {
5,139,477✔
4165
  int32_t numOfElems = 0;
5,139,477✔
4166

4167
  // Only the pre-computing information loaded and actual data does not loaded
4168
  SInputColumnInfoData* pInput = &pCtx->input;
5,139,477✔
4169
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
5,139,477✔
4170
  int32_t               type = pInput->pData[0]->info.type;
5,139,477✔
4171

4172
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
5,139,477✔
4173

4174
  if (pInput->colDataSMAIsSet) {
5,139,477!
UNCOV
4175
    numOfElems = pInput->numOfRows - pAgg->numOfNull;
×
UNCOV
4176
    if (numOfElems == 0) {
×
UNCOV
4177
      goto _spread_over;
×
4178
    }
UNCOV
4179
    double tmin = 0.0, tmax = 0.0;
×
UNCOV
4180
    if (IS_SIGNED_NUMERIC_TYPE(type) || IS_TIMESTAMP_TYPE(type)) {
×
UNCOV
4181
      tmin = (double)GET_INT64_VAL(&pAgg->min);
×
UNCOV
4182
      tmax = (double)GET_INT64_VAL(&pAgg->max);
×
UNCOV
4183
    } else if (IS_FLOAT_TYPE(type)) {
×
UNCOV
4184
      tmin = GET_DOUBLE_VAL(&pAgg->min);
×
UNCOV
4185
      tmax = GET_DOUBLE_VAL(&pAgg->max);
×
UNCOV
4186
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
UNCOV
4187
      tmin = (double)GET_UINT64_VAL(&pAgg->min);
×
4188
      tmax = (double)GET_UINT64_VAL(&pAgg->max);
×
4189
    }
4190

UNCOV
4191
    if (GET_DOUBLE_VAL(&pInfo->min) > tmin) {
×
UNCOV
4192
      SET_DOUBLE_VAL(&pInfo->min, tmin);
×
4193
    }
4194

UNCOV
4195
    if (GET_DOUBLE_VAL(&pInfo->max) < tmax) {
×
UNCOV
4196
      SET_DOUBLE_VAL(&pInfo->max, tmax);
×
4197
    }
4198

4199
  } else {  // computing based on the true data block
4200
    SColumnInfoData* pCol = pInput->pData[0];
5,139,477✔
4201

4202
    int32_t start = pInput->startRowIndex;
5,139,477✔
4203
    // check the valid data one by one
4204
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
26,236,230✔
4205
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
21,096,723✔
4206
        continue;
1,609,601✔
4207
      }
4208

4209
      char* data = colDataGetData(pCol, i);
19,487,122!
4210

4211
      double v = 0;
19,487,122✔
4212
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
19,487,122!
4213
      if (v < GET_DOUBLE_VAL(&pInfo->min)) {
19,487,152✔
4214
        SET_DOUBLE_VAL(&pInfo->min, v);
6,433,023✔
4215
      }
4216

4217
      if (v > GET_DOUBLE_VAL(&pInfo->max)) {
19,487,152✔
4218
        SET_DOUBLE_VAL(&pInfo->max, v);
5,948,477✔
4219
      }
4220

4221
      numOfElems += 1;
19,487,152✔
4222
    }
4223
  }
4224

4225
_spread_over:
5,139,507✔
4226
  // data in the check operation are all null, not output
4227
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
5,139,507✔
4228
  if (numOfElems > 0) {
5,139,507✔
4229
    pInfo->hasResult = true;
5,109,422✔
4230
  }
4231

4232
  return TSDB_CODE_SUCCESS;
5,139,507✔
4233
}
4234

4235
static void spreadTransferInfo(SSpreadInfo* pInput, SSpreadInfo* pOutput) {
1,066,999✔
4236
  pOutput->hasResult = pInput->hasResult;
1,066,999✔
4237
  if (pInput->max > pOutput->max) {
1,066,999✔
4238
    pOutput->max = pInput->max;
1,062,589✔
4239
  }
4240

4241
  if (pInput->min < pOutput->min) {
1,066,999✔
4242
    pOutput->min = pInput->min;
1,062,577✔
4243
  }
4244
}
1,066,999✔
4245

4246
int32_t spreadFunctionMerge(SqlFunctionCtx* pCtx) {
1,063,035✔
4247
  SInputColumnInfoData* pInput = &pCtx->input;
1,063,035✔
4248
  SColumnInfoData*      pCol = pInput->pData[0];
1,063,035✔
4249

4250
  if (IS_NULL_TYPE(pCol->info.type)) {
1,063,035!
UNCOV
4251
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
UNCOV
4252
    return TSDB_CODE_SUCCESS;
×
4253
  }
4254

4255
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
1,063,035!
UNCOV
4256
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4257
  }
4258

4259
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,063,035✔
4260

4261
  int32_t start = pInput->startRowIndex;
1,063,035✔
4262
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
2,130,284✔
4263
    if (colDataIsNull_s(pCol, i)) continue;
2,134,498!
4264
    char*        data = colDataGetData(pCol, i);
1,067,249!
4265
    SSpreadInfo* pInputInfo = (SSpreadInfo*)varDataVal(data);
1,067,249✔
4266
    if (pInputInfo->hasResult) {
1,067,249✔
4267
      spreadTransferInfo(pInputInfo, pInfo);
1,066,998✔
4268
    }
4269
  }
4270

4271
  if (pInfo->hasResult) {
1,063,035✔
4272
    GET_RES_INFO(pCtx)->numOfRes = 1;
1,062,856✔
4273
  }
4274

4275
  return TSDB_CODE_SUCCESS;
1,063,035✔
4276
}
4277

4278
int32_t spreadFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
4,078,579✔
4279
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4,078,579✔
4280
  if (pInfo->hasResult == true) {
4,078,579✔
4281
    SET_DOUBLE_VAL(&pInfo->result, pInfo->max - pInfo->min);
4,048,912✔
4282
  } else {
4283
    GET_RES_INFO(pCtx)->isNullRes = 1;
29,667✔
4284
  }
4285
  return functionFinalize(pCtx, pBlock);
4,078,579✔
4286
}
4287

4288
int32_t spreadPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,067,031✔
4289
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,067,031✔
4290
  SSpreadInfo*         pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,067,031✔
4291
  int32_t              resultBytes = getSpreadInfoSize();
1,067,031✔
4292
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
1,067,030!
4293

4294
  if (NULL == res) {
1,067,031!
UNCOV
4295
    return terrno;
×
4296
  }
4297
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
1,067,031✔
4298
  varDataSetLen(res, resultBytes);
1,067,031✔
4299

4300
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,067,031✔
4301
  int32_t          code = TSDB_CODE_SUCCESS;
1,067,031✔
4302
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,067,031✔
4303
  if (NULL == pCol) {
1,067,031!
UNCOV
4304
    code = terrno;
×
UNCOV
4305
    goto _exit;
×
4306
  }
4307

4308
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
1,067,031✔
4309
  if (TSDB_CODE_SUCCESS != code) {
1,067,030!
UNCOV
4310
    goto _exit;
×
4311
  }
4312

4313
_exit:
1,067,030✔
4314
  taosMemoryFree(res);
1,067,030!
4315
  return code;
1,067,030✔
4316
}
4317

4318
int32_t spreadCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
1✔
4319
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
1✔
4320
  SSpreadInfo*         pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
1✔
4321

4322
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
1✔
4323
  SSpreadInfo*         pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
1✔
4324
  spreadTransferInfo(pSBuf, pDBuf);
1✔
4325
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
1✔
4326
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
1✔
4327
  return TSDB_CODE_SUCCESS;
1✔
4328
}
4329

UNCOV
4330
int32_t getElapsedInfoSize() { return (int32_t)sizeof(SElapsedInfo); }
×
4331

4332
bool getElapsedFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
103,113✔
4333
  pEnv->calcMemSize = sizeof(SElapsedInfo);
103,113✔
4334
  return true;
103,113✔
4335
}
4336

4337
int32_t elapsedFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
7,092,201✔
4338
  if (pResultInfo->initialized) {
7,092,201!
UNCOV
4339
    return TSDB_CODE_SUCCESS;
×
4340
  }
4341
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
7,092,201!
UNCOV
4342
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4343
  }
4344

4345
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
7,092,205✔
4346
  pInfo->result = 0;
7,092,205✔
4347
  pInfo->min = TSKEY_MAX;
7,092,205✔
4348
  pInfo->max = 0;
7,092,205✔
4349

4350
  if (pCtx->numOfParams > 1) {
7,092,205✔
4351
    pInfo->timeUnit = pCtx->param[1].param.i;
7,074,470✔
4352
  } else {
4353
    pInfo->timeUnit = 1;
17,735✔
4354
  }
4355

4356
  return TSDB_CODE_SUCCESS;
7,092,205✔
4357
}
4358

4359
int32_t elapsedFunction(SqlFunctionCtx* pCtx) {
7,092,244✔
4360
  int32_t numOfElems = 0;
7,092,244✔
4361

4362
  // Only the pre-computing information loaded and actual data does not loaded
4363
  SInputColumnInfoData* pInput = &pCtx->input;
7,092,244✔
4364
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
7,092,244✔
4365

4366
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
7,092,244✔
4367

4368
  numOfElems = pInput->numOfRows;  // since this is the primary timestamp, no need to exclude NULL values
7,092,244✔
4369
  if (numOfElems == 0) {
7,092,244✔
4370
    // for stream
4371
    if (pCtx->end.key != INT64_MIN) {
52!
4372
      pInfo->max = pCtx->end.key + 1;
52✔
4373
    }
4374
    goto _elapsed_over;
52✔
4375
  }
4376

4377
  if (pInput->colDataSMAIsSet) {
7,092,192!
UNCOV
4378
    if (pInfo->min == TSKEY_MAX) {
×
4379
      pInfo->min = GET_INT64_VAL(&pAgg->min);
×
4380
      pInfo->max = GET_INT64_VAL(&pAgg->max);
×
4381
    } else {
4382
      if (pCtx->order == TSDB_ORDER_ASC) {
×
UNCOV
4383
        pInfo->max = GET_INT64_VAL(&pAgg->max);
×
4384
      } else {
4385
        pInfo->min = GET_INT64_VAL(&pAgg->min);
×
4386
      }
4387
    }
4388
  } else {  // computing based on the true data block
4389
    if (0 == pInput->numOfRows) {
7,092,192!
4390
      if (pCtx->order == TSDB_ORDER_DESC) {
×
4391
        if (pCtx->end.key != INT64_MIN) {
×
4392
          pInfo->min = pCtx->end.key;
×
4393
        }
4394
      } else {
UNCOV
4395
        if (pCtx->end.key != INT64_MIN) {
×
UNCOV
4396
          pInfo->max = pCtx->end.key + 1;
×
4397
        }
4398
      }
4399
      goto _elapsed_over;
×
4400
    }
4401

4402
    SColumnInfoData* pCol = pInput->pData[0];
7,092,192✔
4403

4404
    int32_t start = pInput->startRowIndex;
7,092,192✔
4405
    TSKEY*  ptsList = (int64_t*)colDataGetData(pCol, 0);
7,092,192!
4406
    if (pCtx->order == TSDB_ORDER_DESC) {
7,092,192✔
4407
      if (pCtx->start.key == INT64_MIN) {
683!
4408
        pInfo->max = (pInfo->max < ptsList[start]) ? ptsList[start] : pInfo->max;
683✔
4409
      } else {
UNCOV
4410
        pInfo->max = pCtx->start.key + 1;
×
4411
      }
4412

4413
      if (pCtx->end.key == INT64_MIN) {
683!
4414
        pInfo->min =
683✔
4415
            (pInfo->min > ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->min;
683✔
4416
      } else {
UNCOV
4417
        pInfo->min = pCtx->end.key;
×
4418
      }
4419
    } else {
4420
      if (pCtx->start.key == INT64_MIN) {
7,091,509✔
4421
        pInfo->min = (pInfo->min > ptsList[start]) ? ptsList[start] : pInfo->min;
4,040,342✔
4422
      } else {
4423
        pInfo->min = pCtx->start.key;
3,051,167✔
4424
      }
4425

4426
      if (pCtx->end.key == INT64_MIN) {
7,091,509✔
4427
        pInfo->max =
3,860,202✔
4428
            (pInfo->max < ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->max;
3,860,202✔
4429
      } else {
4430
        pInfo->max = pCtx->end.key + 1;
3,231,307✔
4431
      }
4432
    }
4433
  }
4434

4435
_elapsed_over:
7,092,244✔
4436
  // data in the check operation are all null, not output
4437
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
7,092,244✔
4438

4439
  return TSDB_CODE_SUCCESS;
7,092,244✔
4440
}
4441

UNCOV
4442
static void elapsedTransferInfo(SElapsedInfo* pInput, SElapsedInfo* pOutput) {
×
4443
  pOutput->timeUnit = pInput->timeUnit;
×
4444
  if (pOutput->min > pInput->min) {
×
4445
    pOutput->min = pInput->min;
×
4446
  }
4447

4448
  if (pOutput->max < pInput->max) {
×
4449
    pOutput->max = pInput->max;
×
4450
  }
UNCOV
4451
}
×
4452

4453
int32_t elapsedFunctionMerge(SqlFunctionCtx* pCtx) {
×
UNCOV
4454
  SInputColumnInfoData* pInput = &pCtx->input;
×
4455
  SColumnInfoData*      pCol = pInput->pData[0];
×
4456
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
×
4457
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4458
  }
4459

UNCOV
4460
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
4461

UNCOV
4462
  int32_t start = pInput->startRowIndex;
×
4463

UNCOV
4464
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
×
UNCOV
4465
    char*         data = colDataGetData(pCol, i);
×
UNCOV
4466
    SElapsedInfo* pInputInfo = (SElapsedInfo*)varDataVal(data);
×
UNCOV
4467
    elapsedTransferInfo(pInputInfo, pInfo);
×
4468
  }
4469

UNCOV
4470
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
×
UNCOV
4471
  return TSDB_CODE_SUCCESS;
×
4472
}
4473

4474
int32_t elapsedFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
7,088,492✔
4475
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
7,088,492✔
4476
  double        result = (double)pInfo->max - (double)pInfo->min;
7,088,492✔
4477
  result = (result >= 0) ? result : -result;
7,088,492✔
4478
  pInfo->result = result / pInfo->timeUnit;
7,088,492✔
4479
  return functionFinalize(pCtx, pBlock);
7,088,492✔
4480
}
4481

UNCOV
4482
int32_t elapsedPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
UNCOV
4483
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
×
UNCOV
4484
  SElapsedInfo*        pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
UNCOV
4485
  int32_t              resultBytes = getElapsedInfoSize();
×
UNCOV
4486
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
×
4487

UNCOV
4488
  if (NULL == res) {
×
UNCOV
4489
    return terrno;
×
4490
  }
UNCOV
4491
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
×
UNCOV
4492
  varDataSetLen(res, resultBytes);
×
4493

4494
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
×
UNCOV
4495
  int32_t          code = TSDB_CODE_SUCCESS;
×
UNCOV
4496
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
×
UNCOV
4497
  if (NULL == pCol) {
×
UNCOV
4498
    code = terrno;
×
UNCOV
4499
    goto _exit;
×
4500
  }
4501

UNCOV
4502
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
×
UNCOV
4503
  if (TSDB_CODE_SUCCESS != code) {
×
4504
    goto _exit;
×
4505
  }
UNCOV
4506
_exit:
×
UNCOV
4507
  taosMemoryFree(res);
×
UNCOV
4508
  return code;
×
4509
}
4510

UNCOV
4511
int32_t elapsedCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
UNCOV
4512
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
UNCOV
4513
  SElapsedInfo*        pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
4514

4515
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4516
  SElapsedInfo*        pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
4517

UNCOV
4518
  elapsedTransferInfo(pSBuf, pDBuf);
×
UNCOV
4519
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
UNCOV
4520
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
UNCOV
4521
  return TSDB_CODE_SUCCESS;
×
4522
}
4523

4524
int32_t getHistogramInfoSize() {
1,745,433✔
4525
  return (int32_t)sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
1,745,433✔
4526
}
4527

4528
bool getHistogramFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
112,080✔
4529
  pEnv->calcMemSize = sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
112,080✔
4530
  return true;
112,080✔
4531
}
4532

4533
static int8_t getHistogramBinType(char* binTypeStr) {
11,743,359✔
4534
  int8_t binType;
4535
  if (strcasecmp(binTypeStr, "user_input") == 0) {
11,743,359✔
4536
    binType = USER_INPUT_BIN;
4,066✔
4537
  } else if (strcasecmp(binTypeStr, "linear_bin") == 0) {
11,739,293✔
4538
    binType = LINEAR_BIN;
686✔
4539
  } else if (strcasecmp(binTypeStr, "log_bin") == 0) {
11,738,607!
4540
    binType = LOG_BIN;
11,738,733✔
4541
  } else {
UNCOV
4542
    binType = UNKNOWN_BIN;
×
4543
  }
4544

4545
  return binType;
11,743,359✔
4546
}
4547

4548
static int32_t getHistogramBinDesc(SHistoFuncInfo* pInfo, char* binDescStr, int8_t binType, bool normalized) {
11,743,498✔
4549
  cJSON*  binDesc = cJSON_Parse(binDescStr);
11,743,498✔
4550
  int32_t numOfBins;
4551
  double* intervals;
4552
  if (cJSON_IsObject(binDesc)) { /* linaer/log bins */
11,743,532✔
4553
    int32_t numOfParams = cJSON_GetArraySize(binDesc);
11,739,445✔
4554
    int32_t startIndex;
4555
    if (numOfParams != 4) {
11,739,387!
UNCOV
4556
      cJSON_Delete(binDesc);
×
UNCOV
4557
      return TSDB_CODE_FAILED;
×
4558
    }
4559

4560
    cJSON* start = cJSON_GetObjectItem(binDesc, "start");
11,739,387✔
4561
    cJSON* factor = cJSON_GetObjectItem(binDesc, "factor");
11,739,457✔
4562
    cJSON* width = cJSON_GetObjectItem(binDesc, "width");
11,739,458✔
4563
    cJSON* count = cJSON_GetObjectItem(binDesc, "count");
11,739,055✔
4564
    cJSON* infinity = cJSON_GetObjectItem(binDesc, "infinity");
11,739,383✔
4565

4566
    if (!cJSON_IsNumber(start) || !cJSON_IsNumber(count) || !cJSON_IsBool(infinity)) {
11,739,451!
4567
      cJSON_Delete(binDesc);
×
UNCOV
4568
      return TSDB_CODE_FAILED;
×
4569
    }
4570

4571
    if (count->valueint <= 0 || count->valueint > 1000) {  // limit count to 1000
11,739,415!
4572
      cJSON_Delete(binDesc);
27✔
4573
      return TSDB_CODE_FAILED;
×
4574
    }
4575

4576
    if (isinf(start->valuedouble) || (width != NULL && isinf(width->valuedouble)) ||
11,739,388!
4577
        (factor != NULL && isinf(factor->valuedouble)) || (count != NULL && isinf(count->valuedouble))) {
11,739,388!
UNCOV
4578
      cJSON_Delete(binDesc);
×
UNCOV
4579
      return TSDB_CODE_FAILED;
×
4580
    }
4581

4582
    int32_t counter = (int32_t)count->valueint;
11,739,388✔
4583
    if (infinity->valueint == false) {
11,739,388✔
4584
      startIndex = 0;
11,734,056✔
4585
      numOfBins = counter + 1;
11,734,056✔
4586
    } else {
4587
      startIndex = 1;
5,332✔
4588
      numOfBins = counter + 3;
5,332✔
4589
    }
4590

4591
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
11,739,388!
4592
    if (NULL == intervals) {
11,739,446!
UNCOV
4593
      cJSON_Delete(binDesc);
×
UNCOV
4594
      qError("histogram function out of memory");
×
UNCOV
4595
      return terrno;
×
4596
    }
4597
    if (cJSON_IsNumber(width) && factor == NULL && binType == LINEAR_BIN) {
11,739,446!
4598
      // linear bin process
4599
      if (width->valuedouble == 0) {
686!
UNCOV
4600
        taosMemoryFree(intervals);
×
UNCOV
4601
        cJSON_Delete(binDesc);
×
4602
        return TSDB_CODE_FAILED;
×
4603
      }
4604
      for (int i = 0; i < counter + 1; ++i) {
2,498✔
4605
        intervals[startIndex] = start->valuedouble + i * width->valuedouble;
1,812✔
4606
        if (isinf(intervals[startIndex])) {
1,812!
UNCOV
4607
          taosMemoryFree(intervals);
×
UNCOV
4608
          cJSON_Delete(binDesc);
×
UNCOV
4609
          return TSDB_CODE_FAILED;
×
4610
        }
4611
        startIndex++;
1,812✔
4612
      }
4613
    } else if (cJSON_IsNumber(factor) && width == NULL && binType == LOG_BIN) {
11,738,750!
4614
      // log bin process
4615
      if (start->valuedouble == 0) {
11,738,714!
4616
        taosMemoryFree(intervals);
×
4617
        cJSON_Delete(binDesc);
×
UNCOV
4618
        return TSDB_CODE_FAILED;
×
4619
      }
4620
      if (factor->valuedouble < 0 || factor->valuedouble == 0 || factor->valuedouble == 1) {
11,738,714!
UNCOV
4621
        taosMemoryFree(intervals);
×
UNCOV
4622
        cJSON_Delete(binDesc);
×
4623
        return TSDB_CODE_FAILED;
×
4624
      }
4625
      for (int i = 0; i < counter + 1; ++i) {
82,164,634✔
4626
        intervals[startIndex] = start->valuedouble * pow(factor->valuedouble, i * 1.0);
70,425,911✔
4627
        if (isinf(intervals[startIndex])) {
70,425,911!
UNCOV
4628
          taosMemoryFree(intervals);
×
UNCOV
4629
          cJSON_Delete(binDesc);
×
UNCOV
4630
          return TSDB_CODE_FAILED;
×
4631
        }
4632
        startIndex++;
70,425,911✔
4633
      }
4634
    } else {
UNCOV
4635
      taosMemoryFree(intervals);
×
UNCOV
4636
      cJSON_Delete(binDesc);
×
UNCOV
4637
      return TSDB_CODE_FAILED;
×
4638
    }
4639

4640
    if (infinity->valueint == true) {
11,739,409✔
4641
      intervals[0] = -INFINITY;
5,387✔
4642
      intervals[numOfBins - 1] = INFINITY;
5,387✔
4643
      // in case of desc bin orders, -inf/inf should be swapped
4644
      if (numOfBins < 4) {
5,387!
UNCOV
4645
        return TSDB_CODE_FAILED;
×
4646
      }
4647
      if (intervals[1] > intervals[numOfBins - 2]) {
5,387✔
4648
        TSWAP(intervals[0], intervals[numOfBins - 1]);
5,277✔
4649
      }
4650
    }
4651
  } else if (cJSON_IsArray(binDesc)) { /* user input bins */
4,068!
4652
    if (binType != USER_INPUT_BIN) {
4,068!
UNCOV
4653
      cJSON_Delete(binDesc);
×
UNCOV
4654
      return TSDB_CODE_FAILED;
×
4655
    }
4656
    numOfBins = cJSON_GetArraySize(binDesc);
4,068✔
4657
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
4,068!
4658
    if (NULL == intervals) {
4,068!
UNCOV
4659
      cJSON_Delete(binDesc);
×
UNCOV
4660
      qError("histogram function out of memory");
×
UNCOV
4661
      return terrno;
×
4662
    }
4663
    cJSON* bin = binDesc->child;
4,068✔
4664
    if (bin == NULL) {
4,068!
UNCOV
4665
      taosMemoryFree(intervals);
×
4666
      cJSON_Delete(binDesc);
×
UNCOV
4667
      return TSDB_CODE_FAILED;
×
4668
    }
4669
    int i = 0;
4,068✔
4670
    while (bin) {
18,035✔
4671
      intervals[i] = bin->valuedouble;
13,967✔
4672
      if (!cJSON_IsNumber(bin)) {
13,967!
UNCOV
4673
        taosMemoryFree(intervals);
×
UNCOV
4674
        cJSON_Delete(binDesc);
×
4675
        return TSDB_CODE_FAILED;
×
4676
      }
4677
      if (i != 0 && intervals[i] <= intervals[i - 1]) {
13,967!
UNCOV
4678
        taosMemoryFree(intervals);
×
UNCOV
4679
        cJSON_Delete(binDesc);
×
UNCOV
4680
        return TSDB_CODE_FAILED;
×
4681
      }
4682
      bin = bin->next;
13,967✔
4683
      i++;
13,967✔
4684
    }
4685
  } else {
UNCOV
4686
    cJSON_Delete(binDesc);
×
UNCOV
4687
    return TSDB_CODE_FAILED;
×
4688
  }
4689

4690
  pInfo->numOfBins = numOfBins - 1;
11,743,477✔
4691
  pInfo->normalized = normalized;
11,743,477✔
4692
  for (int32_t i = 0; i < pInfo->numOfBins; ++i) {
70,455,536✔
4693
    pInfo->bins[i].lower = intervals[i] < intervals[i + 1] ? intervals[i] : intervals[i + 1];
58,712,059✔
4694
    pInfo->bins[i].upper = intervals[i + 1] > intervals[i] ? intervals[i + 1] : intervals[i];
58,712,059✔
4695
    pInfo->bins[i].count = 0;
58,712,059✔
4696
  }
4697

4698
  taosMemoryFree(intervals);
11,743,477!
4699
  cJSON_Delete(binDesc);
11,743,574✔
4700

4701
  return TSDB_CODE_SUCCESS;
11,743,580✔
4702
}
4703

4704
int32_t histogramFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
11,743,356✔
4705
  if (pResultInfo->initialized) {
11,743,356!
UNCOV
4706
    return TSDB_CODE_SUCCESS;
×
4707
  }
4708
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
11,743,356!
UNCOV
4709
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4710
  }
4711

4712
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
11,743,384✔
4713
  pInfo->numOfBins = 0;
11,743,384✔
4714
  pInfo->totalCount = 0;
11,743,384✔
4715
  pInfo->normalized = 0;
11,743,384✔
4716

4717
  char* binTypeStr = taosStrndup(varDataVal(pCtx->param[1].param.pz), varDataLen(pCtx->param[1].param.pz));
11,743,384!
4718
  if (binTypeStr == NULL) {
11,743,397!
UNCOV
4719
    return terrno;
×
4720
  }
4721
  int8_t binType = getHistogramBinType(binTypeStr);
11,743,397✔
4722
  taosMemoryFree(binTypeStr);
11,743,398!
4723

4724
  if (binType == UNKNOWN_BIN) {
11,743,309!
UNCOV
4725
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
4726
  }
4727
  char* binDesc = taosStrndup(varDataVal(pCtx->param[2].param.pz), varDataLen(pCtx->param[2].param.pz));
11,743,309!
4728
  if (binDesc == NULL) {
11,743,312!
UNCOV
4729
    return terrno;
×
4730
  }
4731
  int64_t normalized = pCtx->param[3].param.i;
11,743,312✔
4732
  if (normalized != 0 && normalized != 1) {
11,743,312!
UNCOV
4733
    taosMemoryFree(binDesc);
×
UNCOV
4734
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
4735
  }
4736
  int32_t code = getHistogramBinDesc(pInfo, binDesc, binType, (bool)normalized);
11,743,312✔
4737
  if (TSDB_CODE_SUCCESS != code) {
11,743,579!
UNCOV
4738
    taosMemoryFree(binDesc);
×
UNCOV
4739
    return code;
×
4740
  }
4741
  taosMemoryFree(binDesc);
11,743,579!
4742

4743
  return TSDB_CODE_SUCCESS;
11,743,543✔
4744
}
4745

4746
static int32_t histogramFunctionImpl(SqlFunctionCtx* pCtx, bool isPartial) {
13,457,067✔
4747
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
13,457,067✔
4748

4749
  SInputColumnInfoData* pInput = &pCtx->input;
13,457,067✔
4750
  SColumnInfoData*      pCol = pInput->pData[0];
13,457,067✔
4751

4752
  int32_t type = pInput->pData[0]->info.type;
13,457,067✔
4753

4754
  int32_t start = pInput->startRowIndex;
13,457,067✔
4755
  int32_t numOfRows = pInput->numOfRows;
13,457,067✔
4756

4757
  int32_t numOfElems = 0;
13,457,067✔
4758
  for (int32_t i = start; i < numOfRows + start; ++i) {
49,419,542✔
4759
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
35,962,465✔
4760
      continue;
687,958✔
4761
    }
4762

4763
    numOfElems++;
35,274,507✔
4764

4765
    char*  data = colDataGetData(pCol, i);
35,274,507!
4766
    double v;
4767
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
35,274,507!
4768

4769
    for (int32_t k = 0; k < pInfo->numOfBins; ++k) {
205,883,107✔
4770
      if (v > pInfo->bins[k].lower && v <= pInfo->bins[k].upper) {
172,189,029✔
4771
        pInfo->bins[k].count++;
1,580,439✔
4772
        pInfo->totalCount++;
1,580,439✔
4773
        break;
1,580,439✔
4774
      }
4775
    }
4776
  }
4777

4778
  if (!isPartial) {
13,457,077✔
4779
    GET_RES_INFO(pCtx)->numOfRes = pInfo->numOfBins;
10,018,073✔
4780
  } else {
4781
    GET_RES_INFO(pCtx)->numOfRes = 1;
3,439,004✔
4782
  }
4783
  return TSDB_CODE_SUCCESS;
13,457,077✔
4784
}
4785

4786
int32_t histogramFunction(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, false); }
10,018,105✔
4787

4788
int32_t histogramFunctionPartial(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, true); }
3,439,019✔
4789

4790
static void histogramTransferInfo(SHistoFuncInfo* pInput, SHistoFuncInfo* pOutput) {
1,716,844✔
4791
  pOutput->normalized = pInput->normalized;
1,716,844✔
4792
  pOutput->numOfBins = pInput->numOfBins;
1,716,844✔
4793
  pOutput->totalCount += pInput->totalCount;
1,716,844✔
4794
  for (int32_t k = 0; k < pOutput->numOfBins; ++k) {
10,300,371✔
4795
    pOutput->bins[k].lower = pInput->bins[k].lower;
8,583,527✔
4796
    pOutput->bins[k].upper = pInput->bins[k].upper;
8,583,527✔
4797
    pOutput->bins[k].count += pInput->bins[k].count;
8,583,527✔
4798
  }
4799
}
1,716,844✔
4800

4801
int32_t histogramFunctionMerge(SqlFunctionCtx* pCtx) {
1,716,844✔
4802
  SInputColumnInfoData* pInput = &pCtx->input;
1,716,844✔
4803
  SColumnInfoData*      pCol = pInput->pData[0];
1,716,844✔
4804
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
1,716,844!
UNCOV
4805
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4806
  }
4807

4808
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,716,844✔
4809

4810
  int32_t start = pInput->startRowIndex;
1,716,844✔
4811

4812
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
3,433,688✔
4813
    char*           data = colDataGetData(pCol, i);
1,716,844!
4814
    SHistoFuncInfo* pInputInfo = (SHistoFuncInfo*)varDataVal(data);
1,716,844✔
4815
    histogramTransferInfo(pInputInfo, pInfo);
1,716,844✔
4816
  }
4817

4818
  SET_VAL(GET_RES_INFO(pCtx), pInfo->numOfBins, pInfo->numOfBins);
1,716,844!
4819
  return TSDB_CODE_SUCCESS;
1,716,844✔
4820
}
4821

4822
int32_t histogramFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
11,672,311✔
4823
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
11,672,311✔
4824
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
11,672,311✔
4825
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
11,672,311✔
4826
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
11,672,311✔
4827
  int32_t              code = TSDB_CODE_SUCCESS;
11,672,209✔
4828

4829
  int32_t currentRow = pBlock->info.rows;
11,672,209✔
4830
  if (NULL == pCol) {
11,672,209!
4831
    return TSDB_CODE_OUT_OF_RANGE;
×
4832
  }
4833

4834
  if (pInfo->normalized) {
11,672,209✔
4835
    for (int32_t k = 0; k < pResInfo->numOfRes; ++k) {
69,977,750✔
4836
      if (pInfo->totalCount != 0) {
58,313,257✔
4837
        pInfo->bins[k].percentage = pInfo->bins[k].count / (double)pInfo->totalCount;
14,865✔
4838
      } else {
4839
        pInfo->bins[k].percentage = 0;
58,298,392✔
4840
      }
4841
    }
4842
  }
4843

4844
  for (int32_t i = 0; i < pResInfo->numOfRes; ++i) {
70,018,497✔
4845
    int32_t len;
4846
    char    buf[512] = {0};
58,355,511✔
4847
    if (!pInfo->normalized) {
58,355,511✔
4848
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
43,135✔
4849
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%" PRId64 "}", pInfo->bins[i].lower,
4850
                      pInfo->bins[i].upper, pInfo->bins[i].count);
4851
    } else {
4852
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
58,312,376✔
4853
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%lf}", pInfo->bins[i].lower, pInfo->bins[i].upper,
4854
                      pInfo->bins[i].percentage);
4855
    }
4856
    varDataSetLen(buf, len);
58,354,769✔
4857
    code = colDataSetVal(pCol, currentRow, buf, false);
58,354,769✔
4858
    if (TSDB_CODE_SUCCESS != code) {
58,346,288!
UNCOV
4859
      return code;
×
4860
    }
4861
    currentRow++;
58,346,288✔
4862
  }
4863

4864
  return code;
11,662,986✔
4865
}
4866

4867
int32_t histogramPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,739,266✔
4868
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,739,266✔
4869
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,739,266✔
4870
  int32_t              resultBytes = getHistogramInfoSize();
1,739,266✔
4871
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
1,739,266!
4872

4873
  if (NULL == res) {
1,739,266!
UNCOV
4874
    return terrno;
×
4875
  }
4876
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
1,739,266✔
4877
  varDataSetLen(res, resultBytes);
1,739,266✔
4878

4879
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,739,266✔
4880
  int32_t          code = TSDB_CODE_SUCCESS;
1,739,266✔
4881
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,739,266✔
4882
  if (NULL == pCol) {
1,739,266!
UNCOV
4883
    code = terrno;
×
UNCOV
4884
    goto _exit;
×
4885
  }
4886
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
1,739,266✔
4887

4888
_exit:
1,739,266✔
4889
  taosMemoryFree(res);
1,739,266!
4890
  return code;
1,739,266✔
4891
}
4892

4893
int32_t histogramCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4894
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
4895
  SHistoFuncInfo*      pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
4896

4897
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
UNCOV
4898
  SHistoFuncInfo*      pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
4899

UNCOV
4900
  histogramTransferInfo(pSBuf, pDBuf);
×
UNCOV
4901
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
UNCOV
4902
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
UNCOV
4903
  return TSDB_CODE_SUCCESS;
×
4904
}
4905

4906
int32_t getHLLInfoSize() { return (int32_t)sizeof(SHLLInfo); }
10,453✔
4907

4908
bool getHLLFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
68,629✔
4909
  pEnv->calcMemSize = sizeof(SHLLInfo);
68,629✔
4910
  return true;
68,629✔
4911
}
4912

4913
static uint8_t hllCountNum(void* data, int32_t bytes, int32_t* buk) {
3,477,019✔
4914
  uint64_t hash = MurmurHash3_64(data, bytes);
3,477,019✔
4915
  int32_t  index = hash & HLL_BUCKET_MASK;
3,475,999✔
4916
  hash >>= HLL_BUCKET_BITS;
3,475,999✔
4917
  hash |= ((uint64_t)1 << HLL_DATA_BITS);
3,475,999✔
4918
  uint64_t bit = 1;
3,475,999✔
4919
  uint8_t  count = 1;
3,475,999✔
4920
  while ((hash & bit) == 0) {
7,422,352✔
4921
    count++;
3,946,353✔
4922
    bit <<= 1;
3,946,353✔
4923
  }
4924
  *buk = index;
3,475,999✔
4925
  return count;
3,475,999✔
4926
}
4927

4928
static void hllBucketHisto(uint8_t* buckets, int32_t* bucketHisto) {
252,973✔
4929
  uint64_t* word = (uint64_t*)buckets;
252,973✔
4930
  uint8_t*  bytes;
4931

4932
  for (int32_t j = 0; j < HLL_BUCKETS >> 3; j++) {
511,570,836✔
4933
    if (*word == 0) {
511,317,863✔
4934
      bucketHisto[0] += 8;
510,610,565✔
4935
    } else {
4936
      bytes = (uint8_t*)word;
707,298✔
4937
      bucketHisto[bytes[0]]++;
707,298✔
4938
      bucketHisto[bytes[1]]++;
707,298✔
4939
      bucketHisto[bytes[2]]++;
707,298✔
4940
      bucketHisto[bytes[3]]++;
707,298✔
4941
      bucketHisto[bytes[4]]++;
707,298✔
4942
      bucketHisto[bytes[5]]++;
707,298✔
4943
      bucketHisto[bytes[6]]++;
707,298✔
4944
      bucketHisto[bytes[7]]++;
707,298✔
4945
    }
4946
    word++;
511,317,863✔
4947
  }
4948
}
252,973✔
4949
static double hllTau(double x) {
252,972✔
4950
  if (x == 0. || x == 1.) return 0.;
252,972!
4951
  double zPrime;
UNCOV
4952
  double y = 1.0;
×
UNCOV
4953
  double z = 1 - x;
×
4954
  do {
UNCOV
4955
    x = sqrt(x);
×
UNCOV
4956
    zPrime = z;
×
UNCOV
4957
    y *= 0.5;
×
UNCOV
4958
    z -= pow(1 - x, 2) * y;
×
UNCOV
4959
  } while (zPrime != z);
×
UNCOV
4960
  return z / 3;
×
4961
}
4962

4963
static double hllSigma(double x) {
252,977✔
4964
  if (x == 1.0) return INFINITY;
252,977✔
4965
  double zPrime;
4966
  double y = 1;
223,512✔
4967
  double z = x;
223,512✔
4968
  do {
4969
    x *= x;
4,383,303✔
4970
    zPrime = z;
4,383,303✔
4971
    z += x * y;
4,383,303✔
4972
    y += y;
4,383,303✔
4973
  } while (zPrime != z);
4,383,303✔
4974
  return z;
223,512✔
4975
}
4976

4977
// estimate the cardinality, the algorithm refer this paper: "New cardinality estimation algorithms for HyperLogLog
4978
// sketches"
4979
static uint64_t hllCountCnt(uint8_t* buckets) {
252,933✔
4980
  double  m = HLL_BUCKETS;
252,933✔
4981
  int32_t buckethisto[64] = {0};
252,933✔
4982
  hllBucketHisto(buckets, buckethisto);
252,933✔
4983

4984
  double z = m * hllTau((m - buckethisto[HLL_DATA_BITS + 1]) / (double)m);
252,975✔
4985
  for (int j = HLL_DATA_BITS; j >= 1; --j) {
12,897,534✔
4986
    z += buckethisto[j];
12,644,556✔
4987
    z *= 0.5;
12,644,556✔
4988
  }
4989

4990
  z += m * hllSigma(buckethisto[0] / (double)m);
252,978✔
4991
  double E = (double)llroundl(HLL_ALPHA_INF * m * m / z);
252,981✔
4992

4993
  return (uint64_t)E;
252,981✔
4994
}
4995

4996
int32_t hllFunction(SqlFunctionCtx* pCtx) {
277,774✔
4997
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
277,774✔
4998

4999
  SInputColumnInfoData* pInput = &pCtx->input;
277,774✔
5000
  SColumnInfoData*      pCol = pInput->pData[0];
277,774✔
5001

5002
  int32_t type = pCol->info.type;
277,774✔
5003
  int32_t bytes = pCol->info.bytes;
277,774✔
5004

5005
  int32_t start = pInput->startRowIndex;
277,774✔
5006
  int32_t numOfRows = pInput->numOfRows;
277,774✔
5007

5008
  int32_t numOfElems = 0;
277,774✔
5009
  if (IS_NULL_TYPE(type)) {
277,774✔
5010
    goto _hll_over;
1,562✔
5011
  }
5012

5013
  for (int32_t i = start; i < numOfRows + start; ++i) {
4,890,460✔
5014
    if (pCol->hasNull && colDataIsNull_s(pCol, i)) {
6,553,413!
5015
      continue;
1,137,347✔
5016
    }
5017

5018
    numOfElems++;
3,478,264✔
5019

5020
    char* data = colDataGetData(pCol, i);
3,478,264!
5021
    if (IS_VAR_DATA_TYPE(type)) {
3,478,264!
5022
      bytes = varDataLen(data);
1,029,616✔
5023
      data = varDataVal(data);
1,029,616✔
5024
    }
5025

5026
    int32_t index = 0;
3,478,264✔
5027
    uint8_t count = hllCountNum(data, bytes, &index);
3,478,264✔
5028
    uint8_t oldcount = pInfo->buckets[index];
3,476,901✔
5029
    if (count > oldcount) {
3,476,901✔
5030
      pInfo->buckets[index] = count;
726,335✔
5031
    }
5032
  }
5033

5034
_hll_over:
274,849✔
5035
  pInfo->totalCount += numOfElems;
276,411✔
5036

5037
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
276,411✔
5038
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
1,851✔
5039
  } else {
5040
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
274,560✔
5041
  }
5042

5043
  return TSDB_CODE_SUCCESS;
276,411✔
5044
}
5045

5046
static void hllTransferInfo(SHLLInfo* pInput, SHLLInfo* pOutput) {
10,743✔
5047
  for (int32_t k = 0; k < HLL_BUCKETS; ++k) {
171,812,899✔
5048
    if (pOutput->buckets[k] < pInput->buckets[k]) {
171,802,156✔
5049
      pOutput->buckets[k] = pInput->buckets[k];
113,791✔
5050
    }
5051
  }
5052
  pOutput->totalCount += pInput->totalCount;
10,743✔
5053
}
10,743✔
5054

5055
int32_t hllFunctionMerge(SqlFunctionCtx* pCtx) {
10,656✔
5056
  SInputColumnInfoData* pInput = &pCtx->input;
10,656✔
5057
  SColumnInfoData*      pCol = pInput->pData[0];
10,656✔
5058

5059
  if (IS_NULL_TYPE(pCol->info.type)) {
10,656!
UNCOV
5060
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
UNCOV
5061
    return TSDB_CODE_SUCCESS;
×
5062
  }
5063

5064
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
10,656!
UNCOV
5065
    return TSDB_CODE_SUCCESS;
×
5066
  }
5067

5068
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
10,656✔
5069

5070
  int32_t start = pInput->startRowIndex;
10,656✔
5071

5072
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
21,398✔
5073
    if (colDataIsNull_s(pCol, i)) continue;
21,484!
5074
    char*     data = colDataGetData(pCol, i);
10,742!
5075
    SHLLInfo* pInputInfo = (SHLLInfo*)varDataVal(data);
10,742✔
5076
    hllTransferInfo(pInputInfo, pInfo);
10,742✔
5077
  }
5078

5079
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
10,656✔
5080
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
3✔
5081
  } else {
5082
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
10,653✔
5083
  }
5084

5085
  return TSDB_CODE_SUCCESS;
10,656✔
5086
}
5087

5088
int32_t hllFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
252,933✔
5089
  SResultRowEntryInfo* pInfo = GET_RES_INFO(pCtx);
252,933✔
5090

5091
  SHLLInfo* pHllInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
252,933✔
5092
  pHllInfo->result = hllCountCnt(pHllInfo->buckets);
252,933✔
5093
  if (tsCountAlwaysReturnValue && pHllInfo->result == 0) {
252,987✔
5094
    pInfo->numOfRes = 1;
27,639✔
5095
  }
5096

5097
  return functionFinalize(pCtx, pBlock);
252,987✔
5098
}
5099

5100
int32_t hllPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
10,452✔
5101
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
10,452✔
5102
  SHLLInfo*            pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
10,452✔
5103
  int32_t              resultBytes = getHLLInfoSize();
10,452✔
5104
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
10,452!
5105

5106
  if (NULL == res) {
10,455!
UNCOV
5107
    return terrno;
×
5108
  }
5109
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
10,455✔
5110
  varDataSetLen(res, resultBytes);
10,455✔
5111

5112
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
10,455✔
5113
  int32_t          code = TSDB_CODE_SUCCESS;
10,455✔
5114
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
10,455✔
5115
  if (NULL == pCol) {
10,455!
UNCOV
5116
    code = terrno;
×
UNCOV
5117
    goto _exit;
×
5118
  }
5119

5120
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
10,455✔
5121

5122
_exit:
10,455✔
5123
  taosMemoryFree(res);
10,455!
5124
  return code;
10,455✔
5125
}
5126

5127
int32_t hllCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
1✔
5128
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
1✔
5129
  SHLLInfo*            pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
1✔
5130

5131
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
1✔
5132
  SHLLInfo*            pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
1✔
5133

5134
  hllTransferInfo(pSBuf, pDBuf);
1✔
5135
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
1✔
5136
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
1✔
5137
  return TSDB_CODE_SUCCESS;
1✔
5138
}
5139

5140
bool getStateFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
19,273✔
5141
  pEnv->calcMemSize = sizeof(SStateInfo);
19,273✔
5142
  return true;
19,273✔
5143
}
5144

5145
static int8_t getStateOpType(char* opStr) {
37,693✔
5146
  int8_t opType;
5147
  if (strncasecmp(opStr, "LT", 2) == 0) {
37,693✔
5148
    opType = STATE_OPER_LT;
3,059✔
5149
  } else if (strncasecmp(opStr, "GT", 2) == 0) {
34,634✔
5150
    opType = STATE_OPER_GT;
1,710✔
5151
  } else if (strncasecmp(opStr, "LE", 2) == 0) {
32,924✔
5152
    opType = STATE_OPER_LE;
496✔
5153
  } else if (strncasecmp(opStr, "GE", 2) == 0) {
32,428✔
5154
    opType = STATE_OPER_GE;
5,914✔
5155
  } else if (strncasecmp(opStr, "NE", 2) == 0) {
26,514✔
5156
    opType = STATE_OPER_NE;
19,865✔
5157
  } else if (strncasecmp(opStr, "EQ", 2) == 0) {
6,649✔
5158
    opType = STATE_OPER_EQ;
6,648✔
5159
  } else {
5160
    opType = STATE_OPER_INVALID;
1✔
5161
  }
5162

5163
  return opType;
37,693✔
5164
}
5165

5166
static bool checkStateOp(int8_t op, SColumnInfoData* pCol, int32_t index, SVariant param) {
35,141,125✔
5167
  char* data = colDataGetData(pCol, index);
35,141,125!
5168
  switch (pCol->info.type) {
35,141,125!
5169
    case TSDB_DATA_TYPE_TINYINT: {
5,326,460✔
5170
      int8_t v = *(int8_t*)data;
5,326,460✔
5171
      STATE_COMP(op, v, param);
5,326,460!
UNCOV
5172
      break;
×
5173
    }
5174
    case TSDB_DATA_TYPE_UTINYINT: {
2,880✔
5175
      uint8_t v = *(uint8_t*)data;
2,880✔
5176
      STATE_COMP(op, v, param);
2,880!
UNCOV
5177
      break;
×
5178
    }
5179
    case TSDB_DATA_TYPE_SMALLINT: {
110,656✔
5180
      int16_t v = *(int16_t*)data;
110,656✔
5181
      STATE_COMP(op, v, param);
110,656!
UNCOV
5182
      break;
×
5183
    }
5184
    case TSDB_DATA_TYPE_USMALLINT: {
2,880✔
5185
      uint16_t v = *(uint16_t*)data;
2,880✔
5186
      STATE_COMP(op, v, param);
2,880!
UNCOV
5187
      break;
×
5188
    }
5189
    case TSDB_DATA_TYPE_INT: {
63,274✔
5190
      int32_t v = *(int32_t*)data;
63,274✔
5191
      STATE_COMP(op, v, param);
63,274!
UNCOV
5192
      break;
×
5193
    }
5194
    case TSDB_DATA_TYPE_UINT: {
2,880✔
5195
      uint32_t v = *(uint32_t*)data;
2,880✔
5196
      STATE_COMP(op, v, param);
2,880!
5197
      break;
×
5198
    }
5199
    case TSDB_DATA_TYPE_BIGINT: {
22,384✔
5200
      int64_t v = *(int64_t*)data;
22,384✔
5201
      STATE_COMP(op, v, param);
22,384!
UNCOV
5202
      break;
×
5203
    }
5204
    case TSDB_DATA_TYPE_UBIGINT: {
2,880✔
5205
      uint64_t v = *(uint64_t*)data;
2,880✔
5206
      STATE_COMP(op, v, param);
2,880!
UNCOV
5207
      break;
×
5208
    }
5209
    case TSDB_DATA_TYPE_FLOAT: {
29,498,940✔
5210
      float v = *(float*)data;
29,498,940✔
5211
      STATE_COMP(op, v, param);
29,498,940!
UNCOV
5212
      break;
×
5213
    }
5214
    case TSDB_DATA_TYPE_DOUBLE: {
109,478✔
5215
      double v = *(double*)data;
109,478✔
5216
      STATE_COMP(op, v, param);
109,478!
UNCOV
5217
      break;
×
5218
    }
UNCOV
5219
    default: {
×
5220
      return false;
×
5221
    }
5222
  }
UNCOV
5223
  return false;
×
5224
}
5225

5226
int32_t stateCountFunction(SqlFunctionCtx* pCtx) {
26,960✔
5227
  int32_t              code = TSDB_CODE_SUCCESS;
26,960✔
5228
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
26,960✔
5229
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
26,960✔
5230

5231
  SInputColumnInfoData* pInput = &pCtx->input;
26,960✔
5232
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
26,960✔
5233

5234
  SColumnInfoData* pInputCol = pInput->pData[0];
26,960✔
5235

5236
  int32_t          numOfElems = 0;
26,960✔
5237
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
26,960✔
5238

5239
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
26,960✔
5240
  if (STATE_OPER_INVALID == op) {
26,960!
UNCOV
5241
    return 0;
×
5242
  }
5243

5244
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
29,755,509✔
5245
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
29,728,525!
UNCOV
5246
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5247
    } else {
5248
      pInfo->prevTs = tsList[i];
29,728,525✔
5249
    }
5250

5251
    pInfo->isPrevTsSet = true;
29,728,525✔
5252
    numOfElems++;
29,728,525✔
5253

5254
    if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
29,728,525✔
5255
      colDataSetNULL(pOutput, i);
174,412!
5256
      // handle selectivity
5257
      if (pCtx->subsidiaries.num > 0) {
174,412✔
5258
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
18✔
5259
        if (TSDB_CODE_SUCCESS != code) {
18!
UNCOV
5260
          return code;
×
5261
        }
5262
      }
5263
      continue;
174,412✔
5264
    }
5265

5266
    bool ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
29,554,113✔
5267

5268
    int64_t output = -1;
29,554,105✔
5269
    if (ret) {
29,554,105✔
5270
      output = ++pInfo->count;
22,561,915✔
5271
    } else {
5272
      pInfo->count = 0;
6,992,190✔
5273
    }
5274
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
29,554,105✔
5275
    if (TSDB_CODE_SUCCESS != code) {
29,554,137!
UNCOV
5276
      return code;
×
5277
    }
5278

5279
    // handle selectivity
5280
    if (pCtx->subsidiaries.num > 0) {
29,554,137✔
5281
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
20,013,496✔
5282
      if (TSDB_CODE_SUCCESS != code) {
20,013,496!
UNCOV
5283
        return code;
×
5284
      }
5285
    }
5286
  }
5287

5288
  pResInfo->numOfRes = numOfElems;
26,984✔
5289
  return TSDB_CODE_SUCCESS;
26,984✔
5290
}
5291

5292
int32_t stateDurationFunction(SqlFunctionCtx* pCtx) {
10,734✔
5293
  int32_t              code = TSDB_CODE_SUCCESS;
10,734✔
5294
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
10,734✔
5295
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
10,734✔
5296

5297
  SInputColumnInfoData* pInput = &pCtx->input;
10,734✔
5298
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
10,734✔
5299

5300
  SColumnInfoData* pInputCol = pInput->pData[0];
10,734✔
5301

5302
  int32_t          numOfElems = 0;
10,734✔
5303
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
10,734✔
5304

5305
  // TODO: process timeUnit for different db precisions
5306
  int32_t timeUnit = 1;
10,734✔
5307
  if (pCtx->numOfParams == 5) {  // TODO: param number incorrect
10,734✔
5308
    timeUnit = pCtx->param[3].param.i;
9,752✔
5309
  }
5310

5311
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
10,734✔
5312
  if (STATE_OPER_INVALID == op) {
10,734!
UNCOV
5313
    return TSDB_CODE_INVALID_PARA;
×
5314
  }
5315

5316
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
5,714,434✔
5317
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
5,703,700!
UNCOV
5318
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5319
    } else {
5320
      pInfo->prevTs = tsList[i];
5,703,700✔
5321
    }
5322

5323
    pInfo->isPrevTsSet = true;
5,703,700✔
5324
    numOfElems++;
5,703,700✔
5325

5326
    if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
5,703,700✔
5327
      colDataSetNULL(pOutput, i);
115,384!
5328
      // handle selectivity
5329
      if (pCtx->subsidiaries.num > 0) {
115,384✔
5330
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
26✔
5331
        if (TSDB_CODE_SUCCESS != code) {
26!
UNCOV
5332
          return code;
×
5333
        }
5334
      }
5335
      continue;
115,384✔
5336
    }
5337

5338
    bool    ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
5,588,316✔
5339
    int64_t output = -1;
5,588,316✔
5340
    if (ret) {
5,588,316✔
5341
      if (pInfo->durationStart == 0) {
1,072,543✔
5342
        output = 0;
759,002✔
5343
        pInfo->durationStart = tsList[i];
759,002✔
5344
      } else {
5345
        output = (tsList[i] - pInfo->durationStart) / timeUnit;
313,541✔
5346
      }
5347
    } else {
5348
      pInfo->durationStart = 0;
4,515,773✔
5349
    }
5350
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
5,588,316✔
5351
    if (TSDB_CODE_SUCCESS != code) {
5,588,316!
UNCOV
5352
      return code;
×
5353
    }
5354

5355
    // handle selectivity
5356
    if (pCtx->subsidiaries.num > 0) {
5,588,316✔
5357
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
312✔
5358
      if (TSDB_CODE_SUCCESS != code) {
312!
UNCOV
5359
        return code;
×
5360
      }
5361
    }
5362
  }
5363

5364
  pResInfo->numOfRes = numOfElems;
10,734✔
5365
  return TSDB_CODE_SUCCESS;
10,734✔
5366
}
5367

5368
bool getCsumFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
15,633✔
5369
  pEnv->calcMemSize = sizeof(SSumRes);
15,633✔
5370
  return true;
15,633✔
5371
}
5372

5373
int32_t csumFunction(SqlFunctionCtx* pCtx) {
25,913✔
5374
  int32_t              code = TSDB_CODE_SUCCESS;
25,913✔
5375
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
25,913✔
5376
  SSumRes*             pSumRes = GET_ROWCELL_INTERBUF(pResInfo);
25,913✔
5377

5378
  SInputColumnInfoData* pInput = &pCtx->input;
25,913✔
5379
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
25,913✔
5380

5381
  SColumnInfoData* pInputCol = pInput->pData[0];
25,913✔
5382
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
25,913✔
5383

5384
  int32_t numOfElems = 0;
25,913✔
5385
  int32_t type = pInputCol->info.type;
25,913✔
5386
  int32_t startOffset = pCtx->offset;
25,913✔
5387
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
3,978,406✔
5388
    if (pSumRes->isPrevTsSet == true && tsList[i] == pSumRes->prevTs) {
3,952,438✔
5389
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
18✔
5390
    } else {
5391
      pSumRes->prevTs = tsList[i];
3,952,420✔
5392
    }
5393
    pSumRes->isPrevTsSet = true;
3,952,420✔
5394

5395
    int32_t pos = startOffset + numOfElems;
3,952,420✔
5396
    if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
3,952,420✔
5397
      // colDataSetNULL(pOutput, i);
5398
      continue;
506,656✔
5399
    }
5400

5401
    char* data = colDataGetData(pInputCol, i);
3,445,764!
5402
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
4,640,404!
5403
      int64_t v;
5404
      GET_TYPED_DATA(v, int64_t, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
1,194,564!
5405
      pSumRes->isum += v;
1,194,564✔
5406
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->isum, false);
1,194,564✔
5407
      if (TSDB_CODE_SUCCESS != code) {
1,194,640!
UNCOV
5408
        return code;
×
5409
      }
5410
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
2,251,880!
5411
      uint64_t v;
5412
      GET_TYPED_DATA(v, uint64_t, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
680!
5413
      pSumRes->usum += v;
680✔
5414
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->usum, false);
680✔
5415
      if (TSDB_CODE_SUCCESS != code) {
680!
UNCOV
5416
        return code;
×
5417
      }
5418
    } else if (IS_FLOAT_TYPE(type)) {
2,250,520!
5419
      double v;
5420
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
2,250,536!
5421
      pSumRes->dsum += v;
2,250,533✔
5422
      // check for overflow
5423
      if (isinf(pSumRes->dsum) || isnan(pSumRes->dsum)) {
2,250,533!
5424
        colDataSetNULL(pOutput, pos);
8!
5425
      } else {
5426
        code = colDataSetVal(pOutput, pos, (char*)&pSumRes->dsum, false);
2,250,525✔
5427
        if (TSDB_CODE_SUCCESS != code) {
2,250,525!
UNCOV
5428
          return code;
×
5429
        }
5430
      }
5431
    }
5432

5433
    // handle selectivity
5434
    if (pCtx->subsidiaries.num > 0) {
3,445,837✔
5435
      code = appendSelectivityValue(pCtx, i, pos);
1,988,830✔
5436
      if (TSDB_CODE_SUCCESS != code) {
1,988,830!
UNCOV
5437
        return code;
×
5438
      }
5439
    }
5440

5441
    numOfElems++;
3,445,837✔
5442
  }
5443

5444
  pResInfo->numOfRes = numOfElems;
25,968✔
5445
  return TSDB_CODE_SUCCESS;
25,968✔
5446
}
5447

5448
bool getMavgFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
13,676✔
5449
  pEnv->calcMemSize = sizeof(SMavgInfo) + MAVG_MAX_POINTS_NUM * sizeof(double);
13,676✔
5450
  return true;
13,676✔
5451
}
5452

5453
int32_t mavgFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
67,366✔
5454
  if (pResultInfo->initialized) {
67,366✔
5455
    return TSDB_CODE_SUCCESS;
53,004✔
5456
  }
5457
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
14,362!
UNCOV
5458
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5459
  }
5460

5461
  SMavgInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
14,364✔
5462
  pInfo->pos = 0;
14,364✔
5463
  pInfo->sum = 0;
14,364✔
5464
  pInfo->prevTs = -1;
14,364✔
5465
  pInfo->isPrevTsSet = false;
14,364✔
5466
  pInfo->numOfPoints = pCtx->param[1].param.i;
14,364✔
5467
  if (pInfo->numOfPoints < 1 || pInfo->numOfPoints > MAVG_MAX_POINTS_NUM) {
14,364!
UNCOV
5468
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
5469
  }
5470
  pInfo->pointsMeet = false;
14,364✔
5471

5472
  return TSDB_CODE_SUCCESS;
14,364✔
5473
}
5474

5475
int32_t mavgFunction(SqlFunctionCtx* pCtx) {
53,688✔
5476
  int32_t              code = TSDB_CODE_SUCCESS;
53,688✔
5477
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
53,688✔
5478
  SMavgInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
53,688✔
5479

5480
  SInputColumnInfoData* pInput = &pCtx->input;
53,688✔
5481
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
53,688✔
5482

5483
  SColumnInfoData* pInputCol = pInput->pData[0];
53,688✔
5484
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
53,688✔
5485
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
53,688✔
5486

5487
  int32_t numOfElems = 0;
53,688✔
5488
  int32_t type = pInputCol->info.type;
53,688✔
5489
  int32_t startOffset = pCtx->offset;
53,688✔
5490
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
59,301,448✔
5491
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
59,247,376!
UNCOV
5492
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5493
    } else {
5494
      pInfo->prevTs = tsList[i];
59,247,376✔
5495
    }
5496
    pInfo->isPrevTsSet = true;
59,247,376✔
5497

5498
    int32_t pos = startOffset + numOfElems;
59,247,376✔
5499
    if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
59,247,376✔
5500
      // colDataSetNULL(pOutput, i);
5501
      continue;
310,694✔
5502
    }
5503

5504
    char*  data = colDataGetData(pInputCol, i);
58,936,682!
5505
    double v;
5506
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
58,936,682!
5507

5508
    if (!pInfo->pointsMeet && (pInfo->pos < pInfo->numOfPoints - 1)) {
58,937,031✔
5509
      pInfo->points[pInfo->pos] = v;
5,744,966✔
5510
      pInfo->sum += v;
5,744,966✔
5511
    } else {
5512
      if (!pInfo->pointsMeet && (pInfo->pos == pInfo->numOfPoints - 1)) {
53,192,065!
5513
        pInfo->sum += v;
11,304✔
5514
        pInfo->pointsMeet = true;
11,304✔
5515
      } else {
5516
        pInfo->sum = pInfo->sum + v - pInfo->points[pInfo->pos];
53,180,761✔
5517
      }
5518

5519
      pInfo->points[pInfo->pos] = v;
53,192,065✔
5520
      double result = pInfo->sum / pInfo->numOfPoints;
53,192,065✔
5521
      // check for overflow
5522
      if (isinf(result) || isnan(result)) {
53,192,065!
5523
        colDataSetNULL(pOutput, pos);
1!
5524
      } else {
5525
        code = colDataSetVal(pOutput, pos, (char*)&result, false);
53,192,064✔
5526
        if (TSDB_CODE_SUCCESS != code) {
53,192,099!
UNCOV
5527
          return code;
×
5528
        }
5529
      }
5530

5531
      // handle selectivity
5532
      if (pCtx->subsidiaries.num > 0) {
53,192,100✔
5533
        code = appendSelectivityValue(pCtx, i, pos);
34,082,823✔
5534
        if (TSDB_CODE_SUCCESS != code) {
34,082,823!
UNCOV
5535
          return code;
×
5536
        }
5537
      }
5538

5539
      numOfElems++;
53,192,100✔
5540
    }
5541

5542
    pInfo->pos++;
58,937,066✔
5543
    if (pInfo->pos == pInfo->numOfPoints) {
58,937,066✔
5544
      pInfo->pos = 0;
122,310✔
5545
    }
5546
  }
5547

5548
  pResInfo->numOfRes = numOfElems;
54,072✔
5549
  return TSDB_CODE_SUCCESS;
54,072✔
5550
}
5551

5552
static SSampleInfo* getSampleOutputInfo(SqlFunctionCtx* pCtx) {
14,308,659✔
5553
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
14,308,659✔
5554
  SSampleInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
14,308,659✔
5555

5556
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
14,308,659✔
5557
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
14,308,659✔
5558

5559
  return pInfo;
14,308,659✔
5560
}
5561

5562
bool getSampleFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
30,144✔
5563
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
30,144✔
5564
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
30,147✔
5565
  int32_t      numOfSamples = pVal->datum.i;
30,148✔
5566
  pEnv->calcMemSize = sizeof(SSampleInfo) + numOfSamples * (pCol->node.resType.bytes + sizeof(STuplePos));
30,148✔
5567
  return true;
30,148✔
5568
}
5569

5570
int32_t sampleFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
7,206,569✔
5571
  if (pResultInfo->initialized) {
7,206,569!
UNCOV
5572
    return TSDB_CODE_SUCCESS;
×
5573
  }
5574
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
7,206,569!
UNCOV
5575
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5576
  }
5577

5578
  taosSeedRand(taosSafeRand());
7,206,571✔
5579

5580
  SSampleInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
7,206,571✔
5581
  pInfo->samples = pCtx->param[1].param.i;
7,206,571✔
5582
  pInfo->totalPoints = 0;
7,206,571✔
5583
  pInfo->numSampled = 0;
7,206,571✔
5584
  pInfo->colType = pCtx->resDataInfo.type;
7,206,571✔
5585
  pInfo->colBytes = pCtx->resDataInfo.bytes;
7,206,571✔
5586
  pInfo->nullTuplePos.pageId = -1;
7,206,571✔
5587
  pInfo->nullTupleSaved = false;
7,206,571✔
5588
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
7,206,571✔
5589
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
7,206,571✔
5590

5591
  return TSDB_CODE_SUCCESS;
7,206,571✔
5592
}
5593

5594
static void sampleAssignResult(SSampleInfo* pInfo, char* data, int32_t index) {
15,295,006✔
5595
  assignVal(pInfo->data + index * pInfo->colBytes, data, pInfo->colBytes, pInfo->colType);
15,295,006✔
5596
}
15,295,037✔
5597

5598
static int32_t doReservoirSample(SqlFunctionCtx* pCtx, SSampleInfo* pInfo, char* data, int32_t index) {
15,882,238✔
5599
  pInfo->totalPoints++;
15,882,238✔
5600
  if (pInfo->numSampled < pInfo->samples) {
15,882,238✔
5601
    sampleAssignResult(pInfo, data, pInfo->numSampled);
14,318,100✔
5602
    if (pCtx->subsidiaries.num > 0) {
14,318,051✔
5603
      int32_t code = saveTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[pInfo->numSampled]);
1,142,871✔
5604
      if (code != TSDB_CODE_SUCCESS) {
1,142,812!
UNCOV
5605
        return code;
×
5606
      }
5607
    }
5608
    pInfo->numSampled++;
14,317,992✔
5609
  } else {
5610
    int32_t j = taosRand() % (pInfo->totalPoints);
1,564,138✔
5611
    if (j < pInfo->samples) {
1,564,768✔
5612
      sampleAssignResult(pInfo, data, j);
977,163✔
5613
      if (pCtx->subsidiaries.num > 0) {
977,156✔
5614
        int32_t code = updateTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[j]);
412,897✔
5615
        if (code != TSDB_CODE_SUCCESS) {
412,452!
UNCOV
5616
          return code;
×
5617
        }
5618
      }
5619
    }
5620
  }
5621

5622
  return TSDB_CODE_SUCCESS;
15,882,308✔
5623
}
5624

5625
int32_t sampleFunction(SqlFunctionCtx* pCtx) {
7,240,663✔
5626
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,240,663✔
5627
  SSampleInfo*         pInfo = getSampleOutputInfo(pCtx);
7,240,663✔
5628

5629
  SInputColumnInfoData* pInput = &pCtx->input;
7,240,663✔
5630

5631
  SColumnInfoData* pInputCol = pInput->pData[0];
7,240,663✔
5632
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
23,485,631✔
5633
    if (colDataIsNull_s(pInputCol, i)) {
32,487,326✔
5634
      continue;
362,714✔
5635
    }
5636

5637
    char*   data = colDataGetData(pInputCol, i);
15,880,949!
5638
    int32_t code = doReservoirSample(pCtx, pInfo, data, i);
15,880,949✔
5639
    if (code != TSDB_CODE_SUCCESS) {
15,882,254!
UNCOV
5640
      return code;
×
5641
    }
5642
  }
5643

5644
  if (pInfo->numSampled == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
7,241,968✔
5645
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
12✔
5646
    if (code != TSDB_CODE_SUCCESS) {
12!
UNCOV
5647
      return code;
×
5648
    }
5649
    pInfo->nullTupleSaved = true;
12✔
5650
  }
5651

5652
  SET_VAL(pResInfo, pInfo->numSampled, pInfo->numSampled);
7,241,968✔
5653
  return TSDB_CODE_SUCCESS;
7,241,968✔
5654
}
5655

5656
int32_t sampleFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
7,067,999✔
5657
  int32_t              code = TSDB_CODE_SUCCESS;
7,067,999✔
5658
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
7,067,999✔
5659

5660
  SSampleInfo* pInfo = getSampleOutputInfo(pCtx);
7,067,999✔
5661
  pEntryInfo->complete = true;
7,067,999✔
5662

5663
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
7,067,999✔
5664
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
7,067,999✔
5665
  if (NULL == pCol) {
7,067,999!
UNCOV
5666
    return TSDB_CODE_OUT_OF_RANGE;
×
5667
  }
5668

5669
  int32_t currentRow = pBlock->info.rows;
7,067,999✔
5670
  if (pInfo->numSampled == 0) {
7,067,999✔
5671
    colDataSetNULL(pCol, currentRow);
2,241✔
5672
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
2,241✔
5673
    return code;
2,241✔
5674
  }
5675
  for (int32_t i = 0; i < pInfo->numSampled; ++i) {
21,084,356✔
5676
    code = colDataSetVal(pCol, currentRow + i, pInfo->data + i * pInfo->colBytes, false);
14,018,675✔
5677
    if (TSDB_CODE_SUCCESS != code) {
14,019,271!
UNCOV
5678
      return code;
×
5679
    }
5680
    code = setSelectivityValue(pCtx, pBlock, &pInfo->tuplePos[i], currentRow + i);
14,019,271✔
5681
    if (TSDB_CODE_SUCCESS != code) {
14,018,598!
UNCOV
5682
      return code;
×
5683
    }
5684
  }
5685

5686
  return code;
7,065,681✔
5687
}
5688

UNCOV
5689
bool getTailFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
5690
#if 0
5691
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
5692
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
5693
  int32_t      numOfPoints = pVal->datum.i;
5694
  pEnv->calcMemSize = sizeof(STailInfo) + numOfPoints * (POINTER_BYTES + sizeof(STailItem) + pCol->node.resType.bytes);
5695
#endif
UNCOV
5696
  return true;
×
5697
}
5698

UNCOV
5699
int32_t tailFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
×
5700
#if 0
5701
  if (!functionSetup(pCtx, pResultInfo)) {
5702
    return false;
5703
  }
5704

5705
  STailInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
5706
  pInfo->numAdded = 0;
5707
  pInfo->numOfPoints = pCtx->param[1].param.i;
5708
  if (pCtx->numOfParams == 4) {
5709
    pInfo->offset = pCtx->param[2].param.i;
5710
  } else {
5711
    pInfo->offset = 0;
5712
  }
5713
  pInfo->colType = pCtx->resDataInfo.type;
5714
  pInfo->colBytes = pCtx->resDataInfo.bytes;
5715
  if ((pInfo->numOfPoints < 1 || pInfo->numOfPoints > TAIL_MAX_POINTS_NUM) ||
5716
      (pInfo->numOfPoints < 0 || pInfo->numOfPoints > TAIL_MAX_OFFSET)) {
5717
    return false;
5718
  }
5719

5720
  pInfo->pItems = (STailItem**)((char*)pInfo + sizeof(STailInfo));
5721
  char* pItem = (char*)pInfo->pItems + pInfo->numOfPoints * POINTER_BYTES;
5722

5723
  size_t unitSize = sizeof(STailItem) + pInfo->colBytes;
5724
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5725
    pInfo->pItems[i] = (STailItem*)(pItem + i * unitSize);
5726
    pInfo->pItems[i]->isNull = false;
5727
  }
5728
#endif
5729

UNCOV
5730
  return TSDB_CODE_SUCCESS;
×
5731
}
5732

UNCOV
5733
static void tailAssignResult(STailItem* pItem, char* data, int32_t colBytes, TSKEY ts, bool isNull) {
×
5734
#if 0
5735
  pItem->timestamp = ts;
5736
  if (isNull) {
5737
    pItem->isNull = true;
5738
  } else {
5739
    pItem->isNull = false;
5740
    memcpy(pItem->data, data, colBytes);
5741
  }
5742
#endif
UNCOV
5743
}
×
5744

5745
#if 0
5746
static int32_t tailCompFn(const void* p1, const void* p2, const void* param) {
5747
  STailItem* d1 = *(STailItem**)p1;
5748
  STailItem* d2 = *(STailItem**)p2;
5749
  return compareInt64Val(&d1->timestamp, &d2->timestamp);
5750
}
5751

5752
static void doTailAdd(STailInfo* pInfo, char* data, TSKEY ts, bool isNull) {
5753
  STailItem** pList = pInfo->pItems;
5754
  if (pInfo->numAdded < pInfo->numOfPoints) {
5755
    tailAssignResult(pList[pInfo->numAdded], data, pInfo->colBytes, ts, isNull);
5756
    taosheapsort((void*)pList, sizeof(STailItem**), pInfo->numAdded + 1, NULL, tailCompFn, 0);
5757
    pInfo->numAdded++;
5758
  } else if (pList[0]->timestamp < ts) {
5759
    tailAssignResult(pList[0], data, pInfo->colBytes, ts, isNull);
5760
    taosheapadjust((void*)pList, sizeof(STailItem**), 0, pInfo->numOfPoints - 1, NULL, tailCompFn, NULL, 0);
5761
  }
5762
}
5763
#endif
5764

5765
int32_t tailFunction(SqlFunctionCtx* pCtx) {
×
5766
#if 0
5767
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5768
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5769

5770
  SInputColumnInfoData* pInput = &pCtx->input;
5771
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
5772

5773
  SColumnInfoData* pInputCol = pInput->pData[0];
5774
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
5775

5776
  int32_t startOffset = pCtx->offset;
5777
  if (pInfo->offset >= pInput->numOfRows) {
5778
    return 0;
5779
  } else {
5780
    pInfo->numOfPoints = TMIN(pInfo->numOfPoints, pInput->numOfRows - pInfo->offset);
5781
  }
5782
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex - pInfo->offset; i += 1) {
5783
    char* data = colDataGetData(pInputCol, i);
5784
    doTailAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
5785
  }
5786

5787
  taosqsort(pInfo->pItems, pInfo->numOfPoints, POINTER_BYTES, NULL, tailCompFn);
5788

5789
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5790
    int32_t    pos = startOffset + i;
5791
    STailItem* pItem = pInfo->pItems[i];
5792
    if (pItem->isNull) {
5793
      colDataSetNULL(pOutput, pos);
5794
    } else {
5795
      colDataSetVal(pOutput, pos, pItem->data, false);
5796
    }
5797
  }
5798

5799
  return pInfo->numOfPoints;
5800
#endif
UNCOV
5801
  return 0;
×
5802
}
5803

UNCOV
5804
int32_t tailFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
5805
#if 0
5806
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
5807
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pEntryInfo);
5808
  pEntryInfo->complete = true;
5809

5810
  int32_t type = pCtx->input.pData[0]->info.type;
5811
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
5812

5813
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
5814

5815
  // todo assign the tag value and the corresponding row data
5816
  int32_t currentRow = pBlock->info.rows;
5817
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
5818
    STailItem* pItem = pInfo->pItems[i];
5819
    colDataSetVal(pCol, currentRow, pItem->data, false);
5820
    currentRow += 1;
5821
  }
5822

5823
  return pEntryInfo->numOfRes;
5824
#endif
UNCOV
5825
  return 0;
×
5826
}
5827

UNCOV
5828
bool getUniqueFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
5829
#if 0
5830
  pEnv->calcMemSize = sizeof(SUniqueInfo) + UNIQUE_MAX_RESULT_SIZE;
5831
#endif
UNCOV
5832
  return true;
×
5833
}
5834

UNCOV
5835
int32_t uniqueFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
×
5836
#if 0
5837
  if (!functionSetup(pCtx, pResInfo)) {
5838
    return false;
5839
  }
5840

5841
  SUniqueInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5842
  pInfo->numOfPoints = 0;
5843
  pInfo->colType = pCtx->resDataInfo.type;
5844
  pInfo->colBytes = pCtx->resDataInfo.bytes;
5845
  if (pInfo->pHash != NULL) {
5846
    taosHashClear(pInfo->pHash);
5847
  } else {
5848
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
5849
  }
5850
#endif
UNCOV
5851
  return TSDB_CODE_SUCCESS;
×
5852
}
5853

5854
#if 0
5855
static void doUniqueAdd(SUniqueInfo* pInfo, char* data, TSKEY ts, bool isNull) {
5856
  // handle null elements
5857
  if (isNull == true) {
5858
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
5859
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
5860
    if (pInfo->hasNull == false && pItem->isNull == false) {
5861
      pItem->timestamp = ts;
5862
      pItem->isNull = true;
5863
      pInfo->numOfPoints++;
5864
      pInfo->hasNull = true;
5865
    } else if (pItem->timestamp > ts && pItem->isNull == true) {
5866
      pItem->timestamp = ts;
5867
    }
5868
    return;
5869
  }
5870

5871
  int32_t      hashKeyBytes = IS_VAR_DATA_TYPE(pInfo->colType) ? varDataTLen(data) : pInfo->colBytes;
5872
  SUniqueItem* pHashItem = taosHashGet(pInfo->pHash, data, hashKeyBytes);
5873
  if (pHashItem == NULL) {
5874
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
5875
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
5876
    pItem->timestamp = ts;
5877
    memcpy(pItem->data, data, pInfo->colBytes);
5878

5879
    taosHashPut(pInfo->pHash, data, hashKeyBytes, (char*)pItem, sizeof(SUniqueItem*));
5880
    pInfo->numOfPoints++;
5881
  } else if (pHashItem->timestamp > ts) {
5882
    pHashItem->timestamp = ts;
5883
  }
5884
}
5885
#endif
5886

UNCOV
5887
int32_t uniqueFunction(SqlFunctionCtx* pCtx) {
×
5888
#if 0
5889
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5890
  SUniqueInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5891

5892
  SInputColumnInfoData* pInput = &pCtx->input;
5893
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
5894

5895
  SColumnInfoData* pInputCol = pInput->pData[0];
5896
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
5897
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
5898

5899
  int32_t startOffset = pCtx->offset;
5900
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
5901
    char* data = colDataGetData(pInputCol, i);
5902
    doUniqueAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
5903

5904
    if (sizeof(SUniqueInfo) + pInfo->numOfPoints * (sizeof(SUniqueItem) + pInfo->colBytes) >= UNIQUE_MAX_RESULT_SIZE) {
5905
      taosHashCleanup(pInfo->pHash);
5906
      return 0;
5907
    }
5908
  }
5909

5910
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5911
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + i * (sizeof(SUniqueItem) + pInfo->colBytes));
5912
    if (pItem->isNull == true) {
5913
      colDataSetNULL(pOutput, i);
5914
    } else {
5915
      colDataSetVal(pOutput, i, pItem->data, false);
5916
    }
5917
    if (pTsOutput != NULL) {
5918
      colDataSetInt64(pTsOutput, i, &pItem->timestamp);
5919
    }
5920
  }
5921

5922
  return pInfo->numOfPoints;
5923
#endif
UNCOV
5924
  return 0;
×
5925
}
5926

5927
bool getModeFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
7,412✔
5928
  pEnv->calcMemSize = sizeof(SModeInfo);
7,412✔
5929
  return true;
7,412✔
5930
}
5931

5932
int32_t modeFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
6,188✔
5933
  if (pResInfo->initialized) {
6,188!
UNCOV
5934
    return TSDB_CODE_SUCCESS;
×
5935
  }
5936
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
6,188!
UNCOV
5937
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5938
  }
5939

5940
  SModeInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
6,187✔
5941
  pInfo->colType = pCtx->resDataInfo.type;
6,187✔
5942
  pInfo->colBytes = pCtx->resDataInfo.bytes;
6,187✔
5943
  if (pInfo->pHash != NULL) {
6,187!
UNCOV
5944
    taosHashClear(pInfo->pHash);
×
5945
  } else {
5946
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
6,187✔
5947
    if (NULL == pInfo->pHash) {
6,188!
UNCOV
5948
      return terrno;
×
5949
    }
5950
  }
5951
  pInfo->nullTupleSaved = false;
6,188✔
5952
  pInfo->nullTuplePos.pageId = -1;
6,188✔
5953

5954
  pInfo->buf = taosMemoryMalloc(pInfo->colBytes);
6,188!
5955
  if (NULL == pInfo->buf) {
6,188!
UNCOV
5956
    taosHashCleanup(pInfo->pHash);
×
UNCOV
5957
    pInfo->pHash = NULL;
×
UNCOV
5958
    return terrno;
×
5959
  }
5960
  pCtx->needCleanup = true;
6,188✔
5961
  return TSDB_CODE_SUCCESS;
6,188✔
5962
}
5963

5964
static void modeFunctionCleanup(SModeInfo* pInfo) {
6,188✔
5965
  taosHashCleanup(pInfo->pHash);
6,188✔
5966
  pInfo->pHash = NULL;
6,188✔
5967
  taosMemoryFreeClear(pInfo->buf);
6,188!
5968
}
6,188✔
5969

UNCOV
5970
void modeFunctionCleanupExt(SqlFunctionCtx* pCtx) {
×
UNCOV
5971
  if (pCtx == NULL || GET_RES_INFO(pCtx) == NULL || GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)) == NULL) {
×
UNCOV
5972
    return;
×
5973
  }
UNCOV
5974
  modeFunctionCleanup(GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)));
×
5975
}
5976

5977
static int32_t saveModeTupleData(SqlFunctionCtx* pCtx, char* data, SModeInfo* pInfo, STuplePos* pPos) {
3,222,474✔
5978
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
3,222,474!
5979
    if (pInfo->colType == TSDB_DATA_TYPE_JSON) {
125,974!
UNCOV
5980
      (void)memcpy(pInfo->buf, data, getJsonValueLen(data));
×
5981
    } else {
5982
      (void)memcpy(pInfo->buf, data, varDataTLen(data));
125,974✔
5983
    }
5984
  } else {
5985
    (void)memcpy(pInfo->buf, data, pInfo->colBytes);
3,096,500✔
5986
  }
5987

5988
  return doSaveTupleData(&pCtx->saveHandle, pInfo->buf, pInfo->colBytes, NULL, pPos, pCtx->pStore);
3,222,474✔
5989
}
5990

5991
static int32_t doModeAdd(SModeInfo* pInfo, int32_t rowIndex, SqlFunctionCtx* pCtx, char* data) {
3,256,086✔
5992
  int32_t code = TSDB_CODE_SUCCESS;
3,256,086✔
5993
  int32_t hashKeyBytes;
5994
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
3,256,086!
5995
    if (pInfo->colType == TSDB_DATA_TYPE_JSON) {
126,171!
UNCOV
5996
      hashKeyBytes = getJsonValueLen(data);
×
5997
    } else {
5998
      hashKeyBytes = varDataTLen(data);
126,171✔
5999
    }
6000
  } else {
6001
    hashKeyBytes = pInfo->colBytes;
3,129,915✔
6002
  }
6003

6004
  SModeItem* pHashItem = (SModeItem*)taosHashGet(pInfo->pHash, data, hashKeyBytes);
3,255,926✔
6005
  if (pHashItem == NULL) {
3,254,201✔
6006
    int32_t   size = sizeof(SModeItem);
3,222,450✔
6007
    SModeItem item = {0};
3,222,450✔
6008

6009
    item.count += 1;
3,222,450✔
6010
    code = saveModeTupleData(pCtx, data, pInfo, &item.dataPos);
3,222,450✔
6011
    if (code != TSDB_CODE_SUCCESS) {
3,220,896!
UNCOV
6012
      return code;
×
6013
    }
6014

6015
    if (pCtx->subsidiaries.num > 0) {
3,220,896✔
6016
      code = saveTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &item.tuplePos);
325✔
6017
      if (code != TSDB_CODE_SUCCESS) {
325!
UNCOV
6018
        return code;
×
6019
      }
6020
    }
6021

6022
    code = taosHashPut(pInfo->pHash, data, hashKeyBytes, &item, sizeof(SModeItem));
3,220,896✔
6023
    if (code != TSDB_CODE_SUCCESS) {
3,224,598!
6024
      return code;
×
6025
    }
6026
  } else {
6027
    pHashItem->count += 1;
31,751✔
6028
    if (pCtx->subsidiaries.num > 0) {
31,751✔
6029
      code = updateTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &pHashItem->tuplePos);
109✔
6030
      if (code != TSDB_CODE_SUCCESS) {
109!
UNCOV
6031
        return code;
×
6032
      }
6033
    }
6034
  }
6035

6036
  return code;
3,256,349✔
6037
}
6038

6039
int32_t modeFunction(SqlFunctionCtx* pCtx) {
7,239✔
6040
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,239✔
6041
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
7,239✔
6042

6043
  SInputColumnInfoData* pInput = &pCtx->input;
7,239✔
6044

6045
  SColumnInfoData* pInputCol = pInput->pData[0];
7,239✔
6046
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
7,239✔
6047

6048
  int32_t numOfElems = 0;
7,239✔
6049
  int32_t startOffset = pCtx->offset;
7,239✔
6050
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
3,738,260✔
6051
    if (colDataIsNull_s(pInputCol, i)) {
7,462,134✔
6052
      continue;
475,286✔
6053
    }
6054
    numOfElems++;
3,255,781✔
6055

6056
    char*   data = colDataGetData(pInputCol, i);
3,255,781!
6057
    int32_t code = doModeAdd(pInfo, i, pCtx, data);
3,255,781✔
6058
    if (code != TSDB_CODE_SUCCESS) {
3,256,336✔
6059
      modeFunctionCleanup(pInfo);
601✔
UNCOV
6060
      return code;
×
6061
    }
6062
  }
6063

6064
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
7,193!
6065
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
30✔
6066
    if (code != TSDB_CODE_SUCCESS) {
30!
UNCOV
6067
      modeFunctionCleanup(pInfo);
×
UNCOV
6068
      return code;
×
6069
    }
6070
    pInfo->nullTupleSaved = true;
30✔
6071
  }
6072

6073
  SET_VAL(pResInfo, numOfElems, 1);
7,193✔
6074

6075
  return TSDB_CODE_SUCCESS;
7,193✔
6076
}
6077

6078
int32_t modeFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
6,187✔
6079
  int32_t              code = TSDB_CODE_SUCCESS;
6,187✔
6080
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
6,187✔
6081
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
6,187✔
6082
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
6,187✔
6083
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
6,187✔
6084
  int32_t              currentRow = pBlock->info.rows;
6,187✔
6085
  if (NULL == pCol) {
6,187!
UNCOV
6086
    modeFunctionCleanup(pInfo);
×
UNCOV
6087
    return TSDB_CODE_OUT_OF_RANGE;
×
6088
  }
6089

6090
  STuplePos resDataPos, resTuplePos;
6091
  int32_t   maxCount = 0;
6,187✔
6092

6093
  void* pIter = taosHashIterate(pInfo->pHash, NULL);
6,187✔
6094
  while (pIter != NULL) {
3,231,331✔
6095
    SModeItem* pItem = (SModeItem*)pIter;
3,225,143✔
6096
    if (pItem->count >= maxCount) {
3,225,143✔
6097
      maxCount = pItem->count;
3,193,197✔
6098
      resDataPos = pItem->dataPos;
3,193,197✔
6099
      resTuplePos = pItem->tuplePos;
3,193,197✔
6100
    }
6101

6102
    pIter = taosHashIterate(pInfo->pHash, pIter);
3,225,143✔
6103
  }
6104

6105
  if (maxCount != 0) {
6,188✔
6106
    char* pData = NULL;
3,424✔
6107
    code = loadTupleData(pCtx, &resDataPos, &pData);
3,424✔
6108
    if (pData == NULL || TSDB_CODE_SUCCESS != code) {
3,424!
UNCOV
6109
      code = terrno = TSDB_CODE_NOT_FOUND;
×
UNCOV
6110
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
×
6111
             resDataPos.streamTupleKey.groupId, resDataPos.streamTupleKey.ts);
UNCOV
6112
      modeFunctionCleanup(pInfo);
×
6113
      return code;
×
6114
    }
6115

6116
    code = colDataSetVal(pCol, currentRow, pData, false);
3,424✔
6117
    if (TSDB_CODE_SUCCESS != code) {
3,424!
UNCOV
6118
      modeFunctionCleanup(pInfo);
×
UNCOV
6119
      return code;
×
6120
    }
6121
    code = setSelectivityValue(pCtx, pBlock, &resTuplePos, currentRow);
3,424✔
6122
  } else {
6123
    colDataSetNULL(pCol, currentRow);
2,764✔
6124
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
2,764✔
6125
  }
6126

6127
  modeFunctionCleanup(pInfo);
6,188✔
6128

6129
  return code;
6,188✔
6130
}
6131

6132
bool getTwaFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
77,726✔
6133
  pEnv->calcMemSize = sizeof(STwaInfo);
77,726✔
6134
  return true;
77,726✔
6135
}
6136

6137
int32_t twaFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
7,366,397✔
6138
  if (pResultInfo->initialized) {
7,366,397!
UNCOV
6139
    return TSDB_CODE_SUCCESS;
×
6140
  }
6141
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
7,366,397!
UNCOV
6142
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6143
  }
6144

6145
  STwaInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
7,366,408✔
6146
  pInfo->numOfElems = 0;
7,366,408✔
6147
  pInfo->p.key = INT64_MIN;
7,366,408✔
6148
  pInfo->win = TSWINDOW_INITIALIZER;
7,366,408✔
6149
  return TSDB_CODE_SUCCESS;
7,366,408✔
6150
}
6151

6152
static double twa_get_area(SPoint1 s, SPoint1 e) {
15,861,261✔
6153
  if (e.key == INT64_MAX || s.key == INT64_MIN) {
15,861,261!
UNCOV
6154
    return 0;
×
6155
  }
6156

6157
  if ((s.val >= 0 && e.val >= 0) || (s.val <= 0 && e.val <= 0)) {
15,861,390✔
6158
    return (s.val + e.val) * (e.key - s.key) / 2;
10,725,984✔
6159
  }
6160

6161
  double x = (s.key * e.val - e.key * s.val) / (e.val - s.val);
5,135,406✔
6162
  double val = (s.val * (x - s.key) + e.val * (e.key - x)) / 2;
5,135,406✔
6163
  return val;
5,135,406✔
6164
}
6165

6166
int32_t twaFunction(SqlFunctionCtx* pCtx) {
7,366,947✔
6167
  int32_t               code = TSDB_CODE_SUCCESS;
7,366,947✔
6168
  SInputColumnInfoData* pInput = &pCtx->input;
7,366,947✔
6169
  SColumnInfoData*      pInputCol = pInput->pData[0];
7,366,947✔
6170

6171
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,366,947✔
6172
  STwaInfo*            pInfo = GET_ROWCELL_INTERBUF(pResInfo);
7,366,947✔
6173
  SPoint1*             last = &pInfo->p;
7,366,947✔
6174

6175
  if (IS_NULL_TYPE(pInputCol->info.type)) {
7,366,947!
UNCOV
6176
    pInfo->numOfElems = 0;
×
UNCOV
6177
    goto _twa_over;
×
6178
  }
6179

6180
  funcInputUpdate(pCtx);
7,366,947✔
6181
  SFuncInputRow row = {0};
7,366,968✔
6182
  bool          result = false;
7,366,968✔
6183
  if (pCtx->start.key != INT64_MIN && last->key == INT64_MIN) {
7,366,968!
6184
    while (1) {
6185
      code = funcInputGetNextRow(pCtx, &row, &result);
3,723,051✔
6186
      if (TSDB_CODE_SUCCESS != code) {
3,723,068!
UNCOV
6187
        return code;
×
6188
      }
6189
      if (!result) {
3,723,068✔
6190
        break;
2✔
6191
      }
6192
      if (row.isDataNull) {
3,723,066✔
6193
        continue;
2✔
6194
      }
6195

6196
      last->key = row.ts;
3,723,064✔
6197

6198
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData, typeGetTypeModFromColInfo(&pInputCol->info));
3,723,064!
6199

6200
      pInfo->dOutput += twa_get_area(pCtx->start, *last);
3,723,064✔
6201
      pInfo->win.skey = pCtx->start.key;
3,723,062✔
6202
      pInfo->numOfElems++;
3,723,062✔
6203
      break;
3,723,062✔
6204
    }
6205
  } else if (pInfo->p.key == INT64_MIN) {
3,643,919✔
6206
    while (1) {
6207
      code = funcInputGetNextRow(pCtx, &row, &result);
3,751,655✔
6208
      if (TSDB_CODE_SUCCESS != code) {
3,751,571!
UNCOV
6209
        return code;
×
6210
      }
6211
      if (!result) {
3,751,571✔
6212
        break;
12,523✔
6213
      }
6214
      if (row.isDataNull) {
3,739,048✔
6215
        continue;
107,967✔
6216
      }
6217

6218
      last->key = row.ts;
3,631,081✔
6219

6220
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData, typeGetTypeModFromColInfo(&pInputCol->info));
3,631,081!
6221

6222
      pInfo->win.skey = last->key;
3,631,074✔
6223
      pInfo->numOfElems++;
3,631,074✔
6224
      break;
3,631,074✔
6225
    }
6226
  }
6227

6228
  SPoint1 st = {0};
7,366,892✔
6229

6230
  // calculate the value of
6231
  while (1) {
6232
    code = funcInputGetNextRow(pCtx, &row, &result);
15,519,930✔
6233
    if (TSDB_CODE_SUCCESS != code) {
15,519,418!
UNCOV
6234
      return code;
×
6235
    }
6236
    if (!result) {
15,519,418✔
6237
      break;
7,366,924✔
6238
    }
6239
    if (row.isDataNull) {
8,152,494✔
6240
      continue;
628✔
6241
    }
6242
    pInfo->numOfElems++;
8,151,866✔
6243
    switch (pInputCol->info.type) {
8,151,866!
6244
      case TSDB_DATA_TYPE_TINYINT: {
61,082✔
6245
        INIT_INTP_POINT(st, row.ts, *(int8_t*)row.pData);
61,082✔
6246
        break;
61,082✔
6247
      }
6248
      case TSDB_DATA_TYPE_SMALLINT: {
339,140✔
6249
        INIT_INTP_POINT(st, row.ts, *(int16_t*)row.pData);
339,140✔
6250
        break;
339,140✔
6251
      }
6252
      case TSDB_DATA_TYPE_INT: {
3,156,718✔
6253
        INIT_INTP_POINT(st, row.ts, *(int32_t*)row.pData);
3,156,718✔
6254
        break;
3,156,718✔
6255
      }
6256
      case TSDB_DATA_TYPE_BIGINT: {
348,514✔
6257
        INIT_INTP_POINT(st, row.ts, *(int64_t*)row.pData);
348,514✔
6258
        break;
348,514✔
6259
      }
6260
      case TSDB_DATA_TYPE_FLOAT: {
3,994,147✔
6261
        INIT_INTP_POINT(st, row.ts, *(float_t*)row.pData);
3,994,147✔
6262
        break;
3,994,147✔
6263
      }
6264
      case TSDB_DATA_TYPE_DOUBLE: {
65,886✔
6265
        INIT_INTP_POINT(st, row.ts, *(double*)row.pData);
65,886✔
6266
        break;
65,886✔
6267
      }
6268
      case TSDB_DATA_TYPE_UTINYINT: {
48,273✔
6269
        INIT_INTP_POINT(st, row.ts, *(uint8_t*)row.pData);
48,273✔
6270
        break;
48,273✔
6271
      }
6272
      case TSDB_DATA_TYPE_USMALLINT: {
48,936✔
6273
        INIT_INTP_POINT(st, row.ts, *(uint16_t*)row.pData);
48,936✔
6274
        break;
48,936✔
6275
      }
6276
      case TSDB_DATA_TYPE_UINT: {
50,532✔
6277
        INIT_INTP_POINT(st, row.ts, *(uint32_t*)row.pData);
50,532✔
6278
        break;
50,532✔
6279
      }
6280
      case TSDB_DATA_TYPE_UBIGINT: {
39,381✔
6281
        INIT_INTP_POINT(st, row.ts, *(uint64_t*)row.pData);
39,381✔
6282
        break;
39,381✔
6283
      }
UNCOV
6284
      default: {
×
6285
        return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
6286
      }
6287
    }
6288
    if (pInfo->p.key == st.key) {
8,152,609!
UNCOV
6289
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6290
    }
6291

6292
    pInfo->dOutput += twa_get_area(pInfo->p, st);
8,152,609✔
6293
    pInfo->p = st;
8,152,410✔
6294
  }
6295

6296
  // the last interpolated time window value
6297
  if (pCtx->end.key != INT64_MIN) {
7,366,924✔
6298
    pInfo->dOutput += twa_get_area(pInfo->p, pCtx->end);
3,986,284✔
6299
    pInfo->p = pCtx->end;
3,986,279✔
6300
    pInfo->numOfElems += 1;
3,986,279✔
6301
  }
6302

6303
  pInfo->win.ekey = pInfo->p.key;
7,366,919✔
6304

6305
_twa_over:
7,366,919✔
6306
  SET_VAL(pResInfo, 1, 1);
7,366,919✔
6307
  return TSDB_CODE_SUCCESS;
7,366,919✔
6308
}
6309

6310
/*
6311
 * To copy the input to interResBuf to avoid the input buffer space be over writen
6312
 * by next input data. The TWA function only applies to each table, so no merge procedure
6313
 * is required, we simply copy to the resut ot interResBuffer.
6314
 */
6315
// void twa_function_copy(SQLFunctionCtx *pCtx) {
6316
//   SResultRowEntryInfo *pResInfo = GET_RES_INFO(pCtx);
6317
//
6318
//   memcpy(GET_ROWCELL_INTERBUF(pResInfo), pCtx->pInput, (size_t)pCtx->inputBytes);
6319
//   pResInfo->hasResult = ((STwaInfo *)pCtx->pInput)->hasResult;
6320
// }
6321

6322
int32_t twaFinalize(struct SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
7,354,418✔
6323
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,354,418✔
6324

6325
  STwaInfo* pInfo = (STwaInfo*)GET_ROWCELL_INTERBUF(pResInfo);
7,354,418✔
6326
  if (pInfo->numOfElems == 0) {
7,354,418✔
6327
    pResInfo->numOfRes = 0;
12,345✔
6328
  } else {
6329
    if (pInfo->win.ekey == pInfo->win.skey) {
7,342,073✔
6330
      pInfo->dTwaRes = pInfo->p.val;
2,958,611✔
6331
    } else if (pInfo->win.ekey == INT64_MAX || pInfo->win.skey == INT64_MIN) {  // no data in timewindow
4,383,462!
UNCOV
6332
      pInfo->dTwaRes = 0;
×
6333
    } else {
6334
      pInfo->dTwaRes = pInfo->dOutput / (pInfo->win.ekey - pInfo->win.skey);
4,383,573✔
6335
    }
6336

6337
    pResInfo->numOfRes = 1;
7,342,073✔
6338
  }
6339

6340
  return functionFinalize(pCtx, pBlock);
7,354,418✔
6341
}
6342

6343
int32_t blockDistSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
1,628✔
6344
  if (pResultInfo->initialized) {
1,628!
UNCOV
6345
    return TSDB_CODE_SUCCESS;
×
6346
  }
6347
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
1,628!
UNCOV
6348
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6349
  }
6350

6351
  STableBlockDistInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,628✔
6352
  pInfo->minRows = INT32_MAX;
1,628✔
6353
  return TSDB_CODE_SUCCESS;
1,628✔
6354
}
6355

6356
int32_t blockDistFunction(SqlFunctionCtx* pCtx) {
3,253✔
6357
  const int32_t BLOCK_DIST_RESULT_ROWS = 25;
3,253✔
6358

6359
  SInputColumnInfoData* pInput = &pCtx->input;
3,253✔
6360
  SColumnInfoData*      pInputCol = pInput->pData[0];
3,253✔
6361
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
3,253✔
6362
  STableBlockDistInfo*  pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
3,253✔
6363

6364
  STableBlockDistInfo p1 = {0};
3,253✔
6365
  if (tDeserializeBlockDistInfo(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
3,253!
6366
    qError("failed to deserialize block dist info");
×
UNCOV
6367
    return TSDB_CODE_FAILED;
×
6368
  }
6369

6370
  pDistInfo->numOfBlocks += p1.numOfBlocks;
3,253✔
6371
  pDistInfo->numOfTables += p1.numOfTables;
3,253✔
6372
  pDistInfo->numOfInmemRows += p1.numOfInmemRows;
3,253✔
6373
  pDistInfo->numOfSttRows += p1.numOfSttRows;
3,253✔
6374
  pDistInfo->totalSize += p1.totalSize;
3,253✔
6375
  pDistInfo->totalRows += p1.totalRows;
3,253✔
6376
  pDistInfo->numOfFiles += p1.numOfFiles;
3,253✔
6377

6378
  pDistInfo->defMinRows = p1.defMinRows;
3,253✔
6379
  pDistInfo->defMaxRows = p1.defMaxRows;
3,253✔
6380
  pDistInfo->rowSize = p1.rowSize;
3,253✔
6381

6382
  if (pDistInfo->minRows > p1.minRows) {
3,253✔
6383
    pDistInfo->minRows = p1.minRows;
2✔
6384
  }
6385
  if (pDistInfo->maxRows < p1.maxRows) {
3,253✔
6386
    pDistInfo->maxRows = p1.maxRows;
2✔
6387
  }
6388
  pDistInfo->numOfVgroups += (p1.numOfTables != 0 ? 1 : 0);
3,253✔
6389
  for (int32_t i = 0; i < tListLen(pDistInfo->blockRowsHisto); ++i) {
68,313✔
6390
    pDistInfo->blockRowsHisto[i] += p1.blockRowsHisto[i];
65,060✔
6391
  }
6392

6393
  pResInfo->numOfRes = BLOCK_DIST_RESULT_ROWS;  // default output rows
3,253✔
6394
  return TSDB_CODE_SUCCESS;
3,253✔
6395
}
6396

6397
int32_t tSerializeBlockDistInfo(void* buf, int32_t bufLen, const STableBlockDistInfo* pInfo) {
6,497✔
6398
  SEncoder encoder = {0};
6,497✔
6399
  int32_t  code = 0;
6,497✔
6400
  int32_t  lino;
6401
  int32_t  tlen;
6402
  tEncoderInit(&encoder, buf, bufLen);
6,497✔
6403

6404
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
6,499!
6405
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->rowSize));
13,000!
6406

6407
  TAOS_CHECK_EXIT(tEncodeU16(&encoder, pInfo->numOfFiles));
13,000!
6408
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfBlocks));
13,000!
6409
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfTables));
13,000!
6410

6411
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalSize));
13,000!
6412
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalRows));
13,000!
6413
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->maxRows));
13,000!
6414
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->minRows));
13,000!
6415
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMaxRows));
13,000!
6416
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMinRows));
13,000!
6417
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfInmemRows));
13,000!
6418
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfSttRows));
13,000!
6419
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfVgroups));
13,000!
6420

6421
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
136,171✔
6422
    TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->blockRowsHisto[i]));
259,342!
6423
  }
6424

6425
  tEndEncode(&encoder);
6,500✔
6426

6427
_exit:
6,501✔
6428
  if (code) {
6,501!
UNCOV
6429
    tlen = code;
×
6430
  } else {
6431
    tlen = encoder.pos;
6,501✔
6432
  }
6433
  tEncoderClear(&encoder);
6,501✔
6434
  return tlen;
6,498✔
6435
}
6436

6437
int32_t tDeserializeBlockDistInfo(void* buf, int32_t bufLen, STableBlockDistInfo* pInfo) {
3,253✔
6438
  SDecoder decoder = {0};
3,253✔
6439
  int32_t  code = 0;
3,253✔
6440
  int32_t  lino;
6441
  tDecoderInit(&decoder, buf, bufLen);
3,253✔
6442

6443
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
3,253!
6444
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->rowSize));
6,506!
6445

6446
  TAOS_CHECK_EXIT(tDecodeU16(&decoder, &pInfo->numOfFiles));
6,506!
6447
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfBlocks));
6,506!
6448
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfTables));
6,506!
6449

6450
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalSize));
6,506!
6451
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalRows));
6,506!
6452
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->maxRows));
6,506!
6453
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->minRows));
6,506!
6454
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMaxRows));
6,506!
6455
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMinRows));
6,506!
6456
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfInmemRows));
6,506!
6457
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfSttRows));
6,506!
6458
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfVgroups));
6,506!
6459

6460
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
68,313✔
6461
    TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->blockRowsHisto[i]));
130,120!
6462
  }
6463

6464
_exit:
3,253✔
6465
  tDecoderClear(&decoder);
3,253✔
6466
  return code;
3,253✔
6467
}
6468

6469
int32_t blockDistFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,628✔
6470
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,628✔
6471
  STableBlockDistInfo* pData = GET_ROWCELL_INTERBUF(pResInfo);
1,628✔
6472

6473
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
1,628✔
6474
  if (NULL == pColInfo) {
1,628!
UNCOV
6475
    return TSDB_CODE_OUT_OF_RANGE;
×
6476
  }
6477

6478
  if (pData->totalRows == 0) {
1,628✔
6479
    pData->minRows = 0;
1,626✔
6480
  }
6481

6482
  int32_t row = 0;
1,628✔
6483
  char    st[256] = {0};
1,628✔
6484
  double  averageSize = 0;
1,628✔
6485
  if (pData->numOfBlocks != 0) {
1,628✔
6486
    averageSize = ((double)pData->totalSize) / pData->numOfBlocks;
2✔
6487
  }
6488
  uint64_t totalRawSize = pData->totalRows * pData->rowSize;
1,628✔
6489
  double   compRatio = 0;
1,628✔
6490
  if (totalRawSize != 0) {
1,628✔
6491
    compRatio = pData->totalSize * 100 / (double)totalRawSize;
2✔
6492
  }
6493

6494
  int32_t len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
3,256✔
6495
                          "Total_Blocks=[%d] Total_Size=[%.2f KiB] Average_size=[%.2f KiB] Compression_Ratio=[%.2f %c]",
6496
                          pData->numOfBlocks, pData->totalSize / 1024.0, averageSize / 1024.0, compRatio, '%');
1,628✔
6497

6498
  varDataSetLen(st, len);
1,628✔
6499
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
1,628✔
6500
  if (TSDB_CODE_SUCCESS != code) {
1,628!
UNCOV
6501
    return code;
×
6502
  }
6503

6504
  int64_t avgRows = 0;
1,628✔
6505
  if (pData->numOfBlocks > 0) {
1,628✔
6506
    avgRows = pData->totalRows / pData->numOfBlocks;
2✔
6507
  }
6508

6509
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
1,628✔
6510
                  "Block_Rows=[%" PRId64 "] MinRows=[%d] MaxRows=[%d] AvgRows=[%" PRId64 "]", pData->totalRows,
6511
                  pData->minRows, pData->maxRows, avgRows);
6512
  varDataSetLen(st, len);
1,628✔
6513
  code = colDataSetVal(pColInfo, row++, st, false);
1,628✔
6514
  if (TSDB_CODE_SUCCESS != code) {
1,628!
UNCOV
6515
    return code;
×
6516
  }
6517

6518
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Inmem_Rows=[%u] Stt_Rows=[%u] ",
1,628✔
6519
                  pData->numOfInmemRows, pData->numOfSttRows);
6520
  varDataSetLen(st, len);
1,628✔
6521
  code = colDataSetVal(pColInfo, row++, st, false);
1,628✔
6522
  if (TSDB_CODE_SUCCESS != code) {
1,628!
UNCOV
6523
    return code;
×
6524
  }
6525

6526
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
3,256✔
6527
                  "Total_Tables=[%d] Total_Filesets=[%d] Total_Vgroups=[%d]", pData->numOfTables, pData->numOfFiles,
1,628✔
6528
                  pData->numOfVgroups);
6529

6530
  varDataSetLen(st, len);
1,628✔
6531
  code = colDataSetVal(pColInfo, row++, st, false);
1,628✔
6532
  if (TSDB_CODE_SUCCESS != code) {
1,628!
6533
    return code;
×
6534
  }
6535

6536
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
1,628✔
6537
                  "--------------------------------------------------------------------------------");
6538
  varDataSetLen(st, len);
1,628✔
6539
  code = colDataSetVal(pColInfo, row++, st, false);
1,628✔
6540
  if (TSDB_CODE_SUCCESS != code) {
1,628!
UNCOV
6541
    return code;
×
6542
  }
6543

6544
  int32_t maxVal = 0;
1,628✔
6545
  int32_t minVal = INT32_MAX;
1,628✔
6546
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
34,188✔
6547
    if (maxVal < pData->blockRowsHisto[i]) {
32,560✔
6548
      maxVal = pData->blockRowsHisto[i];
3✔
6549
    }
6550

6551
    if (minVal > pData->blockRowsHisto[i]) {
32,560✔
6552
      minVal = pData->blockRowsHisto[i];
1,629✔
6553
    }
6554
  }
6555

6556
  // maximum number of step is 80
6557
  double factor = pData->numOfBlocks / 80.0;
1,628✔
6558

6559
  int32_t numOfBuckets = sizeof(pData->blockRowsHisto) / sizeof(pData->blockRowsHisto[0]);
1,628✔
6560
  int32_t bucketRange = ceil(((double)(pData->defMaxRows - pData->defMinRows)) / numOfBuckets);
1,628✔
6561

6562
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
34,188✔
6563
    len =
32,560✔
6564
        tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "%04d |", pData->defMinRows + bucketRange * (i + 1));
32,560✔
6565

6566
    int32_t num = 0;
32,560✔
6567
    if (pData->blockRowsHisto[i] > 0) {
32,560✔
6568
      num = (pData->blockRowsHisto[i]) / factor;
3✔
6569
    }
6570

6571
    for (int32_t j = 0; j < num; ++j) {
32,719✔
6572
      int32_t x = tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "%c", '|');
159✔
6573
      len += x;
159✔
6574
    }
6575

6576
    if (pData->blockRowsHisto[i] > 0) {
32,560✔
6577
      double v = pData->blockRowsHisto[i] * 100.0 / pData->numOfBlocks;
3✔
6578
      len += tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "  %d (%.2f%c)",
3✔
6579
                       pData->blockRowsHisto[i], v, '%');
6580
    }
6581

6582
    varDataSetLen(st, len);
32,560✔
6583
    code = colDataSetVal(pColInfo, row++, st, false);
32,560✔
6584
    if (TSDB_CODE_SUCCESS != code) {
32,560!
UNCOV
6585
      return code;
×
6586
    }
6587
  }
6588

6589
  return TSDB_CODE_SUCCESS;
1,628✔
6590
}
6591
int32_t blockDBUsageSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
1✔
6592
  if (pResultInfo->initialized) {
1!
UNCOV
6593
    return TSDB_CODE_SUCCESS;
×
6594
  }
6595
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
1!
UNCOV
6596
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6597
  }
6598

6599
  SDBBlockUsageInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1✔
6600
  return TSDB_CODE_SUCCESS;
1✔
6601
}
6602
int32_t blockDBUsageFunction(SqlFunctionCtx* pCtx) {
2✔
6603
  const int32_t BLOCK_DISK_USAGE_RESULT_ROWS = 2;
2✔
6604

6605
  SInputColumnInfoData* pInput = &pCtx->input;
2✔
6606
  SColumnInfoData*      pInputCol = pInput->pData[0];
2✔
6607
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
2✔
6608
  SDBBlockUsageInfo*    pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
2✔
6609

6610
  SDBBlockUsageInfo p1 = {0};
2✔
6611
  if (tDeserializeBlockDbUsage(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
2!
UNCOV
6612
    qError("failed to deserialize block dist info");
×
UNCOV
6613
    return TSDB_CODE_FAILED;
×
6614
  }
6615

6616
  pDistInfo->dataInDiskSize += p1.dataInDiskSize;
2✔
6617
  pDistInfo->walInDiskSize += p1.walInDiskSize;
2✔
6618
  pDistInfo->rawDataSize += p1.rawDataSize;
2✔
6619
  pResInfo->numOfRes = BLOCK_DISK_USAGE_RESULT_ROWS;  // default output rows
2✔
6620
  return TSDB_CODE_SUCCESS;
2✔
6621
}
6622

6623
int32_t tSerializeBlockDbUsage(void* buf, int32_t bufLen, const SDBBlockUsageInfo* pInfo) {
4✔
6624
  SEncoder encoder = {0};
4✔
6625
  int32_t  code = 0;
4✔
6626
  int32_t  lino;
6627
  int32_t  tlen;
6628
  tEncoderInit(&encoder, buf, bufLen);
4✔
6629

6630
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
4!
6631

6632
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->dataInDiskSize));
8!
6633
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->walInDiskSize));
8!
6634
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->rawDataSize));
8!
6635

6636
  tEndEncode(&encoder);
4✔
6637

6638
_exit:
4✔
6639
  if (code) {
4!
UNCOV
6640
    tlen = code;
×
6641
  } else {
6642
    tlen = encoder.pos;
4✔
6643
  }
6644
  tEncoderClear(&encoder);
4✔
6645
  return tlen;
4✔
6646
}
6647
int32_t tDeserializeBlockDbUsage(void* buf, int32_t bufLen, SDBBlockUsageInfo* pInfo) {
2✔
6648
  SDecoder decoder = {0};
2✔
6649
  int32_t  code = 0;
2✔
6650
  int32_t  lino;
6651
  tDecoderInit(&decoder, buf, bufLen);
2✔
6652

6653
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
2!
6654
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->dataInDiskSize));
4!
6655
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->walInDiskSize));
4!
6656
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->rawDataSize));
4!
6657

6658
_exit:
2✔
6659
  tDecoderClear(&decoder);
2✔
6660
  return code;
2✔
6661
}
6662
int32_t blockDBUsageFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1✔
6663
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1✔
6664
  SDBBlockUsageInfo*   pData = GET_ROWCELL_INTERBUF(pResInfo);
1✔
6665

6666
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
1✔
6667
  if (NULL == pColInfo) {
1!
UNCOV
6668
    return TSDB_CODE_OUT_OF_RANGE;
×
6669
  }
6670
  int32_t len = 0;
1✔
6671
  int32_t row = 0;
1✔
6672
  char    st[256] = {0};
1✔
6673

6674
  uint64_t totalDiskSize = pData->dataInDiskSize;
1✔
6675
  uint64_t rawDataSize = pData->rawDataSize;
1✔
6676
  double   compressRatio = 0;
1✔
6677
  if (rawDataSize != 0) {
1!
6678
    compressRatio = totalDiskSize * 100 / (double)rawDataSize;
1✔
6679
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[%.2f%]", compressRatio);
1✔
6680
  } else {
UNCOV
6681
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[NULL]");
×
6682
  }
6683

6684
  varDataSetLen(st, len);
1✔
6685
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
1✔
6686
  if (TSDB_CODE_SUCCESS != code) {
1!
UNCOV
6687
    return code;
×
6688
  }
6689

6690
  len =
1✔
6691
      tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Disk_occupied=[%" PRId64 "k]", pData->dataInDiskSize);
1✔
6692
  varDataSetLen(st, len);
1✔
6693
  code = colDataSetVal(pColInfo, row++, st, false);
1✔
6694
  if (TSDB_CODE_SUCCESS != code) {
1!
UNCOV
6695
    return code;
×
6696
  }
6697
  return code;
1✔
6698
}
6699

6700
bool getDerivativeFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
30,559✔
6701
  pEnv->calcMemSize = sizeof(SDerivInfo);
30,559✔
6702
  return true;
30,559✔
6703
}
6704

6705
int32_t derivativeFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
84,037✔
6706
  if (pResInfo->initialized) {
84,037✔
6707
    return TSDB_CODE_SUCCESS;
53,347✔
6708
  }
6709
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
30,690!
UNCOV
6710
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6711
  }
6712

6713
  SDerivInfo* pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
30,690✔
6714

6715
  pDerivInfo->ignoreNegative = pCtx->param[2].param.i;
30,690✔
6716
  pDerivInfo->prevTs = -1;
30,690✔
6717
  pDerivInfo->tsWindow = pCtx->param[1].param.i;
30,690✔
6718
  pDerivInfo->valueSet = false;
30,690✔
6719
  return TSDB_CODE_SUCCESS;
30,690✔
6720
}
6721

6722
int32_t derivativeFunction(SqlFunctionCtx* pCtx) {
53,478✔
6723
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
53,478✔
6724
  SDerivInfo*          pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
53,478✔
6725

6726
  SInputColumnInfoData* pInput = &pCtx->input;
53,478✔
6727
  SColumnInfoData*      pInputCol = pInput->pData[0];
53,478✔
6728

6729
  int32_t          numOfElems = 0;
53,478✔
6730
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
53,478✔
6731
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
53,478✔
6732
  int32_t          code = TSDB_CODE_SUCCESS;
53,478✔
6733

6734
  funcInputUpdate(pCtx);
53,478✔
6735

6736
  double v = 0;
53,478✔
6737
  if (pCtx->order == TSDB_ORDER_ASC) {
53,478✔
6738
    SFuncInputRow row = {0};
50,082✔
6739
    bool          result = false;
50,082✔
6740
    while (1) {
2,732,394✔
6741
      code = funcInputGetNextRow(pCtx, &row, &result);
2,782,476✔
6742
      if (TSDB_CODE_SUCCESS != code) {
2,782,476!
UNCOV
6743
        return code;
×
6744
      }
6745
      if (!result) {
2,782,476✔
6746
        break;
50,082✔
6747
      }
6748
      if (row.isDataNull) {
2,732,394✔
6749
        continue;
40,697✔
6750
      }
6751

6752
      char* d = row.pData;
2,691,697✔
6753
      GET_TYPED_DATA(v, double, pInputCol->info.type, d, typeGetTypeModFromColInfo(&pInputCol->info));
2,691,697!
6754

6755
      int32_t pos = pCtx->offset + numOfElems;
2,691,697✔
6756
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
2,691,697✔
6757
        pDerivInfo->valueSet = true;
26,907✔
6758
      } else {
6759
        if (row.ts == pDerivInfo->prevTs) {
2,664,790!
UNCOV
6760
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6761
        }
6762
        double r = ((v - pDerivInfo->prevValue) * pDerivInfo->tsWindow) / (row.ts - pDerivInfo->prevTs);
2,664,790✔
6763
        if (pDerivInfo->ignoreNegative && r < 0) {
2,664,790✔
6764
        } else {
6765
          if (isinf(r) || isnan(r)) {
1,502,710!
UNCOV
6766
            colDataSetNULL(pOutput, pos);
×
6767
          } else {
6768
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
1,502,710✔
6769
            if (code != TSDB_CODE_SUCCESS) {
1,502,710!
UNCOV
6770
              return code;
×
6771
            }
6772
          }
6773

6774
          if (pTsOutput != NULL) {
1,502,710!
6775
            colDataSetInt64(pTsOutput, pos, &row.ts);
×
6776
          }
6777

6778
          // handle selectivity
6779
          if (pCtx->subsidiaries.num > 0) {
1,502,710✔
6780
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
1,044,891✔
6781
            if (code != TSDB_CODE_SUCCESS) {
1,044,891!
UNCOV
6782
              return code;
×
6783
            }
6784
          }
6785

6786
          numOfElems++;
1,502,710✔
6787
        }
6788
      }
6789

6790
      pDerivInfo->prevValue = v;
2,691,697✔
6791
      pDerivInfo->prevTs = row.ts;
2,691,697✔
6792
    }
6793
  } else {
6794
    SFuncInputRow row = {0};
3,396✔
6795
    bool          result = false;
3,396✔
6796
    while (1) {
334,543✔
6797
      code = funcInputGetNextRow(pCtx, &row, &result);
337,939✔
6798
      if (TSDB_CODE_SUCCESS != code) {
337,939!
UNCOV
6799
        return code;
×
6800
      }
6801
      if (!result) {
337,939✔
6802
        break;
3,396✔
6803
      }
6804
      if (row.isDataNull) {
334,543✔
6805
        continue;
701✔
6806
      }
6807

6808
      char* d = row.pData;
333,842✔
6809
      GET_TYPED_DATA(v, double, pInputCol->info.type, d, typeGetTypeModFromColInfo(&pInputCol->info));
333,842!
6810

6811
      int32_t pos = pCtx->offset + numOfElems;
333,842✔
6812
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
333,842✔
6813
        pDerivInfo->valueSet = true;
3,359✔
6814
      } else {
6815
        if (row.ts == pDerivInfo->prevTs) {
330,483!
UNCOV
6816
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6817
        }
6818
        double r = ((pDerivInfo->prevValue - v) * pDerivInfo->tsWindow) / (pDerivInfo->prevTs - row.ts);
330,483✔
6819
        if (pDerivInfo->ignoreNegative && r < 0) {
330,483✔
6820
        } else {
6821
          if (isinf(r) || isnan(r)) {
173,594!
UNCOV
6822
            colDataSetNULL(pOutput, pos);
×
6823
          } else {
6824
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
173,594✔
6825
            if (code != TSDB_CODE_SUCCESS) {
173,594!
UNCOV
6826
              return code;
×
6827
            }
6828
          }
6829

6830
          if (pTsOutput != NULL) {
173,594!
UNCOV
6831
            colDataSetInt64(pTsOutput, pos, &pDerivInfo->prevTs);
×
6832
          }
6833

6834
          // handle selectivity
6835
          if (pCtx->subsidiaries.num > 0) {
173,594✔
6836
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
60,008✔
6837
            if (code != TSDB_CODE_SUCCESS) {
60,008!
UNCOV
6838
              return code;
×
6839
            }
6840
          }
6841
          numOfElems++;
173,594✔
6842
        }
6843
      }
6844

6845
      pDerivInfo->prevValue = v;
333,842✔
6846
      pDerivInfo->prevTs = row.ts;
333,842✔
6847
    }
6848
  }
6849

6850
  pResInfo->numOfRes = numOfElems;
53,478✔
6851

6852
  return TSDB_CODE_SUCCESS;
53,478✔
6853
}
6854

6855
int32_t getIrateInfoSize(int32_t pkBytes) { return (int32_t)sizeof(SRateInfo) + 2 * pkBytes; }
2,022,229✔
6856

6857
bool getIrateFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
125,450✔
6858
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
125,450✔
6859
  pEnv->calcMemSize = getIrateInfoSize(pkBytes);
125,450✔
6860
  return true;
125,536✔
6861
}
6862

6863
int32_t irateFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
9,289,763✔
6864
  if (pResInfo->initialized) {
9,289,763!
UNCOV
6865
    return TSDB_CODE_SUCCESS;
×
6866
  }
6867
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
9,289,763!
UNCOV
6868
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6869
  }
6870

6871
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
9,289,899✔
6872

6873
  pInfo->firstKey = INT64_MIN;
9,289,899✔
6874
  pInfo->lastKey = INT64_MIN;
9,289,899✔
6875
  pInfo->firstValue = (double)INT64_MIN;
9,289,899✔
6876
  pInfo->lastValue = (double)INT64_MIN;
9,289,899✔
6877

6878
  pInfo->hasResult = 0;
9,289,899✔
6879
  return TSDB_CODE_SUCCESS;
9,289,899✔
6880
}
6881

6882
static void doSaveRateInfo(SRateInfo* pRateInfo, bool isFirst, int64_t ts, char* pk, double v) {
30,064,260✔
6883
  if (isFirst) {
30,064,260✔
6884
    pRateInfo->firstValue = v;
11,342,088✔
6885
    pRateInfo->firstKey = ts;
11,342,088✔
6886
    if (pRateInfo->firstPk) {
11,342,088✔
6887
      int32_t pkBytes;
6888
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
35!
6889
        if (pRateInfo->pkType == TSDB_DATA_TYPE_JSON) {
8!
UNCOV
6890
          pkBytes = getJsonValueLen(pk);
×
6891
        } else {
6892
          pkBytes = varDataTLen(pk);
8✔
6893
        }
6894
      } else {
6895
        pkBytes = pRateInfo->pkBytes;
27✔
6896
      }
6897
      (void)memcpy(pRateInfo->firstPk, pk, pkBytes);
35✔
6898
    }
6899
  } else {
6900
    pRateInfo->lastValue = v;
18,722,172✔
6901
    pRateInfo->lastKey = ts;
18,722,172✔
6902
    if (pRateInfo->lastPk) {
18,722,172✔
6903
      int32_t pkBytes;
6904
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
52!
6905
        if (pRateInfo->pkType == TSDB_DATA_TYPE_JSON) {
12!
UNCOV
6906
          pkBytes = getJsonValueLen(pk);
×
6907
        } else {
6908
          pkBytes = varDataTLen(pk);
12✔
6909
        }
6910
      } else {
6911
        pkBytes = pRateInfo->pkBytes;
40✔
6912
      }
6913
      (void)memcpy(pRateInfo->lastPk, pk, pkBytes);
52✔
6914
    }
6915
  }
6916
}
30,064,260✔
6917

6918
static void initializeRateInfo(SqlFunctionCtx* pCtx, SRateInfo* pRateInfo, bool isMerge) {
11,222,370✔
6919
  if (pCtx->hasPrimaryKey) {
11,222,370✔
6920
    if (!isMerge) {
19✔
6921
      pRateInfo->pkType = pCtx->input.pPrimaryKey->info.type;
17✔
6922
      pRateInfo->pkBytes = pCtx->input.pPrimaryKey->info.bytes;
17✔
6923
      pRateInfo->firstPk = pRateInfo->pkData;
17✔
6924
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
17✔
6925
    } else {
6926
      pRateInfo->firstPk = pRateInfo->pkData;
2✔
6927
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
2✔
6928
    }
6929
  } else {
6930
    pRateInfo->firstPk = NULL;
11,222,351✔
6931
    pRateInfo->lastPk = NULL;
11,222,351✔
6932
  }
6933
}
11,222,370✔
6934

6935
int32_t irateFunction(SqlFunctionCtx* pCtx) {
7,432,226✔
6936
  int32_t              code = TSDB_CODE_SUCCESS;
7,432,226✔
6937
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,432,226✔
6938
  SRateInfo*           pRateInfo = GET_ROWCELL_INTERBUF(pResInfo);
7,432,226✔
6939

6940
  SInputColumnInfoData* pInput = &pCtx->input;
7,432,226✔
6941
  SColumnInfoData*      pInputCol = pInput->pData[0];
7,432,226✔
6942

6943
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
7,432,226✔
6944

6945
  funcInputUpdate(pCtx);
7,432,226✔
6946

6947
  initializeRateInfo(pCtx, pRateInfo, false);
7,432,304✔
6948

6949
  int32_t       numOfElems = 0;
7,432,300✔
6950
  int32_t       type = pInputCol->info.type;
7,432,300✔
6951
  SFuncInputRow row = {0};
7,432,300✔
6952
  bool          result = false;
7,432,300✔
6953
  while (1) {
17,369,926✔
6954
    code = funcInputGetNextRow(pCtx, &row, &result);
24,802,226✔
6955
    if (TSDB_CODE_SUCCESS != code) {
24,801,767!
UNCOV
6956
      return code;
×
6957
    }
6958
    if (!result) {
24,801,767✔
6959
      break;
7,432,264✔
6960
    }
6961
    if (row.isDataNull) {
17,369,503✔
6962
      continue;
128,098✔
6963
    }
6964

6965
    char*  data = row.pData;
17,241,405✔
6966
    double v = 0;
17,241,405✔
6967
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
17,241,405!
6968

6969
    if (INT64_MIN == pRateInfo->lastKey) {
17,242,175✔
6970
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
7,381,490✔
6971
      pRateInfo->hasResult = 1;
7,381,484✔
6972
      continue;
7,381,484✔
6973
    }
6974

6975
    if (row.ts > pRateInfo->lastKey) {
9,860,685✔
6976
      if ((INT64_MIN == pRateInfo->firstKey) || pRateInfo->lastKey > pRateInfo->firstKey) {
9,446,445!
6977
        doSaveRateInfo(pRateInfo, true, pRateInfo->lastKey, pRateInfo->lastPk, pRateInfo->lastValue);
9,446,446✔
6978
      }
6979
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
9,446,415✔
6980
      continue;
9,446,368✔
6981
    } else if (row.ts == pRateInfo->lastKey) {
414,240!
UNCOV
6982
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6983
    }
6984

6985
    if ((INT64_MIN == pRateInfo->firstKey) || row.ts > pRateInfo->firstKey) {
414,240!
6986
      doSaveRateInfo(pRateInfo, true, row.ts, row.pPk, v);
489✔
6987
    } else if (row.ts == pRateInfo->firstKey) {
413,751!
UNCOV
6988
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6989
    }
6990
  }
6991

6992
  numOfElems++;
7,432,264✔
6993

6994
  SET_VAL(pResInfo, numOfElems, 1);
7,432,264!
6995
  return TSDB_CODE_SUCCESS;
7,432,264✔
6996
}
6997

6998
static double doCalcRate(const SRateInfo* pRateInfo, double tickPerSec) {
7,384,974✔
6999
  if ((INT64_MIN == pRateInfo->lastKey) || (INT64_MIN == pRateInfo->firstKey) ||
7,384,974✔
7000
      (pRateInfo->firstKey >= pRateInfo->lastKey)) {
665,853!
7001
    return 0.0;
6,719,121✔
7002
  }
7003

7004
  double diff = 0;
665,853✔
7005
  // If the previous value of the last is greater than the last value, only keep the last point instead of the delta
7006
  // value between two values.
7007
  diff = pRateInfo->lastValue;
665,853✔
7008
  if (diff >= pRateInfo->firstValue) {
665,853✔
7009
    diff -= pRateInfo->firstValue;
340,276✔
7010
  }
7011

7012
  int64_t duration = pRateInfo->lastKey - pRateInfo->firstKey;
665,853✔
7013
  if (duration == 0) {
665,853!
UNCOV
7014
    return 0;
×
7015
  }
7016

7017
  return (duration > 0) ? ((double)diff) / (duration / tickPerSec) : 0.0;
665,853!
7018
}
7019

7020
static void irateTransferInfoImpl(TSKEY inputKey, SRateInfo* pInput, SRateInfo* pOutput, bool isFirstKey) {
402✔
7021
  if (inputKey > pOutput->lastKey) {
402✔
7022
    doSaveRateInfo(pOutput, true, pOutput->lastKey, pOutput->lastPk, pOutput->lastValue);
166✔
7023
    if (isFirstKey) {
166✔
7024
      doSaveRateInfo(pOutput, false, pInput->firstKey, pInput->firstPk, pInput->firstValue);
44✔
7025
    } else {
7026
      doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
122✔
7027
    }
7028
  } else if ((inputKey < pOutput->lastKey) && (inputKey > pOutput->firstKey)) {
236!
7029
    if (isFirstKey) {
130✔
7030
      doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
76✔
7031
    } else {
7032
      doSaveRateInfo(pOutput, true, pInput->lastKey, pInput->lastPk, pInput->lastValue);
54✔
7033
    }
7034
  } else {
7035
    // inputKey < pOutput->firstKey
7036
  }
7037
}
402✔
7038

7039
static void irateCopyInfo(SRateInfo* pInput, SRateInfo* pOutput) {
1,894,899✔
7040
  doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
1,894,899✔
7041
  doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
1,894,899✔
7042
}
1,894,899✔
7043

7044
static int32_t irateTransferInfo(SRateInfo* pInput, SRateInfo* pOutput) {
1,895,100✔
7045
  if ((pInput->firstKey != INT64_MIN &&
1,895,100✔
7046
       (pInput->firstKey == pOutput->firstKey || pInput->firstKey == pOutput->lastKey)) ||
180,205!
7047
      (pInput->lastKey != INT64_MIN && (pInput->lastKey == pOutput->firstKey || pInput->lastKey == pOutput->lastKey))) {
1,895,100!
UNCOV
7048
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7049
  }
7050

7051
  if (pOutput->hasResult == 0) {
1,895,100✔
7052
    irateCopyInfo(pInput, pOutput);
1,894,899✔
7053
    pOutput->hasResult = pInput->hasResult;
1,894,899✔
7054
    return TSDB_CODE_SUCCESS;
1,894,899✔
7055
  }
7056

7057
  if (pInput->firstKey != INT64_MIN) {
201!
7058
    irateTransferInfoImpl(pInput->firstKey, pInput, pOutput, true);
201✔
7059
  }
7060

7061
  if (pInput->lastKey != INT64_MIN) {
201!
7062
    irateTransferInfoImpl(pInput->lastKey, pInput, pOutput, false);
201✔
7063
  }
7064

7065
  pOutput->hasResult = pInput->hasResult;
201✔
7066
  return TSDB_CODE_SUCCESS;
201✔
7067
}
7068

7069
int32_t irateFunctionMerge(SqlFunctionCtx* pCtx) {
1,895,108✔
7070
  SInputColumnInfoData* pInput = &pCtx->input;
1,895,108✔
7071
  SColumnInfoData*      pCol = pInput->pData[0];
1,895,108✔
7072
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
1,895,108!
UNCOV
7073
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
7074
  }
7075

7076
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,895,108✔
7077
  initializeRateInfo(pCtx, pInfo, true);
1,895,108✔
7078

7079
  int32_t start = pInput->startRowIndex;
1,895,108✔
7080
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
3,790,216✔
7081
    char*      data = colDataGetData(pCol, i);
1,895,108!
7082
    SRateInfo* pInputInfo = (SRateInfo*)varDataVal(data);
1,895,108✔
7083
    initializeRateInfo(pCtx, pInfo, true);
1,895,108✔
7084
    if (pInputInfo->hasResult) {
1,895,108✔
7085
      int32_t code = irateTransferInfo(pInputInfo, pInfo);
1,895,100✔
7086
      if (code != TSDB_CODE_SUCCESS) {
1,895,100!
UNCOV
7087
        return code;
×
7088
      }
7089
    }
7090
  }
7091

7092
  if (pInfo->hasResult) {
1,895,108✔
7093
    GET_RES_INFO(pCtx)->numOfRes = 1;
1,895,100✔
7094
  }
7095

7096
  return TSDB_CODE_SUCCESS;
1,895,108✔
7097
}
7098

7099
int32_t iratePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,896,626✔
7100
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,896,626✔
7101
  SRateInfo*           pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,896,626✔
7102
  int32_t              resultBytes = getIrateInfoSize(pInfo->pkBytes);
1,896,626✔
7103
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
1,896,626!
7104

7105
  if (NULL == res) {
1,896,628!
UNCOV
7106
    return terrno;
×
7107
  }
7108
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
1,896,628✔
7109
  varDataSetLen(res, resultBytes);
1,896,628✔
7110

7111
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,896,628✔
7112
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,896,628✔
7113
  if (NULL == pCol) {
1,896,628!
UNCOV
7114
    taosMemoryFree(res);
×
UNCOV
7115
    return TSDB_CODE_OUT_OF_RANGE;
×
7116
  }
7117

7118
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
1,896,628✔
7119

7120
  taosMemoryFree(res);
1,896,628!
7121
  return code;
1,896,627✔
7122
}
7123

7124
int32_t irateFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
7,384,987✔
7125
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
7,384,987✔
7126
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
7,384,987✔
7127
  if (NULL == pCol) {
7,384,973!
UNCOV
7128
    return TSDB_CODE_OUT_OF_RANGE;
×
7129
  }
7130

7131
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,384,973✔
7132
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
7,384,973✔
7133

7134
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
7,384,973✔
7135
  double     result = doCalcRate(pInfo, (double)TSDB_TICK_PER_SECOND(pCtx->param[1].param.i));
7,384,973!
7136
  int32_t    code = colDataSetVal(pCol, pBlock->info.rows, (const char*)&result, pResInfo->isNullRes);
7,384,967✔
7137

7138
  return code;
7,384,995✔
7139
}
7140

7141
int32_t groupConstValueFunction(SqlFunctionCtx* pCtx) {
94,818,956✔
7142
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
94,818,956✔
7143
  SGroupKeyInfo*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
94,818,956✔
7144

7145
  SInputColumnInfoData* pInput = &pCtx->input;
94,818,956✔
7146
  SColumnInfoData*      pInputCol = pInput->pData[0];
94,818,956✔
7147

7148
  int32_t startIndex = pInput->startRowIndex;
94,818,956✔
7149

7150
  // escape rest of data blocks to avoid first entry to be overwritten.
7151
  if (pInfo->hasResult) {
94,818,956✔
7152
    goto _group_value_over;
10,601,441✔
7153
  }
7154

7155
  if (pInputCol->pData == NULL || colDataIsNull_s(pInputCol, startIndex)) {
168,074,203✔
7156
    pInfo->isNull = true;
2,164,007✔
7157
    pInfo->hasResult = true;
2,164,007✔
7158
    goto _group_value_over;
2,164,007✔
7159
  }
7160

7161
  char* data = colDataGetData(pInputCol, startIndex);
82,053,508!
7162
  if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
82,053,508!
7163
    (void)memcpy(pInfo->data, data,
62,315,032✔
7164
                 (pInputCol->info.type == TSDB_DATA_TYPE_JSON) ? getJsonValueLen(data) : varDataTLen(data));
62,315,032✔
7165
  } else {
7166
    (void)memcpy(pInfo->data, data, pInputCol->info.bytes);
19,738,476✔
7167
  }
7168
  pInfo->hasResult = true;
82,053,508✔
7169

7170
_group_value_over:
94,818,956✔
7171

7172
  SET_VAL(pResInfo, 1, 1);
94,818,956✔
7173
  return TSDB_CODE_SUCCESS;
94,818,956✔
7174
}
7175

7176
int32_t groupKeyFunction(SqlFunctionCtx* pCtx) { return groupConstValueFunction(pCtx); }
94,824,194✔
7177

7178
int32_t groupConstValueFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
82,867,587✔
7179
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
82,867,587✔
7180
  int32_t          code = TSDB_CODE_SUCCESS;
82,867,587✔
7181
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
82,867,587✔
7182
  if (NULL == pCol) {
82,897,824!
UNCOV
7183
    return TSDB_CODE_OUT_OF_RANGE;
×
7184
  }
7185

7186
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
82,897,824✔
7187

7188
  SGroupKeyInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
82,897,824✔
7189

7190
  if (pInfo->hasResult) {
82,897,824!
7191
    int32_t currentRow = pBlock->info.rows;
82,923,920✔
7192
    for (; currentRow < pBlock->info.rows + pResInfo->numOfRes; ++currentRow) {
166,080,313✔
7193
      code = colDataSetVal(pCol, currentRow, pInfo->data, pInfo->isNull ? true : false);
82,923,114✔
7194
      if (TSDB_CODE_SUCCESS != code) {
83,156,393!
UNCOV
7195
        return code;
×
7196
      }
7197
    }
7198
  } else {
UNCOV
7199
    pResInfo->numOfRes = 0;
×
7200
  }
7201

7202
  return code;
83,131,103✔
7203
}
7204

7205
int32_t groupKeyFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) { return groupConstValueFinalize(pCtx, pBlock); }
82,847,433✔
7206

UNCOV
7207
int32_t groupKeyCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
UNCOV
7208
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
UNCOV
7209
  SGroupKeyInfo*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
7210

7211
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
UNCOV
7212
  SGroupKeyInfo*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
7213

7214
  // escape rest of data blocks to avoid first entry to be overwritten.
UNCOV
7215
  if (pDBuf->hasResult) {
×
UNCOV
7216
    goto _group_key_over;
×
7217
  }
7218

UNCOV
7219
  if (pSBuf->isNull) {
×
UNCOV
7220
    pDBuf->isNull = true;
×
UNCOV
7221
    pDBuf->hasResult = true;
×
UNCOV
7222
    goto _group_key_over;
×
7223
  }
7224

UNCOV
7225
  if (IS_VAR_DATA_TYPE(pSourceCtx->resDataInfo.type)) {
×
UNCOV
7226
    (void)memcpy(pDBuf->data, pSBuf->data,
×
UNCOV
7227
                 (pSourceCtx->resDataInfo.type == TSDB_DATA_TYPE_JSON) ? getJsonValueLen(pSBuf->data)
×
UNCOV
7228
                                                                       : varDataTLen(pSBuf->data));
×
7229
  } else {
UNCOV
7230
    (void)memcpy(pDBuf->data, pSBuf->data, pSourceCtx->resDataInfo.bytes);
×
7231
  }
7232

UNCOV
7233
  pDBuf->hasResult = true;
×
7234

UNCOV
7235
_group_key_over:
×
7236

UNCOV
7237
  SET_VAL(pDResInfo, 1, 1);
×
UNCOV
7238
  return TSDB_CODE_SUCCESS;
×
7239
}
7240

7241
int32_t cachedLastRowFunction(SqlFunctionCtx* pCtx) {
5,646✔
7242
  int32_t numOfElems = 0;
5,646✔
7243

7244
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5,646✔
7245
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5,646✔
7246

7247
  SInputColumnInfoData* pInput = &pCtx->input;
5,646✔
7248
  SColumnInfoData*      pInputCol = pInput->pData[0];
5,646✔
7249

7250
  int32_t bytes = pInputCol->info.bytes;
5,646✔
7251
  pInfo->bytes = bytes;
5,646✔
7252

7253
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
5,646✔
7254
  pInfo->pkType = -1;
5,646✔
7255
  __compar_fn_t pkCompareFn = NULL;
5,646✔
7256
  if (pCtx->hasPrimaryKey) {
5,646✔
7257
    pInfo->pkType = pkCol->info.type;
20✔
7258
    pInfo->pkBytes = pkCol->info.bytes;
20✔
7259
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
20✔
7260
  }
7261

7262
  // TODO it traverse the different way.
7263
  // last_row function does not ignore the null value
7264
  for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
11,302✔
7265
    numOfElems++;
5,656✔
7266

7267
    bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
5,656✔
7268
    char* data = isNull ? NULL : colDataGetData(pInputCol, i);
5,656!
7269

7270
    TSKEY cts = getRowPTs(pInput->pPTS, i);
5,656!
7271
    if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
5,656✔
7272
      int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
5,315✔
7273
      if (code != TSDB_CODE_SUCCESS) {
5,315!
UNCOV
7274
        return code;
×
7275
      }
7276
      pResInfo->numOfRes = 1;
5,315✔
7277
    }
7278
  }
7279

7280
  SET_VAL(pResInfo, numOfElems, 1);
5,646!
7281
  return TSDB_CODE_SUCCESS;
5,646✔
7282
}
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