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

taosdata / TDengine / #4442

04 Jul 2025 02:10AM UTC coverage: 63.58% (+0.3%) from 63.29%
#4442

push

travis-ci

web-flow
fix:(stmt2) heap buffer overflow (#31607)

160719 of 321690 branches covered (49.96%)

Branch coverage included in aggregate %.

19 of 22 new or added lines in 3 files covered. (86.36%)

222 existing lines in 60 files now uncovered.

247667 of 320626 relevant lines covered (77.24%)

17710656.63 hits per line

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

73.36
/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,547,754,398✔
33
bool ignoreNull(int8_t ignoreOption) { return (ignoreOption & 0x2) == 0x2; }
1,886,773✔
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) {
20,345,168✔
210
  SFuncInputRowIter* pIter = &pCtx->rowIter;
20,345,168✔
211

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

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;
×
237
      pRow->rowIndex = 0;
×
238

239
      pIter->hasPrev = false;
×
240
      *res = true;
×
241
      return TSDB_CODE_SUCCESS;
×
242
    } else {
243
      *res = false;
×
244
      return TSDB_CODE_SUCCESS;
×
245
    }
246
  }
247
  if (pIter->hasPrev) {
×
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

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
      }
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);
×
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;
×
280
      while (pIter->tsList[idx] == pIter->prevBlockTsEnd) {
×
281
        ++idx;
×
282
      }
283
      pRow->ts = pIter->prevBlockTsEnd;
×
284
      if (idx == pIter->pInput->startRowIndex) {
×
285
        pRow->isDataNull = pIter->prevIsDataNull;
×
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);
×
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;
×
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];
×
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;
×
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) {
×
324
        qError("out of memory when function get input row.");
×
325
        return terrno;
×
326
      }
327
      (void)memcpy(pIter->pPrevData, colDataGetData(pIter->pDataCol, pIter->inputEndIndex),
×
328
                   pIter->pDataCol->info.bytes);
×
329
      pIter->pPrevPk = taosMemoryMalloc(pIter->pPkCol->info.bytes);
×
330
      if (NULL == pIter->pPrevPk) {
×
331
        qError("out of memory when function get input row.");
×
332
        taosMemoryFree(pIter->pPrevData);
×
333
        return terrno;
×
334
      }
335
      (void)memcpy(pIter->pPrevPk, colDataGetData(pIter->pPkCol, pIter->inputEndIndex), pIter->pPkCol->info.bytes);
×
336

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

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

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

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

373
      pIter->hasPrev = false;
2,232✔
374
      setInputRowInfo(pRow, pIter, idx, true);
2,232✔
375
      forwardToNextDiffTsRow(pIter, idx);
2,232✔
376
      return true;
2,232✔
377
    }
378
  } else {
379
    if (pIter->rowIndex <= pIter->inputEndIndex) {
33,360✔
380
      setInputRowInfo(pRow, pIter, pIter->rowIndex, true);
29,722✔
381

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

398
bool funcInputGetNextRowNoPk(SFuncInputRowIter* pIter, SFuncInputRow* pRow) {
1,615,722,774✔
399
  if (pIter->rowIndex <= pIter->inputEndIndex) {
1,615,722,774✔
400
    setInputRowInfo(pRow, pIter, pIter->rowIndex, false);
1,595,382,986✔
401
    ++pIter->rowIndex;
1,595,387,682✔
402
    return true;
1,595,387,682✔
403
  } else {
404
    return false;
20,339,788✔
405
  }
406
}
407

408
int32_t funcInputGetNextRow(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, bool* res) {
1,615,753,851✔
409
  SFuncInputRowIter* pIter = &pCtx->rowIter;
1,615,753,851✔
410
  if (pCtx->hasPrimaryKey) {
1,615,753,851✔
411
    if (pCtx->order == TSDB_ORDER_ASC) {
35,592!
412
      *res = funcInputGetNextRowAscPk(pIter, pRow);
35,592✔
413
      return TSDB_CODE_SUCCESS;
35,592✔
414
    } else {
415
      return funcInputGetNextRowDescPk(pIter, pRow, res);
×
416
    }
417
  } else {
418
    *res = funcInputGetNextRowNoPk(pIter, pRow);
1,615,718,259✔
419
    return TSDB_CODE_SUCCESS;
1,615,728,120✔
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) {
35,732,113✔
427
  if (pCtx->subsidiaries.num <= 0) {
35,732,113!
428
    return TSDB_CODE_SUCCESS;
×
429
  }
430

431
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
71,469,118✔
432
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
35,739,565✔
433

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

438
    SColumnInfoData* pSrcCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
35,739,565✔
439
    if (NULL == pSrcCol) {
35,732,447!
440
      return TSDB_CODE_OUT_OF_RANGE;
×
441
    }
442

443
    char* pData = colDataGetData(pSrcCol, rowIndex);
35,732,447!
444

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

448
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
35,732,447✔
449
    if (NULL == pDstCol) {
35,730,200!
450
      return TSDB_CODE_OUT_OF_RANGE;
×
451
    }
452
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
71,460,400✔
453
      colDataSetNULL(pDstCol, pos);
20!
454
    } else {
455
      int32_t code = colDataSetVal(pDstCol, pos, pData, false);
35,730,180✔
456
      if (TSDB_CODE_SUCCESS != code) {
35,736,985!
457
        return code;
×
458
      }
459
    }
460
  }
461
  return TSDB_CODE_SUCCESS;
35,729,553✔
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) {
750,509,700✔
470
  if (pResultInfo->initialized) {
750,509,700✔
471
    return TSDB_CODE_SUCCESS;  // already initialized
63,685✔
472
  }
473

474
  if (pCtx->pOutput != NULL) {
750,446,015!
475
    (void)memset(pCtx->pOutput, 0, (size_t)pCtx->resDataInfo.bytes);
×
476
  }
477

478
  initResultRowEntry(pResultInfo, pCtx->resDataInfo.interBufSize);
750,446,015✔
479
  return TSDB_CODE_SUCCESS;
750,446,015✔
480
}
481

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

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

495
  return code;
209,276,396✔
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) {
1,082✔
514
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,082✔
515
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,082✔
516
  if (NULL == pCol) {
1,082!
517
    return TSDB_CODE_OUT_OF_RANGE;
×
518
  }
519
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,082✔
520
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
1,082✔
521

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

525
  return code;
1,082✔
526
}
527

528
EFuncDataRequired countDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
213,068✔
529
  SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0);
213,068✔
530
  if (QUERY_NODE_COLUMN == nodeType(pParam) && PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pParam)->colId) {
213,111!
531
    return FUNC_DATA_REQUIRED_NOT_LOAD;
153,448✔
532
  }
533
  return FUNC_DATA_REQUIRED_SMA_LOAD;
59,663✔
534
}
535

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

541
static int64_t getNumOfElems(SqlFunctionCtx* pCtx) {
121,638,622✔
542
  int64_t numOfElem = 0;
121,638,622✔
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;
121,638,622✔
550
  SColumnInfoData*      pInputCol = pInput->pData[0];
121,638,622✔
551
  if (1 == pInput->numOfRows && pInput->blankFill) {
121,638,622✔
552
    return 0;
454,859✔
553
  }
554
  if (pInput->colDataSMAIsSet && pInput->totalRows == pInput->numOfRows) {
121,183,763!
555
    numOfElem = pInput->numOfRows - pInput->pColumnDataAgg[0]->numOfNull;
4,171✔
556
  } else {
557
    if (pInputCol->hasNull) {
121,179,592✔
558
      for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
431,027,348✔
559
        if (colDataIsNull(pInputCol, pInput->totalRows, i, NULL)) {
799,487,108!
560
          continue;
9,238,147✔
561
        }
562
        numOfElem += 1;
390,505,407✔
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;
89,895,798✔
568
    }
569
  }
570
  return numOfElem;
121,183,763✔
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) {
121,966,976✔
578
  int64_t numOfElem = 0;
121,966,976✔
579

580
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
121,966,976✔
581
  SInputColumnInfoData* pInput = &pCtx->input;
121,966,976✔
582

583
  int32_t type = pInput->pData[0]->info.type;
121,966,976✔
584

585
  char*   buf = GET_ROWCELL_INTERBUF(pResInfo);
121,966,976✔
586
  int64_t val = *((int64_t*)buf);
121,966,976✔
587
  if (IS_NULL_TYPE(type)) {
121,966,976✔
588
    // select count(NULL) returns 0
589
    numOfElem = 1;
144,857✔
590
    val += 0;
144,857✔
591
  } else {
592
    numOfElem = getNumOfElems(pCtx);
121,822,119✔
593
    val += numOfElem;
121,462,646✔
594
  }
595
  taosSetInt64Aligned((int64_t*)buf, val);
596

597
  if (tsCountAlwaysReturnValue) {
121,607,503!
598
    pResInfo->numOfRes = 1;
121,890,302✔
599
  } else {
600
    SET_VAL(pResInfo, val, 1);
×
601
  }
602

603
  return TSDB_CODE_SUCCESS;
121,607,503✔
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) {
23✔
620
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
23✔
621
  char*                pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
23✔
622

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

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

631
int32_t sumFunction(SqlFunctionCtx* pCtx) {
97,313,810✔
632
  int32_t numOfElem = 0;
97,313,810✔
633

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

640
  void* pSumRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
97,313,810✔
641
  SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, type);
97,313,810!
642

643
  if (IS_NULL_TYPE(type)) {
97,313,810✔
644
    numOfElem = 0;
282✔
645
    goto _sum_over;
282✔
646
  }
647

648
  if (pInput->colDataSMAIsSet) {
97,313,528✔
649
    numOfElem = pInput->numOfRows - pAgg->numOfNull;
2,884✔
650

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

669
    int32_t start = pInput->startRowIndex;
97,310,644✔
670
    int32_t numOfRows = pInput->numOfRows;
97,310,644✔
671

672
    if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
97,310,644!
673
      if (type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_BOOL) {
90,047,673✔
674
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int8_t, numOfElem);
4,243,516✔
675
      } else if (type == TSDB_DATA_TYPE_SMALLINT) {
89,171,221✔
676
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int16_t, numOfElem);
652,025✔
677
      } else if (type == TSDB_DATA_TYPE_INT) {
89,092,136✔
678
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int32_t, numOfElem);
400,765,131✔
679
      } else if (type == TSDB_DATA_TYPE_BIGINT) {
22,500,188✔
680
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int64_t, numOfElem);
82,055,405✔
681
      }
682
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
7,262,971✔
683
      if (type == TSDB_DATA_TYPE_UTINYINT) {
614✔
684
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint8_t, numOfElem);
130,039!
685
      } else if (type == TSDB_DATA_TYPE_USMALLINT) {
575✔
686
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint16_t, numOfElem);
130,047✔
687
      } else if (type == TSDB_DATA_TYPE_UINT) {
535✔
688
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint32_t, numOfElem);
133,482!
689
      } else if (type == TSDB_DATA_TYPE_UBIGINT) {
353!
690
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint64_t, numOfElem);
134,762✔
691
      }
692
    } else if (type == TSDB_DATA_TYPE_DOUBLE) {
7,262,357✔
693
      LIST_ADD_N(SUM_RES_GET_DSUM(pSumRes), pCol, start, numOfRows, double, numOfElem);
6,199,313✔
694
    } else if (type == TSDB_DATA_TYPE_FLOAT) {
5,646,290✔
695
      LIST_ADD_N(SUM_RES_GET_DSUM(pSumRes), pCol, start, numOfRows, float, numOfElem);
18,815,663✔
696
    } else if (IS_DECIMAL_TYPE(type)) {
3,126!
697
      SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, TSDB_DATA_TYPE_DECIMAL);
3,177!
698
      int32_t overflow = false;
3,177✔
699
      if (TSDB_DATA_TYPE_DECIMAL64 == type) {
3,177✔
700
        LIST_ADD_DECIMAL_N(&SUM_RES_GET_DECIMAL_SUM(pSumRes), pCol, start, numOfRows, Decimal64, numOfElem);
43,043!
701
      } else if (TSDB_DATA_TYPE_DECIMAL == type) {
3,134!
702
        LIST_ADD_DECIMAL_N(&SUM_RES_GET_DECIMAL_SUM(pSumRes), pCol, start, numOfRows, Decimal128, numOfElem);
139,834!
703
      }
704
      if (overflow) return TSDB_CODE_DECIMAL_OVERFLOW;
3,177✔
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)))) {
97,313,513!
710
    numOfElem = 0;
×
711
  }
712

713
_sum_over:
97,756,453✔
714
  if (numOfElem == 0) {
97,313,795✔
715
    if (tsCountAlwaysReturnValue && pCtx->pExpr->pExpr->_function.pFunctNode->hasOriginalFunc &&
2,684,822✔
716
        fmIsCountLikeFunc(pCtx->pExpr->pExpr->_function.pFunctNode->originalFuncId)) {
913,631✔
717
      numOfElem = 1;
8✔
718
    }
719
  }
720
  // data in the check operation are all null, not output
721
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
97,313,799✔
722
  return TSDB_CODE_SUCCESS;
97,313,799✔
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) {
39✔
786
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
39✔
787
  void*                pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
39✔
788
  int16_t              type = SUM_RES_GET_TYPE(pDBuf, pDestCtx->inputType);
39!
789

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

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

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

814
static bool funcNotSupportStringSma(SFunctionNode* pFunc) {
162,274✔
815
  SNode* pParam;
816
  switch (pFunc->funcType) {
162,274!
817
    case FUNCTION_TYPE_MAX:
162,274✔
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);
162,274✔
829
      if (pParam && nodesIsExprNode(pParam) && (IS_VAR_DATA_TYPE(((SExprNode*)pParam)->resType.type))) {
162,274!
830
        return true;
132✔
831
      }
832
      break;
162,142✔
833
    default:
×
834
      break;
×
835
  }
836
  return false;
162,142✔
837
}
838

839
EFuncDataRequired statisDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
162,274✔
840
  if (funcNotSupportStringSma(pFunc)) {
162,274✔
841
    return FUNC_DATA_REQUIRED_DATA_LOAD;
132✔
842
  }
843
  return FUNC_DATA_REQUIRED_SMA_LOAD;
162,142✔
844
}
845

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

854
  SMinmaxResInfo* buf = GET_ROWCELL_INTERBUF(pResultInfo);
59,732,447✔
855
  buf->assign = false;
59,732,447✔
856
  buf->tuplePos.pageId = -1;
59,732,447✔
857

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

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

870
int32_t minFunction(SqlFunctionCtx* pCtx) {
34,191,942✔
871
  int32_t numOfElems = 0;
34,191,942✔
872
  int32_t code = doMinMaxHelper(pCtx, 1, &numOfElems);
34,191,942✔
873
  if (code != TSDB_CODE_SUCCESS) {
34,263,621!
874
    return code;
×
875
  }
876
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
34,263,621✔
877
  return TSDB_CODE_SUCCESS;
34,263,621✔
878
}
879

880
int32_t maxFunction(SqlFunctionCtx* pCtx) {
33,356,497✔
881
  int32_t numOfElems = 0;
33,356,497✔
882
  int32_t code = doMinMaxHelper(pCtx, 0, &numOfElems);
33,356,497✔
883
  if (code != TSDB_CODE_SUCCESS) {
33,421,113!
884
    return code;
×
885
  }
886
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
33,421,113✔
887
  return TSDB_CODE_SUCCESS;
33,421,113✔
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) {
58,285,652✔
895
  int32_t code = TSDB_CODE_SUCCESS;
58,285,652✔
896

897
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
58,285,652✔
898
  SMinmaxResInfo*      pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
58,285,652✔
899

900
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
58,285,652✔
901
  int32_t currentRow = pBlock->info.rows;
58,285,652✔
902

903
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
58,285,652✔
904
  if (NULL == pCol) {
58,254,172!
905
    return TSDB_CODE_OUT_OF_RANGE;
×
906
  }
907
  pEntryInfo->isNullRes = (pEntryInfo->numOfRes == 0) ? 1 : 0;
58,254,172✔
908

909
  // NOTE: do nothing change it, for performance issue
910
  if (!pEntryInfo->isNullRes) {
58,254,172✔
911
    switch (pCol->info.type) {
49,039,892!
912
      case TSDB_DATA_TYPE_UBIGINT:
10,445,375✔
913
      case TSDB_DATA_TYPE_BIGINT:
914
        ((int64_t*)pCol->pData)[currentRow] = pRes->v;
10,445,375✔
915
        break;
10,445,375✔
916
      case TSDB_DATA_TYPE_UINT:
23,590,444✔
917
      case TSDB_DATA_TYPE_INT:
918
        colDataSetInt32(pCol, currentRow, (int32_t*)&pRes->v);
23,590,444✔
919
        break;
23,590,444✔
920
      case TSDB_DATA_TYPE_USMALLINT:
3,998,078✔
921
      case TSDB_DATA_TYPE_SMALLINT:
922
        colDataSetInt16(pCol, currentRow, (int16_t*)&pRes->v);
3,998,078✔
923
        break;
3,998,078✔
924
      case TSDB_DATA_TYPE_BOOL:
454,281✔
925
      case TSDB_DATA_TYPE_UTINYINT:
926
      case TSDB_DATA_TYPE_TINYINT:
927
        colDataSetInt8(pCol, currentRow, (int8_t*)&pRes->v);
454,281✔
928
        break;
454,281✔
929
      case TSDB_DATA_TYPE_DOUBLE:
316,687✔
930
        colDataSetDouble(pCol, currentRow, (double*)&pRes->v);
316,687✔
931
        break;
316,687✔
932
      case TSDB_DATA_TYPE_FLOAT: {
398,698✔
933
        float v = GET_FLOAT_VAL(&pRes->v);
398,698✔
934
        colDataSetFloat(pCol, currentRow, &v);
398,698✔
935
        break;
398,698✔
936
      }
937
      case TSDB_DATA_TYPE_VARBINARY:
9,887,238✔
938
      case TSDB_DATA_TYPE_VARCHAR:
939
      case TSDB_DATA_TYPE_NCHAR: {
940
        code = colDataSetVal(pCol, currentRow, pRes->str, false);
9,887,238✔
941
        if (TSDB_CODE_SUCCESS != code) {
9,906,619!
942
          return code;
×
943
        }
944
        break;
9,906,619✔
945
      }
946
      case TSDB_DATA_TYPE_DECIMAL64:
70✔
947
        code = colDataSetVal(pCol, currentRow, (const char*)&pRes->v, false);
70✔
948
        break;
70✔
949
      case TSDB_DATA_TYPE_DECIMAL:
1,050✔
950
        code = colDataSetVal(pCol, currentRow, (void*)pRes->dec, false);
1,050✔
951
        break;
1,050✔
952
    }
953
  } else {
954
    colDataSetNULL(pCol, currentRow);
9,214,280!
955
  }
956

957
  if (IS_VAR_DATA_TYPE(pCol->info.type)) taosMemoryFreeClear(pRes->str);
58,273,553!
958
  if (pCtx->subsidiaries.num > 0) {
58,303,019✔
959
    if (pEntryInfo->numOfRes > 0) {
14,689,490✔
960
      code = setSelectivityValue(pCtx, pBlock, &pRes->tuplePos, currentRow);
14,687,323✔
961
    } else {
962
      code = setNullSelectivityValue(pCtx, pBlock, currentRow);
2,167✔
963
    }
964
  }
965

966
  return code;
58,302,862✔
967
}
968

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

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

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

985
  return TSDB_CODE_SUCCESS;
2,118✔
986
}
987

988
int32_t setSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, const STuplePos* pTuplePos, int32_t rowIndex) {
266,584,771✔
989
  if (pCtx->subsidiaries.num <= 0) {
266,584,771✔
990
    return TSDB_CODE_SUCCESS;
112,506,552✔
991
  }
992

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

1004
    bool* nullList = (bool*)p;
155,946,983✔
1005
    char* pStart = (char*)(nullList + numOfCols * sizeof(bool));
155,946,983✔
1006

1007
    // todo set the offset value to optimize the performance.
1008
    for (int32_t j = 0; j < numOfCols; ++j) {
310,854,130✔
1009
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
155,965,181✔
1010
      int32_t         dstSlotId = pc->pExpr->base.resSchema.slotId;
155,965,181✔
1011

1012
      SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
155,965,181✔
1013
      if (NULL == pDstCol) {
154,923,309!
1014
        return terrno;
×
1015
      }
1016
      if (nullList[j]) {
154,927,960✔
1017
        colDataSetNULL(pDstCol, rowIndex);
261!
1018
      } else {
1019
        code = colDataSetValOrCover(pDstCol, rowIndex, pStart, false);
154,927,699✔
1020
        if (TSDB_CODE_SUCCESS != code) {
154,906,886!
1021
          return code;
×
1022
        }
1023
      }
1024
      pStart += pDstCol->info.bytes;
154,907,147✔
1025
    }
1026
  }
1027

1028
  return TSDB_CODE_SUCCESS;
154,863,209✔
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) {
55,126,996✔
1034
  if (pCtx->subsidiaries.num <= 0) {
55,126,996!
1035
    return TSDB_CODE_SUCCESS;
×
1036
  }
1037

1038
  int32_t code = TSDB_CODE_SUCCESS;
55,126,996✔
1039
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
110,178,206✔
1040
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
55,130,609✔
1041

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

1046
    SColumnInfoData* pSrcCol = taosArrayGet(pCtx->pSrcBlock->pDataBlock, srcSlotId);
55,130,609✔
1047
    if (NULL == pSrcCol) {
55,029,777!
1048
      return TSDB_CODE_OUT_OF_RANGE;
×
1049
    }
1050

1051
    char* pData = colDataGetData(pSrcCol, rowIndex);
55,029,777!
1052

1053
    // append to dest col
1054
    int32_t dstSlotId = pc->pExpr->base.resSchema.slotId;
55,029,777✔
1055

1056
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
55,029,777✔
1057
    if (NULL == pDstCol) {
54,984,872!
1058
      return TSDB_CODE_OUT_OF_RANGE;
×
1059
    }
1060

1061
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
109,969,744✔
1062
      colDataSetNULL(pDstCol, pos);
560✔
1063
    } else {
1064
      code = colDataSetVal(pDstCol, pos, pData, false);
54,984,312✔
1065
      if (TSDB_CODE_SUCCESS != code) {
55,050,650!
1066
        return code;
×
1067
      }
1068
    }
1069
  }
1070
  return code;
55,047,597✔
1071
}
1072

1073
void replaceTupleData(STuplePos* pDestPos, STuplePos* pSourcePos) { *pDestPos = *pSourcePos; }
34✔
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) {
70✔
1077
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
70✔
1078
  SMinmaxResInfo*      pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
70✔
1079

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

1084
  switch (type) {
70!
1085
    case TSDB_DATA_TYPE_UBIGINT:
×
1086
    case TSDB_DATA_TYPE_BIGINT:
1087
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int64_t) || !pDBuf->assign)) {
×
1088
        pDBuf->v = pSBuf->v;
×
1089
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1090
        pDBuf->assign = true;
×
1091
      }
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✔
1101
    case TSDB_DATA_TYPE_USMALLINT:
×
1102
    case TSDB_DATA_TYPE_SMALLINT:
1103
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int16_t) || !pDBuf->assign)) {
×
1104
        pDBuf->v = pSBuf->v;
×
1105
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1106
        pDBuf->assign = true;
×
1107
      }
1108
      break;
×
1109
    case TSDB_DATA_TYPE_BOOL:
×
1110
    case TSDB_DATA_TYPE_UTINYINT:
1111
    case TSDB_DATA_TYPE_TINYINT:
1112
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int8_t) || !pDBuf->assign)) {
×
1113
        pDBuf->v = pSBuf->v;
×
1114
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1115
        pDBuf->assign = true;
×
1116
      }
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: {
10✔
1128
      const SDecimalOps* pOps = getDecimalOps(type);
10✔
1129
      if (pSBuf->assign && ((pOps->lt(&pDBuf->v, &pSBuf->v, DECIMAL_WORD_NUM(Decimal64)) ^ isMinFunc) || !pDBuf->assign)) {
10!
1130
        pDBuf->v = pSBuf->v;
4✔
1131
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
4✔
1132
        pDBuf->assign = true;
4✔
1133
      }
1134
    } break;
10✔
1135
    case TSDB_DATA_TYPE_DECIMAL: {
10✔
1136
      const SDecimalOps* pOps = getDecimalOps(type);
10✔
1137
      if (pSBuf->assign && (pOps->lt(pDBuf->dec, pSBuf->dec, DECIMAL_WORD_NUM(Decimal)) ^ isMinFunc) || !pDBuf->assign) {
10!
1138
        memcpy(pDBuf->dec, pSBuf->dec, DECIMAL128_BYTES);
4✔
1139
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
4✔
1140
        pDBuf->assign = true;
4✔
1141
      }
1142
    } break;
10✔
1143
    default:
×
1144
      if (pSBuf->assign && (strcmp(pDBuf->str, pSBuf->str) || !pDBuf->assign)) {
×
1145
        memcpy(pDBuf->str, pSBuf->str, varDataLen(pSBuf->str));
×
1146
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1147
        pDBuf->assign = true;
×
1148
      }
1149
      break;
×
1150
  }
1151
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
70✔
1152
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
70✔
1153
  return TSDB_CODE_SUCCESS;
70✔
1154
}
1155

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

1163
int32_t getStdInfoSize() { return (int32_t)sizeof(SStdRes); }
1,004,652✔
1164

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

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

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

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

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

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

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

1196
  int32_t start = pInput->startRowIndex;
4,786,929✔
1197
  int32_t numOfRows = pInput->numOfRows;
4,786,929✔
1198

1199
  if (IS_NULL_TYPE(type)) {
4,786,929✔
1200
    numOfElem = 0;
127✔
1201
    goto _stddev_over;
127✔
1202
  }
1203

1204
  switch (type) {
4,786,802!
1205
    case TSDB_DATA_TYPE_TINYINT: {
4,451,217✔
1206
      int8_t* plist = (int8_t*)pCol->pData;
4,451,217✔
1207
      for (int32_t i = start; i < numOfRows + start; ++i) {
13,743,627✔
1208
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
9,292,410✔
1209
          continue;
241,873✔
1210
        }
1211

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

1218
      break;
4,451,217✔
1219
    }
1220

1221
    case TSDB_DATA_TYPE_SMALLINT: {
231,097✔
1222
      int16_t* plist = (int16_t*)pCol->pData;
231,097✔
1223
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
1,947,229✔
1224
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
1,716,132✔
1225
          continue;
168,731✔
1226
        }
1227

1228
        numOfElem += 1;
1,547,401✔
1229
        pStdRes->count += 1;
1,547,401✔
1230
        pStdRes->isum += plist[i];
1,547,401✔
1231
        pStdRes->quadraticISum += plist[i] * plist[i];
1,547,401✔
1232
      }
1233
      break;
231,097✔
1234
    }
1235

1236
    case TSDB_DATA_TYPE_INT: {
20,135✔
1237
      int32_t* plist = (int32_t*)pCol->pData;
20,135✔
1238
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
205,164✔
1239
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
185,029✔
1240
          continue;
37,149✔
1241
        }
1242

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

1249
      break;
20,135✔
1250
    }
1251

1252
    case TSDB_DATA_TYPE_BIGINT: {
23,764✔
1253
      int64_t* plist = (int64_t*)pCol->pData;
23,764✔
1254
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
1,787,538✔
1255
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
1,763,774✔
1256
          continue;
26,351✔
1257
        }
1258

1259
        numOfElem += 1;
1,737,423✔
1260
        pStdRes->count += 1;
1,737,423✔
1261
        pStdRes->isum += plist[i];
1,737,423✔
1262
        pStdRes->quadraticISum += plist[i] * plist[i];
1,737,423✔
1263
      }
1264
      break;
23,764✔
1265
    }
1266

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

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

1280
      break;
25✔
1281
    }
1282

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

1290
        numOfElem += 1;
80,000✔
1291
        pStdRes->count += 1;
80,000✔
1292
        pStdRes->usum += plist[i];
80,000✔
1293
        pStdRes->quadraticUSum += plist[i] * plist[i];
80,000✔
1294
      }
1295
      break;
24✔
1296
    }
1297

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

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

1311
      break;
25✔
1312
    }
1313

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

1321
        numOfElem += 1;
80,000✔
1322
        pStdRes->count += 1;
80,000✔
1323
        pStdRes->usum += plist[i];
80,000✔
1324
        pStdRes->quadraticUSum += plist[i] * plist[i];
80,000✔
1325
      }
1326
      break;
24✔
1327
    }
1328

1329
    case TSDB_DATA_TYPE_FLOAT: {
11,825✔
1330
      float* plist = (float*)pCol->pData;
11,825✔
1331
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
252,898✔
1332
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
241,073✔
1333
          continue;
110,550✔
1334
        }
1335

1336
        numOfElem += 1;
130,523✔
1337
        pStdRes->count += 1;
130,523✔
1338
        pStdRes->dsum += plist[i];
130,523✔
1339
        pStdRes->quadraticDSum += plist[i] * plist[i];
130,523✔
1340
      }
1341
      break;
11,825✔
1342
    }
1343

1344
    case TSDB_DATA_TYPE_DOUBLE: {
48,678✔
1345
      double* plist = (double*)pCol->pData;
48,678✔
1346
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
3,157,073✔
1347
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
3,108,395✔
1348
          continue;
757,351✔
1349
        }
1350

1351
        numOfElem += 1;
2,351,044✔
1352
        pStdRes->count += 1;
2,351,044✔
1353
        pStdRes->dsum += plist[i];
2,351,044✔
1354
        pStdRes->quadraticDSum += plist[i] * plist[i];
2,351,044✔
1355
      }
1356
      break;
48,678✔
1357
    }
1358

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

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

1369
static void stdTransferInfo(SStdRes* pInput, SStdRes* pOutput) {
1,002,964✔
1370
  if (IS_NULL_TYPE(pInput->type)) {
1,002,964✔
1371
    return;
80✔
1372
  }
1373
  pOutput->type = pInput->type;
1,002,884✔
1374
  if (IS_SIGNED_NUMERIC_TYPE(pOutput->type)) {
1,002,884!
1375
    pOutput->quadraticISum += pInput->quadraticISum;
1,000,690✔
1376
    pOutput->isum += pInput->isum;
1,000,690✔
1377
  } else if (IS_UNSIGNED_NUMERIC_TYPE(pOutput->type)) {
2,194!
1378
    pOutput->quadraticUSum += pInput->quadraticUSum;
1✔
1379
    pOutput->usum += pInput->usum;
1✔
1380
  } else {
1381
    pOutput->quadraticDSum += pInput->quadraticDSum;
2,193✔
1382
    pOutput->dsum += pInput->dsum;
2,193✔
1383
  }
1384

1385
  pOutput->count += pInput->count;
1,002,884✔
1386
}
1387

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

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

1397
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
1,002,879!
1398
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
1399
  }
1400

1401
  SStdRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,002,879✔
1402

1403
  for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
2,005,840✔
1404
    if (colDataIsNull_s(pCol, i)) continue;
2,005,922!
1405
    char*    data = colDataGetData(pCol, i);
1,002,961!
1406
    SStdRes* pInputInfo = (SStdRes*)varDataVal(data);
1,002,961✔
1407
    stdTransferInfo(pInputInfo, pInfo);
1,002,961✔
1408
  }
1409

1410
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
1,002,879✔
1411
  return TSDB_CODE_SUCCESS;
1,002,879✔
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,717,308✔
1482
  SInputColumnInfoData* pInput = &pCtx->input;
4,717,308✔
1483
  SStdRes*              pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4,717,308✔
1484
  int32_t               type = pStddevRes->type;
4,717,308✔
1485
  double                avg;
1486

1487
  if (pStddevRes->count == 0) {
4,717,308✔
1488
    GET_RES_INFO(pCtx)->numOfRes = 0;
74,124✔
1489
    return functionFinalize(pCtx, pBlock);
74,124✔
1490
  }
1491

1492
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
4,643,184!
1493
    avg = pStddevRes->isum / ((double)pStddevRes->count);
4,618,862✔
1494
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticISum / ((double)pStddevRes->count) - avg * avg));
4,618,862✔
1495
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
24,322!
1496
    avg = pStddevRes->usum / ((double)pStddevRes->count);
10✔
1497
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticUSum / ((double)pStddevRes->count) - avg * avg));
10✔
1498
  } else {
1499
    avg = pStddevRes->dsum / ((double)pStddevRes->count);
24,312✔
1500
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticDSum / ((double)pStddevRes->count) - avg * avg));
24,312✔
1501
  }
1502

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

1508
  return functionFinalize(pCtx, pBlock);
4,643,184✔
1509
}
1510

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

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

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

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

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

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

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

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

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

1562
  taosMemoryFree(res);
1,002,759!
1563
  return code;
1,002,759✔
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,221✔
1582
  pEnv->calcMemSize = sizeof(SLeastSQRInfo);
42,221✔
1583
  return true;
42,221✔
1584
}
1585

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

1594
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
5,631,010✔
1595

1596
  GET_TYPED_DATA(pInfo->startVal, double, pCtx->param[1].param.nType, &pCtx->param[1].param.i,
5,631,010!
1597
                 typeGetTypeModFromCol(pCtx->param[1].pCol));
1598
  GET_TYPED_DATA(pInfo->stepVal, double, pCtx->param[2].param.nType, &pCtx->param[2].param.i,
5,631,009!
1599
                 typeGetTypeModFromCol(pCtx->param[2].pCol));
1600
  return TSDB_CODE_SUCCESS;
5,631,006✔
1601
}
1602

1603
int32_t leastSQRFunction(SqlFunctionCtx* pCtx) {
6,774,538✔
1604
  int32_t numOfElem = 0;
6,774,538✔
1605

1606
  SInputColumnInfoData* pInput = &pCtx->input;
6,774,538✔
1607
  int32_t               type = pInput->pData[0]->info.type;
6,774,538✔
1608

1609
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
6,774,538✔
1610

1611
  SColumnInfoData* pCol = pInput->pData[0];
6,774,538✔
1612

1613
  double(*param)[3] = pInfo->matrix;
6,774,538✔
1614
  double x = pInfo->startVal;
6,774,538✔
1615

1616
  int32_t start = pInput->startRowIndex;
6,774,538✔
1617
  int32_t numOfRows = pInput->numOfRows;
6,774,538✔
1618

1619
  switch (type) {
6,774,538!
1620
    case TSDB_DATA_TYPE_TINYINT: {
13,682✔
1621
      int8_t* plist = (int8_t*)pCol->pData;
13,682✔
1622
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
673,169✔
1623
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
659,487✔
1624
          continue;
433,503✔
1625
        }
1626
        numOfElem++;
225,984✔
1627
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
225,984✔
1628
      }
1629
      break;
13,682✔
1630
    }
1631
    case TSDB_DATA_TYPE_SMALLINT: {
10,979✔
1632
      int16_t* plist = (int16_t*)pCol->pData;
10,979✔
1633
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
626,427✔
1634
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
615,448✔
1635
          continue;
150,907✔
1636
        }
1637

1638
        numOfElem++;
464,541✔
1639
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
464,541✔
1640
      }
1641
      break;
10,979✔
1642
    }
1643

1644
    case TSDB_DATA_TYPE_INT: {
7,161✔
1645
      int32_t* plist = (int32_t*)pCol->pData;
7,161✔
1646
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
298,688✔
1647
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
291,527✔
1648
          continue;
3,547✔
1649
        }
1650

1651
        numOfElem++;
287,980✔
1652
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
287,980✔
1653
      }
1654
      break;
7,161✔
1655
    }
1656

1657
    case TSDB_DATA_TYPE_BIGINT: {
4,972,575✔
1658
      int64_t* plist = (int64_t*)pCol->pData;
4,972,575✔
1659
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
18,450,835✔
1660
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
13,478,260✔
1661
          continue;
2,260✔
1662
        }
1663

1664
        numOfElem++;
13,476,000✔
1665
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
13,476,000✔
1666
      }
1667
      break;
4,972,575✔
1668
    }
1669

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

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

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

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

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

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

1720
    case TSDB_DATA_TYPE_FLOAT: {
1,763,551✔
1721
      float* plist = (float*)pCol->pData;
1,763,551✔
1722
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
6,165,859✔
1723
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
4,402,308✔
1724
          continue;
150,679✔
1725
        }
1726

1727
        numOfElem++;
4,251,629✔
1728
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
4,251,629✔
1729
      }
1730
      break;
1,763,551✔
1731
    }
1732

1733
    case TSDB_DATA_TYPE_DOUBLE: {
5,978✔
1734
      double* plist = (double*)pCol->pData;
5,978✔
1735
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
96,938✔
1736
        if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
90,960✔
1737
          continue;
2,260✔
1738
        }
1739

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

1751
    default:
×
1752
      break;
×
1753
  }
1754

1755
  pInfo->startVal = x;
6,774,538✔
1756
  pInfo->num += numOfElem;
6,774,538✔
1757

1758
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
6,774,538✔
1759

1760
  return TSDB_CODE_SUCCESS;
6,774,538✔
1761
}
1762

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

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

1774
  if (0 == pInfo->num) {
5,618,877✔
1775
    colDataSetNULL(pCol, currentRow);
33,739!
1776
    return TSDB_CODE_SUCCESS;
33,739✔
1777
  }
1778

1779
  double(*param)[3] = pInfo->matrix;
5,585,138✔
1780

1781
  param[1][1] = (double)pInfo->num;
5,585,138✔
1782
  param[1][0] = param[0][1];
5,585,138✔
1783

1784
  double param00 = param[0][0] - param[1][0] * (param[0][1] / param[1][1]);
5,585,138✔
1785
  double param02 = param[0][2] - param[1][2] * (param[0][1] / param[1][1]);
5,585,138✔
1786

1787
  if (0 == param00) {
5,585,138✔
1788
    colDataSetNULL(pCol, currentRow);
3,773,234!
1789
    return TSDB_CODE_SUCCESS;
3,773,234✔
1790
  }
1791

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

1797
  param12 /= param[1][1];
1,811,904✔
1798

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

1814
  int32_t code = colDataSetVal(pCol, currentRow, buf, pResInfo->isNullRes);
1,811,904✔
1815

1816
  return code;
1,811,904✔
1817
}
1818

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

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

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

1846
int32_t percentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
6,658✔
1847
  if (pResultInfo->initialized) {
6,658!
1848
    return TSDB_CODE_SUCCESS;
×
1849
  }
1850
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
6,658!
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);
6,658✔
1856
  SET_DOUBLE_VAL(&pInfo->minval, DBL_MAX);
6,658✔
1857
  SET_DOUBLE_VAL(&pInfo->maxval, -DBL_MAX);
6,658✔
1858
  pInfo->numOfElems = 0;
6,658✔
1859

1860
  return TSDB_CODE_SUCCESS;
6,658✔
1861
}
1862

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

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

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

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

1885
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,580,598✔
1886
  if (pCtx->scanFlag == MAIN_SCAN && pInfo->stage == 0) {
2,580,598✔
1887
    pInfo->stage += 1;
6,658✔
1888

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

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

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

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

1925
      pInfo->numOfElems += (pInput->numOfRows - pAgg->numOfNull);
1,278,396✔
1926
    } else {
1927
      // check the valid data one by one
1928
      int32_t start = pInput->startRowIndex;
11,904✔
1929
      for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
14,108,502✔
1930
        if (colDataIsNull_f(pCol->nullbitmap, i)) {
14,096,598✔
1931
          continue;
4,200✔
1932
        }
1933

1934
        char* data = colDataGetData(pCol, i);
14,092,398!
1935

1936
        double v = 0;
14,092,398✔
1937
        GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
14,092,398!
1938
        if (v < GET_DOUBLE_VAL(&pInfo->minval)) {
14,092,398✔
1939
          SET_DOUBLE_VAL(&pInfo->minval, v);
3,088✔
1940
        }
1941

1942
        if (v > GET_DOUBLE_VAL(&pInfo->maxval)) {
14,092,398✔
1943
          SET_DOUBLE_VAL(&pInfo->maxval, v);
411,172✔
1944
        }
1945

1946
        pInfo->numOfElems += 1;
14,092,398✔
1947
      }
1948
    }
1949
  } else {
1950
    // the second stage, calculate the true percentile value
1951
    int32_t start = pInput->startRowIndex;
1,286,496✔
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!
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!
1961
        tMemBucketDestroy(&(pInfo->pMemBucket));
×
1962
        return code;
×
1963
      }
1964
    }
1965

1966
    SET_VAL(pResInfo, numOfElems, 1);
1,286,496!
1967
  }
1968

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

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

1977
  int32_t code = 0;
6,658✔
1978
  double  v = 0;
6,658✔
1979

1980
  tMemBucket** pMemBucket = &ppInfo->pMemBucket;
6,658✔
1981
  if ((*pMemBucket) != NULL && (*pMemBucket)->total > 0) {  // check for null
6,658!
1982
    if (pCtx->numOfParams > 2) {
2,856✔
1983
      char buf[3200] = {0};
34✔
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;
34✔
1987

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

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

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

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

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

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

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

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

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

2031
      tMemBucketDestroy(pMemBucket);
2,822✔
2032
      return functionFinalize(pCtx, pBlock);
2,822✔
2033
    }
2034
  } else {
2035
    return functionFinalize(pCtx, pBlock);
3,802✔
2036
  }
2037

2038
_fin_error:
×
2039

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

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

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

2059
static int8_t getApercentileAlgo(char* algoStr) {
15,694,398✔
2060
  int8_t algoType;
2061
  if (strcasecmp(algoStr, "default") == 0) {
15,694,398✔
2062
    algoType = APERCT_ALGO_DEFAULT;
11,453✔
2063
  } else if (strcasecmp(algoStr, "t-digest") == 0) {
15,682,945✔
2064
    algoType = APERCT_ALGO_TDIGEST;
15,682,942✔
2065
  } else {
2066
    algoType = APERCT_ALGO_UNKNOWN;
3✔
2067
  }
2068

2069
  return algoType;
15,694,398✔
2070
}
2071

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

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

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

2089
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
15,885,166✔
2090

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

2095
  if (pCtx->numOfParams == 2) {
15,885,166✔
2096
    pInfo->algo = APERCT_ALGO_DEFAULT;
190,769✔
2097
  } else if (pCtx->numOfParams == 3) {
15,694,397!
2098
    pInfo->algo = getApercentileAlgo(varDataVal(pCtx->param[2].param.pz));
15,694,398✔
2099
    if (pInfo->algo == APERCT_ALGO_UNKNOWN) {
15,694,396!
2100
      return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
2101
    }
2102
  }
2103

2104
  char* tmp = (char*)pInfo + sizeof(SAPercentileInfo);
15,885,164✔
2105
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
15,885,164✔
2106
    pInfo->pTDigest = tdigestNewFrom(tmp, COMPRESSION);
15,682,944✔
2107
  } else {
2108
    buildHistogramInfo(pInfo);
202,220✔
2109
    pInfo->pHisto = tHistogramCreateFrom(tmp, MAX_HISTOGRAM_BIN);
202,219✔
2110
    qDebug("%s set up histogram, numOfElems:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
202,201✔
2111
           pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2112
  }
2113

2114
  return TSDB_CODE_SUCCESS;
15,885,153✔
2115
}
2116

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

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

2125
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
12,643,346✔
2126

2127
  int32_t start = pInput->startRowIndex;
12,643,346✔
2128
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
12,643,346✔
2129
    buildTDigestInfo(pInfo);
12,429,342✔
2130
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
12,429,342✔
2131
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
39,455,156✔
2132
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
27,025,807✔
2133
        continue;
362,908✔
2134
      }
2135
      numOfElems += 1;
26,662,899✔
2136
      char* data = colDataGetData(pCol, i);
26,662,899!
2137

2138
      double  v = 0;  // value
26,662,899✔
2139
      int64_t w = 1;  // weigth
26,662,899✔
2140
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
26,662,899!
2141
      int32_t code = tdigestAdd(pInfo->pTDigest, v, w);
26,662,899✔
2142
      if (code != TSDB_CODE_SUCCESS) {
26,662,909!
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);
214,004✔
2150
    qDebug("%s before add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
213,998✔
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) {
2,729,865✔
2154
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
2,515,630✔
2155
        continue;
1,024,970✔
2156
      }
2157
      numOfElems += 1;
1,490,660✔
2158
      char* data = colDataGetData(pCol, i);
1,490,660!
2159

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

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

2173
  SET_VAL(pResInfo, numOfElems, 1);
12,643,360✔
2174
  return TSDB_CODE_SUCCESS;
12,643,360✔
2175
}
2176

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

2184
    if (pInput->pTDigest->num_centroids == 0 && pInput->pTDigest->num_buffered_pts == 0) {
3,258,541✔
2185
      return TSDB_CODE_SUCCESS;
2✔
2186
    }
2187

2188
    if (hasRes) {
3,258,539✔
2189
      *hasRes = true;
3,258,537✔
2190
    }
2191

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

2196
    if (pTDigest->num_centroids <= 0 && pTDigest->num_buffered_pts == 0) {
3,258,539!
2197
      (void)memcpy(pTDigest, pInput->pTDigest, (size_t)TDIGEST_SIZE(COMPRESSION));
3,258,537✔
2198
      tdigestAutoFill(pTDigest, COMPRESSION);
3,258,537✔
2199
    } else {
2200
      int32_t code = tdigestMerge(pTDigest, pInput->pTDigest);
2✔
2201
      if (TSDB_CODE_SUCCESS != code) {
2!
2202
        return code;
×
2203
      }
2204
    }
2205
  } else {
2206
    buildHistogramInfo(pInput);
8,458✔
2207
    if (pInput->pHisto->numOfElems <= 0) {
8,458✔
2208
      return TSDB_CODE_SUCCESS;
157✔
2209
    }
2210

2211
    if (hasRes) {
8,301✔
2212
      *hasRes = true;
8,299✔
2213
    }
2214

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

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

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

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

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

2246
int32_t apercentileFunctionMerge(SqlFunctionCtx* pCtx) {
3,266,915✔
2247
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
3,266,915✔
2248

2249
  SInputColumnInfoData* pInput = &pCtx->input;
3,266,915✔
2250

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

2256
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
3,266,915✔
2257

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

2260
  bool    hasRes = false;
3,266,915✔
2261
  int32_t start = pInput->startRowIndex;
3,266,915✔
2262
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
6,533,910✔
2263
    char* data = colDataGetData(pCol, i);
3,266,995!
2264

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

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

2278
  SET_VAL(pResInfo, hasRes ? 1 : 0, 1);
3,266,915✔
2279
  return TSDB_CODE_SUCCESS;
3,266,915✔
2280
}
2281

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

2286
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
12,604,505✔
2287
    buildTDigestInfo(pInfo);
12,424,412✔
2288
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
12,424,412✔
2289
    if (pInfo->pTDigest->size > 0) {
12,424,412!
2290
      pInfo->result = tdigestQuantile(pInfo->pTDigest, pInfo->percent / 100);
12,424,412✔
2291
    } else {  // no need to free
2292
      // setNull(pCtx->pOutput, pCtx->outputType, pCtx->outputBytes);
2293
      return TSDB_CODE_SUCCESS;
×
2294
    }
2295
  } else {
2296
    buildHistogramInfo(pInfo);
180,093✔
2297
    if (pInfo->pHisto->numOfElems > 0) {
180,089✔
2298
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
120,958✔
2299
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2300

2301
      double  ratio[] = {pInfo->percent};
120,958✔
2302
      double* res = NULL;
120,958✔
2303
      int32_t code = tHistogramUniform(pInfo->pHisto, ratio, 1, &res);
120,958✔
2304
      if (TSDB_CODE_SUCCESS != code) {
120,958!
2305
        taosMemoryFree(res);
×
2306
        return code;
×
2307
      }
2308
      pInfo->result = *res;
120,958✔
2309
      // memcpy(pCtx->pOutput, res, sizeof(double));
2310
      taosMemoryFree(res);
120,958✔
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__,
59,131✔
2315
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries);
2316
    }
2317
  }
2318

2319
  return functionFinalize(pCtx, pBlock);
12,604,495✔
2320
}
2321

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

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

2332
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
3,266,763✔
2333
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
3,258,539✔
2334
    varDataSetLen(res, resultBytes);
3,258,539✔
2335
  } else {
2336
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
8,224✔
2337
    varDataSetLen(res, resultBytes);
8,224✔
2338
  }
2339

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

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

2349
  taosMemoryFree(res);
3,266,762!
2350
  return code;
3,266,763✔
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!
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) {
5,473✔
2373
  char numVal[8] = {0};
5,473✔
2374
  switch (pkType) {
5,473✔
2375
    case TSDB_DATA_TYPE_INT:
960✔
2376
      *(int32_t*)numVal = (int32_t)VALUE_GET_TRIVIAL_DATUM(pVal);
960✔
2377
      break;
960✔
2378
    case TSDB_DATA_TYPE_UINT:
854✔
2379
      *(uint32_t*)numVal = (uint32_t)VALUE_GET_TRIVIAL_DATUM(pVal);
854✔
2380
      break;
854✔
2381
    case TSDB_DATA_TYPE_BIGINT:
1,007✔
2382
      *(int64_t*)numVal = (int64_t)VALUE_GET_TRIVIAL_DATUM(pVal);
1,007✔
2383
      break;
1,007✔
2384
    case TSDB_DATA_TYPE_UBIGINT:
1,061✔
2385
      *(uint64_t*)numVal = (uint64_t)VALUE_GET_TRIVIAL_DATUM(pVal);
1,061✔
2386
      break;
1,061✔
2387
    default:
1,591✔
2388
      break;
1,591✔
2389
  }
2390
  char*         blockData = (IS_NUMERIC_TYPE(pkType)) ? (char*)numVal : (char*)pVal->pData;
5,473!
2391
  __compar_fn_t fn = getKeyComparFunc(pkType, order);
5,473✔
2392
  return fn(pkData, blockData);
5,477✔
2393
}
2394

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

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

2403
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
10,176✔
2404
  if (pResult->hasResult) {
10,176✔
2405
    if (pResult->pkBytes > 0) {
10,094✔
2406
      pResult->pkData = pResult->buf + pResult->bytes;
3,389✔
2407
    } else {
2408
      pResult->pkData = NULL;
6,705✔
2409
    }
2410
    if (pResult->ts < pBlockInfo->window.skey) {
10,094✔
2411
      return FUNC_DATA_REQUIRED_NOT_LOAD;
5,997✔
2412
    } else if (pResult->ts == pBlockInfo->window.skey) {
4,097✔
2413
      if (NULL == pResult->pkData) {
2,117✔
2414
        return FUNC_DATA_REQUIRED_NOT_LOAD;
476✔
2415
      }
2416
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 0, TSDB_ORDER_ASC) < 0) {
1,641✔
2417
        return FUNC_DATA_REQUIRED_NOT_LOAD;
216✔
2418
      }
2419
    }
2420
    return FUNC_DATA_REQUIRED_DATA_LOAD;
3,404✔
2421
  } else {
2422
    return FUNC_DATA_REQUIRED_DATA_LOAD;
82✔
2423
  }
2424
}
2425

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

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

2434
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
20,705✔
2435
  if (pResult->hasResult) {
20,705✔
2436
    if (pResult->pkBytes > 0) {
20,628✔
2437
      pResult->pkData = pResult->buf + pResult->bytes;
7,153✔
2438
    } else {
2439
      pResult->pkData = NULL;
13,475✔
2440
    }
2441
    if (pResult->ts > pBlockInfo->window.ekey) {
20,628✔
2442
      return FUNC_DATA_REQUIRED_NOT_LOAD;
12,930✔
2443
    } else if (pResult->ts == pBlockInfo->window.ekey && pResult->pkData) {
7,698✔
2444
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 1, TSDB_ORDER_DESC) < 0) {
3,836✔
2445
        return FUNC_DATA_REQUIRED_NOT_LOAD;
1,140✔
2446
      }
2447
    }
2448
    return FUNC_DATA_REQUIRED_DATA_LOAD;
6,558✔
2449
  } else {
2450
    return FUNC_DATA_REQUIRED_DATA_LOAD;
77✔
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; }
67,319,691✔
2456

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

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

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

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

2482
  return *(TSKEY*)colDataGetData(pTsColInfo, rowIndex);
324,216,191!
2483
}
2484

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

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

2499
static int32_t prepareBuf(SqlFunctionCtx* pCtx) {
258,446,090✔
2500
  if (pCtx->subsidiaries.rowLen == 0) {
258,446,090✔
2501
    int32_t rowLen = 0;
668,345✔
2502
    for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
1,346,094✔
2503
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
677,749✔
2504
      rowLen += pc->pExpr->base.resSchema.bytes;
677,749✔
2505
    }
2506

2507
    pCtx->subsidiaries.rowLen = rowLen + pCtx->subsidiaries.num * sizeof(bool);
668,345✔
2508
    pCtx->subsidiaries.buf = taosMemoryMalloc(pCtx->subsidiaries.rowLen);
668,345!
2509
    if (NULL == pCtx->subsidiaries.buf) {
662,829!
2510
      return terrno;
×
2511
    }
2512
  }
2513
  return TSDB_CODE_SUCCESS;
258,440,574✔
2514
}
2515

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

2520
  if (pCtx->subsidiaries.num <= 0) {
201,171,789✔
2521
    return TSDB_CODE_SUCCESS;
104,102,356✔
2522
  }
2523

2524
  if (!pInfo->hasResult) {
97,069,433✔
2525
    code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
81,107,110✔
2526
  } else if (!noElements) {
15,962,323!
2527
    code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
16,035,899✔
2528
  } else { } // dothing
2529

2530
  return code;
97,005,279✔
2531
}
2532

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

2538
  if (IS_VAR_DATA_TYPE(type)) {
95,214,153!
2539
    if (type == TSDB_DATA_TYPE_JSON) {
14,726,724!
2540
      pInfo->bytes = getJsonValueLen(pData);
×
2541
    } else {
2542
      pInfo->bytes = varDataTLen(pData);
14,726,724✔
2543
    }
2544
  }
2545

2546
  (void)memcpy(pInfo->buf, pData, pInfo->bytes);
95,214,153✔
2547
  if (pkData != NULL) {
95,214,153✔
2548
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
1,430,913!
2549
      if (pInfo->pkType == TSDB_DATA_TYPE_JSON) {
466,961!
2550
        pInfo->pkBytes = getJsonValueLen(pkData);
×
2551
      } else {
2552
        pInfo->pkBytes = varDataTLen(pkData);
466,961✔
2553
      }
2554
    }
2555
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
1,430,913✔
2556
    pInfo->pkData = pInfo->buf + pInfo->bytes;
1,430,913✔
2557
  }
2558

2559
  pInfo->ts = currentTs;
95,214,153✔
2560
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
95,214,153✔
2561
  if (code != TSDB_CODE_SUCCESS) {
95,271,909!
2562
    return code;
×
2563
  }
2564

2565
  pInfo->hasResult = true;
95,271,909✔
2566
  return TSDB_CODE_SUCCESS;
95,271,909✔
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) {
52,882,230✔
2572
  int32_t numOfElems = 0;
52,882,230✔
2573

2574
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
52,882,230✔
2575
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
52,882,230✔
2576

2577
  SInputColumnInfoData* pInput = &pCtx->input;
52,882,230✔
2578
  SColumnInfoData*      pInputCol = pInput->pData[0];
52,882,230✔
2579

2580
  pInfo->bytes = pInputCol->info.bytes;
52,882,230✔
2581

2582
  if (IS_NULL_TYPE(pInputCol->info.type)) {
52,882,230✔
2583
    return TSDB_CODE_SUCCESS;
5,068✔
2584
  }
2585

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

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

2607
  SColumnDataAgg* pColAgg = (pInput->colDataSMAIsSet) ? pInput->pColumnDataAgg[0] : NULL;
52,875,705!
2608

2609
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
52,875,705!
2610
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
52,875,705!
2611

2612
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
52,875,705✔
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;
52,875,705✔
2666

2667
  int     from = -1;
52,875,705✔
2668
  int32_t i = -1;
52,875,705✔
2669
  while (funcInputGetNextRowIndex(pInput, from, true, &i, &from)) {
186,707,071✔
2670
    if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
173,464,222!
2671
      continue;
129,159✔
2672
    }
2673

2674
    numOfElems++;
133,655,599✔
2675
    char* data = colDataGetData(pInputCol, i);
133,655,599!
2676
    char* pkData = NULL;
133,655,599✔
2677
    if (pCtx->hasPrimaryKey) {
133,655,599✔
2678
      pkData = colDataGetData(pkCol, i);
1,396,013!
2679
    }
2680
    TSKEY cts = pts[i];
133,655,599✔
2681
    if (pResInfo->numOfRes == 0 || pInfo->ts > cts ||
133,655,599✔
2682
        (pInfo->ts == cts && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
88,654,913!
2683
      int32_t code = doSaveCurrentVal(pCtx, i, cts, pkData, pInputCol->info.type, data);
45,000,686✔
2684
      if (code != TSDB_CODE_SUCCESS) {
45,047,290!
2685
        return code;
×
2686
      }
2687
      pResInfo->numOfRes = 1;
45,047,290✔
2688
    }
2689
  }
2690
#endif
2691

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

2704
int32_t lastFunction(SqlFunctionCtx* pCtx) {
44,316,369✔
2705
  int32_t numOfElems = 0;
44,316,369✔
2706

2707
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
44,316,369✔
2708
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
44,316,369✔
2709

2710
  SInputColumnInfoData* pInput = &pCtx->input;
44,316,369✔
2711
  SColumnInfoData*      pInputCol = pInput->pData[0];
44,316,369✔
2712

2713
  int32_t type = pInputCol->info.type;
44,316,369✔
2714
  int32_t bytes = pInputCol->info.bytes;
44,316,369✔
2715

2716
  if (IS_NULL_TYPE(type)) {
44,316,369✔
2717
    return TSDB_CODE_SUCCESS;
5,071✔
2718
  }
2719
  pInfo->bytes = bytes;
44,311,298✔
2720

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

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

2742
  SColumnDataAgg* pColAgg = (pInput->colDataSMAIsSet) ? pInput->pColumnDataAgg[0] : NULL;
44,371,597!
2743

2744
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
44,371,597!
2745
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
44,371,597!
2746

2747
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
44,371,597✔
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;
44,371,597✔
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) {
70,980,589✔
2803
    numOfElems = 1;
26,639,472✔
2804

2805
    int32_t round = pInput->numOfRows >> 2;
26,639,472✔
2806
    int32_t reminder = pInput->numOfRows & 0x03;
26,639,472✔
2807

2808
    for (int32_t i = pInput->startRowIndex, tick = 0; tick < round; i += 4, tick += 1) {
42,038,728✔
2809
      int64_t cts = pts[i];
15,400,000✔
2810
      int32_t chosen = i;
15,400,000✔
2811

2812
      if (cts < pts[i + 1]) {
15,400,000✔
2813
        cts = pts[i + 1];
3,055,785✔
2814
        chosen = i + 1;
3,055,785✔
2815
      }
2816

2817
      if (cts < pts[i + 2]) {
15,400,000✔
2818
        cts = pts[i + 2];
3,055,964✔
2819
        chosen = i + 2;
3,055,964✔
2820
      }
2821

2822
      if (cts < pts[i + 3]) {
15,400,000✔
2823
        cts = pts[i + 3];
3,055,892✔
2824
        chosen = i + 3;
3,055,892✔
2825
      }
2826

2827
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
15,400,000✔
2828
        char*   data = colDataGetData(pInputCol, chosen);
3,124,733!
2829
        int32_t code = doSaveCurrentVal(pCtx, chosen, cts, NULL, type, data);
3,124,733✔
2830
        if (code != TSDB_CODE_SUCCESS) {
3,123,989!
2831
          return code;
×
2832
        }
2833
        pResInfo->numOfRes = 1;
3,123,989✔
2834
      }
2835
    }
2836

2837
    for (int32_t i = pInput->startRowIndex + round * 4; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
58,968,625✔
2838
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i]) {
32,359,633✔
2839
        char*   data = colDataGetData(pInputCol, i);
18,929,337!
2840
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], NULL, type, data);
18,929,337✔
2841
        if (code != TSDB_CODE_SUCCESS) {
18,899,601!
2842
          return code;
×
2843
        }
2844
        pResInfo->numOfRes = 1;
18,899,601✔
2845
      }
2846
    }
2847
  } else {
2848
    int     from = -1;
17,732,125✔
2849
    int32_t i = -1;
17,732,125✔
2850
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
163,473,976✔
2851
      if (colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
291,497,296✔
2852
        continue;
5,660,510✔
2853
      }
2854

2855
      numOfElems++;
140,088,138✔
2856
      char* pkData = NULL;
140,088,138✔
2857
      if (pCtx->hasPrimaryKey) {
140,088,138✔
2858
        pkData = colDataGetData(pkCol, i);
101,456,874!
2859
      }
2860
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i] ||
140,088,138✔
2861
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
111,990,464!
2862
        char*   data = colDataGetData(pInputCol, i);
28,147,457!
2863
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], pkData, type, data);
28,147,457✔
2864
        if (code != TSDB_CODE_SUCCESS) {
28,140,662!
2865
          return code;
×
2866
        }
2867
        pResInfo->numOfRes = 1;
28,140,662✔
2868
      }
2869
    }
2870
  }
2871
#endif
2872

2873
#endif
2874

2875
  // save selectivity value for column consisted of all null values
2876
  if (numOfElems == 0) {
44,528,815✔
2877
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
4,104,373✔
2878
    if (code != TSDB_CODE_SUCCESS) {
4,097,450!
2879
      return code;
×
2880
    }
2881
    pInfo->nullTupleSaved = true;
4,097,450✔
2882
  }
2883

2884
  return TSDB_CODE_SUCCESS;
44,521,892✔
2885
}
2886

2887
static bool firstLastTransferInfoImpl(SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst) {
61,060,033✔
2888
  if (!pInput->hasResult) {
61,060,033✔
2889
    return false;
2✔
2890
  }
2891
  __compar_fn_t pkCompareFn = NULL;
61,060,031✔
2892
  if (pInput->pkData) {
61,060,031✔
2893
    pkCompareFn = getKeyComparFunc(pInput->pkType, (isFirst) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC);
37,318✔
2894
  }
2895
  if (pOutput->hasResult) {
61,061,654✔
2896
    if (isFirst) {
15,390,453✔
2897
      if (pInput->ts > pOutput->ts ||
8,618,763✔
2898
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
8,618,202✔
2899
        return false;
955✔
2900
      }
2901
    } else {
2902
      if (pInput->ts < pOutput->ts ||
6,771,690✔
2903
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
4,656,510✔
2904
        return false;
2,116,900✔
2905
      }
2906
    }
2907
  }
2908

2909
  pOutput->isNull = pInput->isNull;
58,943,799✔
2910
  pOutput->ts = pInput->ts;
58,943,799✔
2911
  pOutput->bytes = pInput->bytes;
58,943,799✔
2912
  pOutput->pkType = pInput->pkType;
58,943,799✔
2913

2914
  (void)memcpy(pOutput->buf, pInput->buf, pOutput->bytes);
58,943,799✔
2915
  if (pInput->pkData) {
58,943,799✔
2916
    pOutput->pkBytes = pInput->pkBytes;
35,202✔
2917
    (void)memcpy(pOutput->buf + pOutput->bytes, pInput->pkData, pOutput->pkBytes);
35,202✔
2918
    pOutput->pkData = pOutput->buf + pOutput->bytes;
35,202✔
2919
  }
2920
  return true;
58,943,799✔
2921
}
2922

2923
static int32_t firstLastTransferInfo(SqlFunctionCtx* pCtx, SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst,
61,059,562✔
2924
                                     int32_t rowIndex) {
2925
  if (firstLastTransferInfoImpl(pInput, pOutput, isFirst)) {
61,059,562✔
2926
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pOutput, false);
58,943,560✔
2927
    if (TSDB_CODE_SUCCESS != code) {
58,935,936!
2928
      return code;
×
2929
    }
2930
    pOutput->hasResult = true;
58,935,936✔
2931
  }
2932
  return TSDB_CODE_SUCCESS;
61,051,641✔
2933
}
2934

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

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

2944
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
45,700,947!
2945
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
2946
  }
2947

2948
  SFirstLastRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
45,700,947✔
2949

2950
  int32_t start = pInput->startRowIndex;
45,700,947✔
2951
  int32_t numOfElems = 0;
45,700,947✔
2952

2953
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
109,041,344✔
2954
    if (colDataIsNull_s(pCol, i)) {
126,704,516✔
2955
      continue;
2,289,831✔
2956
    }
2957
    char*          data = colDataGetData(pCol, i);
61,062,427!
2958
    SFirstLastRes* pInputInfo = (SFirstLastRes*)varDataVal(data);
61,062,427✔
2959
    if (pCtx->hasPrimaryKey) {
61,062,427✔
2960
      pInputInfo->pkData = pInputInfo->buf + pInputInfo->bytes;
37,318✔
2961
    } else {
2962
      pInputInfo->pkData = NULL;
61,025,109✔
2963
    }
2964

2965
    int32_t code = firstLastTransferInfo(pCtx, pInputInfo, pInfo, isFirstQuery, i);
61,062,427✔
2966
    if (code != TSDB_CODE_SUCCESS) {
61,050,566!
2967
      return code;
×
2968
    }
2969
    if (!numOfElems) {
61,050,566✔
2970
      numOfElems = pInputInfo->hasResult ? 1 : 0;
45,693,715✔
2971
    }
2972
  }
2973

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

2982
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
45,689,086✔
2983
  return TSDB_CODE_SUCCESS;
45,689,086✔
2984
}
2985

2986
int32_t firstFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, true); }
12,717,484✔
2987

2988
int32_t lastFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, false); }
32,993,393✔
2989

2990
int32_t firstLastFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
88,314,606✔
2991
  int32_t          code = TSDB_CODE_SUCCESS;
88,314,606✔
2992
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
88,314,606✔
2993
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
88,314,606✔
2994
  if (NULL == pCol) {
87,996,799!
2995
    return TSDB_CODE_OUT_OF_RANGE;
×
2996
  }
2997

2998
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
87,996,799✔
2999
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
87,996,799✔
3000

3001
  SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pResInfo);
87,996,799✔
3002

3003
  if (pResInfo->isNullRes) {
87,996,799✔
3004
    colDataSetNULL(pCol, pBlock->info.rows);
46,333✔
3005
    return setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
46,333✔
3006
  }
3007
  code = colDataSetVal(pCol, pBlock->info.rows, pRes->buf, pRes->isNull || pResInfo->isNullRes);
87,950,466!
3008
  if (TSDB_CODE_SUCCESS != code) {
87,926,524!
3009
    return code;
×
3010
  }
3011

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

3015
  return code;
87,973,958✔
3016
}
3017

3018
int32_t firstLastPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
65,351,301✔
3019
  int32_t code = TSDB_CODE_SUCCESS;
65,351,301✔
3020

3021
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
65,351,301✔
3022
  SFirstLastRes*       pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
65,351,301✔
3023

3024
  int32_t resultBytes = getFirstLastInfoSize(pRes->bytes, pRes->pkBytes);
65,351,301✔
3025

3026
  // todo check for failure
3027
  char* res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
65,301,763!
3028
  if (NULL == res) {
65,544,446!
3029
    return terrno;
×
3030
  }
3031
  (void)memcpy(varDataVal(res), pRes, resultBytes);
65,544,446✔
3032

3033
  varDataSetLen(res, resultBytes);
65,544,446✔
3034

3035
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
65,544,446✔
3036
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
65,544,446✔
3037
  if (NULL == pCol) {
65,243,753!
3038
    taosMemoryFree(res);
×
3039
    return TSDB_CODE_OUT_OF_RANGE;
×
3040
  }
3041

3042
  if (pEntryInfo->numOfRes == 0) {
65,287,107✔
3043
    colDataSetNULL(pCol, pBlock->info.rows);
2,359,805!
3044
    code = setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
2,359,805✔
3045
  } else {
3046
    code = colDataSetVal(pCol, pBlock->info.rows, res, false);
62,927,302✔
3047
    if (TSDB_CODE_SUCCESS != code) {
62,758,191!
3048
      taosMemoryFree(res);
×
3049
      return code;
×
3050
    }
3051
    code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
62,758,191✔
3052
  }
3053
  taosMemoryFree(res);
65,085,192✔
3054
  return code;
65,613,175✔
3055
}
3056

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

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

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

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

3076
  if (colDataIsNull_s(pInputCol, rowIndex)) {
86,074,708✔
3077
    pInfo->isNull = true;
3,746✔
3078
  } else {
3079
    pInfo->isNull = false;
43,033,608✔
3080

3081
    if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
43,033,608!
3082
      if (pInputCol->info.type == TSDB_DATA_TYPE_JSON) {
5,703,747!
3083
        pInfo->bytes = getJsonValueLen(pData);
×
3084
      } else {
3085
        pInfo->bytes = varDataTLen(pData);
5,703,747✔
3086
      }
3087
    }
3088

3089
    (void)memcpy(pInfo->buf, pData, pInfo->bytes);
43,033,608✔
3090
  }
3091

3092
  if (pCtx->hasPrimaryKey && !colDataIsNull_s(pkCol, rowIndex)) {
43,108,478✔
3093
    char* pkData = colDataGetData(pkCol, rowIndex);
71,109!
3094
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
71,109!
3095
      if (pInfo->pkType == TSDB_DATA_TYPE_JSON) {
23,631!
3096
        pInfo->pkBytes = getJsonValueLen(pkData);
×
3097
      } else {
3098
        pInfo->pkBytes = varDataTLen(pkData);
23,631✔
3099
      }
3100
    }
3101
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
71,109✔
3102
    pInfo->pkData = pInfo->buf + pInfo->bytes;
71,109✔
3103
  }
3104
  pInfo->ts = cts;
43,037,354✔
3105
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
43,037,354✔
3106
  if (code != TSDB_CODE_SUCCESS) {
43,031,657!
3107
    return code;
×
3108
  }
3109

3110
  pInfo->hasResult = true;
43,031,657✔
3111

3112
  return TSDB_CODE_SUCCESS;
43,031,657✔
3113
}
3114

3115
int32_t lastRowFunction(SqlFunctionCtx* pCtx) {
43,190,977✔
3116
  int32_t numOfElems = 0;
43,190,977✔
3117

3118
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
43,190,977✔
3119
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
43,190,977✔
3120

3121
  SInputColumnInfoData* pInput = &pCtx->input;
43,190,977✔
3122
  SColumnInfoData*      pInputCol = pInput->pData[0];
43,190,977✔
3123

3124
  int32_t type = pInputCol->info.type;
43,190,977✔
3125
  int32_t bytes = pInputCol->info.bytes;
43,190,977✔
3126
  pInfo->bytes = bytes;
43,190,977✔
3127

3128
  if (IS_NULL_TYPE(type)) {
43,190,977✔
3129
    return TSDB_CODE_SUCCESS;
64✔
3130
  }
3131
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
43,190,913✔
3132
  pInfo->pkType = -1;
43,190,913✔
3133
  __compar_fn_t pkCompareFn = NULL;
43,190,913✔
3134
  if (pCtx->hasPrimaryKey) {
43,190,913✔
3135
    pInfo->pkType = pkCol->info.type;
324,564✔
3136
    pInfo->pkBytes = pkCol->info.bytes;
324,564✔
3137
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
324,564✔
3138
  }
3139
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
43,193,938!
3140
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
43,193,938!
3141

3142
  if (pCtx->order == TSDB_ORDER_ASC && !pCtx->hasPrimaryKey) {
43,193,938!
3143
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
40,335,090!
3144
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
20,168,816✔
3145
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
20,168,816!
3146
      TSKEY cts = getRowPTs(pInput->pPTS, i);
20,168,816✔
3147
      numOfElems++;
20,168,816✔
3148

3149
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
20,168,816✔
3150
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
20,142,915✔
3151
        if (code != TSDB_CODE_SUCCESS) return code;
20,140,577!
3152
      }
3153

3154
      break;
20,166,478✔
3155
    }
3156
  } else if (!pCtx->hasPrimaryKey && pCtx->order == TSDB_ORDER_DESC) {
23,025,326✔
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) {
45,415,776!
3160
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
22,708,555✔
3161
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
22,708,555!
3162
      TSKEY cts = getRowPTs(pInput->pPTS, i);
22,708,555✔
3163
      numOfElems++;
22,708,555✔
3164

3165
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
22,708,555✔
3166
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
22,538,887✔
3167
        if (code != TSDB_CODE_SUCCESS) return code;
22,537,992!
3168
      }
3169
      break;
22,707,660✔
3170
    }
3171
  } else {
3172
    int64_t* pts = (int64_t*)pInput->pPTS->pData;
317,210✔
3173
    int      from = -1;
317,210✔
3174
    int32_t  i = -1;
317,210✔
3175
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
2,411,228✔
3176
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
2,093,752✔
3177
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
2,093,752!
3178
      TSKEY cts = pts[i];
2,093,752✔
3179

3180
      numOfElems++;
2,093,752✔
3181
      char* pkData = NULL;
2,093,752✔
3182
      if (pCtx->hasPrimaryKey) {
2,093,752✔
3183
        pkData = colDataGetData(pkCol, i);
1,411,448!
3184
      }
3185
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts ||
2,093,752✔
3186
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
1,737,810✔
3187
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
355,948✔
3188
        if (code != TSDB_CODE_SUCCESS) {
356,214!
3189
          return code;
×
3190
        }
3191
        pResInfo->numOfRes = 1;
356,214✔
3192
      }
3193
    }
3194
  }
3195

3196
  SET_VAL(pResInfo, numOfElems, 1);
43,198,092!
3197
  return TSDB_CODE_SUCCESS;
43,198,092✔
3198
}
3199

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

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

3225
static int32_t doSetPrevVal(SDiffInfo* pDiffInfo, int32_t type, const char* pv, int64_t ts) {
1,624,637✔
3226
  switch (type) {
1,624,637!
3227
    case TSDB_DATA_TYPE_BOOL:
38✔
3228
      pDiffInfo->prev.i64 = *(bool*)pv ? 1 : 0;
38✔
3229
      break;
38✔
3230
    case TSDB_DATA_TYPE_UTINYINT:
399✔
3231
    case TSDB_DATA_TYPE_TINYINT:
3232
      pDiffInfo->prev.i64 = *(int8_t*)pv;
399✔
3233
      break;
399✔
3234
    case TSDB_DATA_TYPE_UINT:
53,790✔
3235
    case TSDB_DATA_TYPE_INT:
3236
      pDiffInfo->prev.i64 = *(int32_t*)pv;
53,790✔
3237
      break;
53,790✔
3238
    case TSDB_DATA_TYPE_USMALLINT:
284,938✔
3239
    case TSDB_DATA_TYPE_SMALLINT:
3240
      pDiffInfo->prev.i64 = *(int16_t*)pv;
284,938✔
3241
      break;
284,938✔
3242
    case TSDB_DATA_TYPE_TIMESTAMP:
646✔
3243
    case TSDB_DATA_TYPE_UBIGINT:
3244
    case TSDB_DATA_TYPE_BIGINT:
3245
      pDiffInfo->prev.i64 = *(int64_t*)pv;
646✔
3246
      break;
646✔
3247
    case TSDB_DATA_TYPE_FLOAT:
1,212,430✔
3248
      pDiffInfo->prev.d64 = *(float*)pv;
1,212,430✔
3249
      break;
1,212,430✔
3250
    case TSDB_DATA_TYPE_DOUBLE:
72,396✔
3251
      pDiffInfo->prev.d64 = *(double*)pv;
72,396✔
3252
      break;
72,396✔
3253
    default:
×
3254
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3255
  }
3256
  pDiffInfo->prevTs = ts;
1,624,637✔
3257
  pDiffInfo->hasPrev = true;
1,624,637✔
3258
  return TSDB_CODE_SUCCESS;
1,624,637✔
3259
}
3260

3261
static bool diffIsNegtive(SDiffInfo* pDiffInfo, int32_t type, const char* pv) {
8,590,297✔
3262
  switch (type) {
8,590,297!
3263
    case TSDB_DATA_TYPE_UINT: {
×
3264
      int64_t v = *(uint32_t*)pv;
×
3265
      return v < pDiffInfo->prev.i64;
×
3266
    }
3267
    case TSDB_DATA_TYPE_INT: {
7,196✔
3268
      int64_t v = *(int32_t*)pv;
7,196✔
3269
      return v < pDiffInfo->prev.i64;
7,196✔
3270
    }
3271
    case TSDB_DATA_TYPE_BOOL: {
×
3272
      int64_t v = *(bool*)pv;
×
3273
      return v < pDiffInfo->prev.i64;
×
3274
    }
3275
    case TSDB_DATA_TYPE_UTINYINT: {
×
3276
      int64_t v = *(uint8_t*)pv;
×
3277
      return v < pDiffInfo->prev.i64;
×
3278
    }
3279
    case TSDB_DATA_TYPE_TINYINT: {
5,402✔
3280
      int64_t v = *(int8_t*)pv;
5,402✔
3281
      return v < pDiffInfo->prev.i64;
5,402✔
3282
    }
3283
    case TSDB_DATA_TYPE_USMALLINT: {
×
3284
      int64_t v = *(uint16_t*)pv;
×
3285
      return v < pDiffInfo->prev.i64;
×
3286
    }
3287
    case TSDB_DATA_TYPE_SMALLINT: {
1,510,710✔
3288
      int64_t v = *(int16_t*)pv;
1,510,710✔
3289
      return v < pDiffInfo->prev.i64;
1,510,710✔
3290
    }
3291
    case TSDB_DATA_TYPE_UBIGINT: {
40✔
3292
      uint64_t v = *(uint64_t*)pv;
40✔
3293
      return v < (uint64_t)pDiffInfo->prev.i64;
40✔
3294
    }
3295
    case TSDB_DATA_TYPE_TIMESTAMP:
6,597✔
3296
    case TSDB_DATA_TYPE_BIGINT: {
3297
      int64_t v = *(int64_t*)pv;
6,597✔
3298
      return v < pDiffInfo->prev.i64;
6,597✔
3299
    }
3300
    case TSDB_DATA_TYPE_FLOAT: {
6,640,996✔
3301
      float v = *(float*)pv;
6,640,996✔
3302
      return v < pDiffInfo->prev.d64;
6,640,996✔
3303
    }
3304
    case TSDB_DATA_TYPE_DOUBLE: {
419,356✔
3305
      double v = *(double*)pv;
419,356✔
3306
      return v < pDiffInfo->prev.d64;
419,356✔
3307
    }
3308
    default:
×
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,531,041,128✔
3316
  bool isNegative = v < pDiffInfo->prev.i64;
1,531,041,128✔
3317
  if (type == TSDB_DATA_TYPE_UBIGINT) {
1,531,041,128✔
3318
    isNegative = (uint64_t)v < (uint64_t)pDiffInfo->prev.i64;
3,745✔
3319
  }
3320
  int64_t delta = v - pDiffInfo->prev.i64;
1,531,041,128✔
3321
  if (isNegative && ignoreNegative(pDiffInfo->ignoreOption)) {
1,531,041,128✔
3322
    colDataSetNull_f_s(pOutput, pos);
489,267✔
3323
    pOutput->hasNull = true;
489,267✔
3324
  } else {
3325
    colDataSetInt64(pOutput, pos, &delta);
1,530,551,861✔
3326
  }
3327
  pDiffInfo->prev.i64 = v;
1,531,041,128✔
3328
}
1,531,041,128✔
3329

3330
static void tryToSetDouble(SDiffInfo* pDiffInfo, SColumnInfoData* pOutput, double v, int32_t pos) {
5,888,242✔
3331
  double delta = v - pDiffInfo->prev.d64;
5,888,242✔
3332
  if (delta < 0 && ignoreNegative(pDiffInfo->ignoreOption)) {
5,888,242✔
3333
    colDataSetNull_f_s(pOutput, pos);
2,538,588✔
3334
  } else {
3335
    colDataSetDouble(pOutput, pos, &delta);
3,349,654✔
3336
  }
3337
  pDiffInfo->prev.d64 = v;
5,888,242✔
3338
}
5,888,242✔
3339

3340
static int32_t doHandleDiff(SDiffInfo* pDiffInfo, int32_t type, const char* pv, SColumnInfoData* pOutput, int32_t pos,
1,536,929,986✔
3341
                            int64_t ts) {
3342
  if (!pDiffInfo->hasPrev) {
1,536,929,986✔
3343
    colDataSetNull_f_s(pOutput, pos);
616✔
3344
    return doSetPrevVal(pDiffInfo, type, pv, ts);
616✔
3345
  }
3346
  pDiffInfo->prevTs = ts;
1,536,929,370✔
3347
  switch (type) {
1,536,929,370!
3348
    case TSDB_DATA_TYPE_UINT: {
3,675✔
3349
      int64_t v = *(uint32_t*)pv;
3,675✔
3350
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
3,675✔
3351
      break;
3,675✔
3352
    }
3353
    case TSDB_DATA_TYPE_INT: {
26,262,256✔
3354
      int64_t v = *(int32_t*)pv;
26,262,256✔
3355
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
26,262,256✔
3356
      break;
26,262,256✔
3357
    }
3358
    case TSDB_DATA_TYPE_BOOL: {
10,877✔
3359
      int64_t v = *(bool*)pv;
10,877✔
3360
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
10,877✔
3361
      break;
10,877✔
3362
    }
3363
    case TSDB_DATA_TYPE_UTINYINT: {
675✔
3364
      int64_t v = *(uint8_t*)pv;
675✔
3365
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
675✔
3366
      break;
675✔
3367
    }
3368
    case TSDB_DATA_TYPE_TINYINT: {
34,391✔
3369
      int64_t v = *(int8_t*)pv;
34,391✔
3370
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
34,391✔
3371
      break;
34,391✔
3372
    }
3373
    case TSDB_DATA_TYPE_USMALLINT: {
675✔
3374
      int64_t v = *(uint16_t*)pv;
675✔
3375
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
675✔
3376
      break;
675✔
3377
    }
3378
    case TSDB_DATA_TYPE_SMALLINT: {
1,400,517✔
3379
      int64_t v = *(int16_t*)pv;
1,400,517✔
3380
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
1,400,517✔
3381
      break;
1,400,517✔
3382
    }
3383
    case TSDB_DATA_TYPE_TIMESTAMP:
1,503,328,062✔
3384
    case TSDB_DATA_TYPE_UBIGINT:
3385
    case TSDB_DATA_TYPE_BIGINT: {
3386
      int64_t v = *(int64_t*)pv;
1,503,328,062✔
3387
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
1,503,328,062✔
3388
      break;
1,503,328,062✔
3389
    }
3390
    case TSDB_DATA_TYPE_FLOAT: {
5,494,248✔
3391
      double v = *(float*)pv;
5,494,248✔
3392
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
5,494,248✔
3393
      break;
5,494,248✔
3394
    }
3395
    case TSDB_DATA_TYPE_DOUBLE: {
393,994✔
3396
      double v = *(double*)pv;
393,994✔
3397
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
393,994✔
3398
      break;
393,994✔
3399
    }
3400
    default:
×
3401
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3402
  }
3403
  pDiffInfo->hasPrev = true;
1,536,929,370✔
3404
  return TSDB_CODE_SUCCESS;
1,536,929,370✔
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,
351,880,757✔
3410
                              int32_t* nextFrom) {
3411
  if (pInput->pPrimaryKey == NULL) {
351,880,757✔
3412
    if (from == -1) {
246,717,827✔
3413
      from = pInput->startRowIndex;
70,728,223✔
3414
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
175,989,604✔
3415
      return false;
70,592,169✔
3416
    }
3417
    *pRowIndex = from;
176,125,658✔
3418
    *nextFrom = from + 1;
176,125,658✔
3419
    return true;
176,125,658✔
3420
  } else {
3421
    if (from == -1) {
105,162,930✔
3422
      from = pInput->startRowIndex;
1,007,605✔
3423
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
104,155,325✔
3424
      return false;
1,007,627✔
3425
    }
3426
    TSKEY*           tsList = (int64_t*)pInput->pPTS->pData;
104,155,303✔
3427
    SColumnInfoData* pkCol = pInput->pPrimaryKey;
104,155,303✔
3428
    int8_t           pkType = pkCol->info.type;
104,155,303✔
3429
    int32_t          order = (firstOccur) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
104,155,303✔
3430
    __compar_fn_t    compareFunc = getKeyComparFunc(pkType, order);
104,155,303✔
3431
    int32_t          select = from;
104,248,082✔
3432
    char*            val = colDataGetData(pkCol, select);
104,248,082!
3433
    while (from < pInput->numOfRows + pInput->startRowIndex - 1 && tsList[from + 1] == tsList[from]) {
110,631,617✔
3434
      char* val1 = colDataGetData(pkCol, from + 1);
6,385,302!
3435
      if (compareFunc(val1, val) < 0) {
6,385,302✔
3436
        select = from + 1;
1,969,799✔
3437
        val = val1;
1,969,799✔
3438
      }
3439
      from = from + 1;
6,383,535✔
3440
    }
3441
    *pRowIndex = select;
104,246,315✔
3442
    *nextFrom = from + 1;
104,246,315✔
3443
    return true;
104,246,315✔
3444
  }
3445
}
3446

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

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

3456
  if (pRow->isDataNull || !pDiffInfo->hasPrev) {
1,538,655,198✔
3457
    return true;
191,673✔
3458
  } else if (ignoreNegative(pDiffInfo->ignoreOption)) {
1,538,463,525✔
3459
    return diffIsNegtive(pDiffInfo, pCtx->input.pData[0]->info.type, pRow->pData);
8,590,297✔
3460
  }
3461
  return false;
1,529,873,228✔
3462
}
3463

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

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

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

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

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

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

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

3509
  char* pv = pRow->pData;
1,536,930,017✔
3510

3511
  if (pRow->ts == pDiffInfo->prevTs) {
1,536,930,017✔
3512
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
31✔
3513
  }
3514
  code = doHandleDiff(pDiffInfo, inputType, pv, pOutput, pos, pRow->ts);
1,536,929,986✔
3515
  if (code != TSDB_CODE_SUCCESS) {
1,536,929,986!
3516
    return code;
×
3517
  }
3518
  // handle selectivity
3519
  if (pCtx->subsidiaries.num > 0) {
1,536,929,986✔
3520
    code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
34,010,603✔
3521
    if (code != TSDB_CODE_SUCCESS) {
34,010,603!
3522
      return code;
×
3523
    }
3524
  }
3525

3526
  return TSDB_CODE_SUCCESS;
1,536,929,986✔
3527
}
3528

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

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

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

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

3559
  SqlFunctionCtx* pCtx0 = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, 0);
1,886,515✔
3560
  SFuncInputRow*  pRow0 = (SFuncInputRow*)taosArrayGet(pRows, 0);
1,886,515✔
3561
  if (NULL == pCtx0 || NULL == pRow0) {
1,886,515!
3562
    code = terrno;
×
3563
    goto _exit;
×
3564
  }
3565
  int32_t startOffset = pCtx0->offset;
1,886,515✔
3566
  bool    result = false;
1,886,515✔
3567
  while (1) {
1,538,637,677✔
3568
    code = funcInputGetNextRow(pCtx0, pRow0, &result);
1,540,524,192✔
3569
    if (TSDB_CODE_SUCCESS != code) {
1,540,524,192!
3570
      goto _exit;
×
3571
    }
3572
    if (!result) {
1,540,524,192✔
3573
      break;
1,886,484✔
3574
    }
3575
    bool hasNotNullValue = !diffResultIsNull(pCtx0, pRow0);
1,538,637,708✔
3576
    for (int i = 1; i < diffColNum; ++i) {
1,538,655,198✔
3577
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
17,490✔
3578
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
17,490✔
3579
      if (NULL == pCtx || NULL == pRow) {
17,490!
3580
        code = terrno;
×
3581
        goto _exit;
×
3582
      }
3583
      code = funcInputGetNextRow(pCtx, pRow, &result);
17,490✔
3584
      if (TSDB_CODE_SUCCESS != code) {
17,490!
3585
        goto _exit;
×
3586
      }
3587
      if (!result) {
17,490!
3588
        // rows are not equal
3589
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
3590
        goto _exit;
×
3591
      }
3592
      if (!diffResultIsNull(pCtx, pRow)) {
17,490✔
3593
        hasNotNullValue = true;
16,754✔
3594
      }
3595
    }
3596
    int32_t pos = startOffset + numOfElems;
1,538,637,708✔
3597

3598
    bool newRow = false;
1,538,637,708✔
3599
    for (int i = 0; i < diffColNum; ++i) {
2,147,483,647✔
3600
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
1,538,655,198✔
3601
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
1,538,655,198✔
3602
      if (NULL == pCtx || NULL == pRow) {
1,538,655,198!
3603
        code = terrno;
×
3604
        goto _exit;
×
3605
      }
3606
      if ((keepNull || hasNotNullValue) && !isFirstRow(pCtx, pRow)) {
1,538,655,198✔
3607
        code = setDoDiffResult(pCtx, pRow, pos);
1,537,029,150✔
3608
        if (code != TSDB_CODE_SUCCESS) {
1,537,029,150✔
3609
          goto _exit;
31✔
3610
        }
3611
        newRow = true;
1,537,029,119✔
3612
      } else {
3613
        code = trySetPreVal(pCtx, pRow);
1,626,048✔
3614
        if (code != TSDB_CODE_SUCCESS) {
1,626,048!
3615
          goto _exit;
×
3616
        }
3617
      }
3618
    }
3619
    if (newRow) ++numOfElems;
1,538,637,677✔
3620
  }
3621

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

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

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

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

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

3656
  STopBotRes*           pRes = GET_ROWCELL_INTERBUF(pResInfo);
46,648,734✔
3657
  SInputColumnInfoData* pInput = &pCtx->input;
46,648,734✔
3658

3659
  pRes->maxSize = pCtx->param[1].param.i;
46,648,734✔
3660

3661
  pRes->nullTupleSaved = false;
46,648,734✔
3662
  pRes->nullTuplePos.pageId = -1;
46,648,734✔
3663
  return TSDB_CODE_SUCCESS;
46,648,734✔
3664
}
3665

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

3671
  return pRes;
218,608,731✔
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) {
33,914,087✔
3680
  int32_t              numOfElems = 0;
33,914,087✔
3681
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
33,914,087✔
3682

3683
  SInputColumnInfoData* pInput = &pCtx->input;
33,914,087✔
3684
  SColumnInfoData*      pCol = pInput->pData[0];
33,914,087✔
3685

3686
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
33,914,087✔
3687
  pRes->type = pInput->pData[0]->info.type;
33,913,565✔
3688

3689
  int32_t start = pInput->startRowIndex;
33,913,565✔
3690
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
123,964,331✔
3691
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
90,031,697✔
3692
      continue;
28,730✔
3693
    }
3694

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

3703
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
33,932,634✔
3704
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
5,117✔
3705
    if (code != TSDB_CODE_SUCCESS) {
5,117!
3706
      return code;
×
3707
    }
3708
    pRes->nullTupleSaved = true;
5,117✔
3709
  }
3710
  return TSDB_CODE_SUCCESS;
33,932,634✔
3711
}
3712

3713
int32_t bottomFunction(SqlFunctionCtx* pCtx) {
13,900,656✔
3714
  int32_t              numOfElems = 0;
13,900,656✔
3715
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
13,900,656✔
3716

3717
  SInputColumnInfoData* pInput = &pCtx->input;
13,900,656✔
3718
  SColumnInfoData*      pCol = pInput->pData[0];
13,900,656✔
3719

3720
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
13,900,656✔
3721
  pRes->type = pInput->pData[0]->info.type;
13,900,485✔
3722

3723
  int32_t start = pInput->startRowIndex;
13,900,485✔
3724
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
48,465,513✔
3725
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
34,559,236✔
3726
      continue;
29,695✔
3727
    }
3728

3729
    numOfElems++;
34,529,541✔
3730
    char*   data = colDataGetData(pCol, i);
34,529,541!
3731
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, false);
34,529,541✔
3732
    if (code != TSDB_CODE_SUCCESS) {
34,535,333!
3733
      return code;
×
3734
    }
3735
  }
3736

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

3745
  return TSDB_CODE_SUCCESS;
13,906,277✔
3746
}
3747

3748
static int32_t topBotResComparFn(const void* p1, const void* p2, const void* param) {
629,344,940✔
3749
  uint16_t type = *(uint16_t*)param;
629,344,940✔
3750

3751
  STopBotResItem* val1 = (STopBotResItem*)p1;
629,344,940✔
3752
  STopBotResItem* val2 = (STopBotResItem*)p2;
629,344,940✔
3753

3754
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
629,344,940!
3755
    if (val1->v.i == val2->v.i) {
261,676,988✔
3756
      return 0;
290,978✔
3757
    }
3758

3759
    return (val1->v.i > val2->v.i) ? 1 : -1;
261,386,010✔
3760
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
367,667,952!
3761
    if (val1->v.u == val2->v.u) {
822,820✔
3762
      return 0;
175,769✔
3763
    }
3764

3765
    return (val1->v.u > val2->v.u) ? 1 : -1;
647,051✔
3766
  } else if (TSDB_DATA_TYPE_FLOAT == type) {
366,845,132✔
3767
    if (val1->v.f == val2->v.f) {
347,761,166✔
3768
      return 0;
126✔
3769
    }
3770

3771
    return (val1->v.f > val2->v.f) ? 1 : -1;
347,761,040✔
3772
  }
3773

3774
  if (val1->v.d == val2->v.d) {
19,083,966✔
3775
    return 0;
22✔
3776
  }
3777

3778
  return (val1->v.d > val2->v.d) ? 1 : -1;
19,083,944✔
3779
}
3780

3781
int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock, uint16_t type,
124,512,648✔
3782
                        uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery) {
3783
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
124,512,648✔
3784
  int32_t     code = TSDB_CODE_SUCCESS;
124,486,555✔
3785

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

3789
  STopBotResItem* pItems = pRes->pItems;
124,528,268✔
3790

3791
  // not full yet
3792
  if (pEntryInfo->numOfRes < pRes->maxSize) {
124,528,268✔
3793
    STopBotResItem* pItem = &pItems[pEntryInfo->numOfRes];
88,238,299✔
3794
    pItem->v = val;
88,238,299✔
3795
    pItem->uid = uid;
88,238,299✔
3796

3797
    // save the data of this tuple
3798
    if (pCtx->subsidiaries.num > 0) {
88,238,299✔
3799
      code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
59,521,690✔
3800
      if (code != TSDB_CODE_SUCCESS) {
59,424,920!
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++;
88,141,529✔
3810
    code = taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type,
88,141,529✔
3811
                        topBotResComparFn, !isTopQuery);
88,141,529✔
3812
    if (code != TSDB_CODE_SUCCESS) {
88,279,656!
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,289,969✔
3817
                        (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u > pItems[0].v.u) ||
22,456,655!
3818
                        (TSDB_DATA_TYPE_FLOAT == type && val.f > pItems[0].v.f) ||
22,362,526✔
3819
                        (TSDB_DATA_TYPE_DOUBLE == type && val.d > pItems[0].v.d))) ||
18,119,069✔
3820
        (!isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i < pItems[0].v.i) ||
30,203,403!
3821
                         (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u < pItems[0].v.u) ||
9,225,015!
3822
                         (TSDB_DATA_TYPE_FLOAT == type && val.f < pItems[0].v.f) ||
9,221,134✔
3823
                         (TSDB_DATA_TYPE_DOUBLE == type && val.d < pItems[0].v.d)))) {
9,220,262✔
3824
      // replace the old data and the coresponding tuple data
3825
      STopBotResItem* pItem = &pItems[0];
9,521,723✔
3826
      pItem->v = val;
9,521,723✔
3827
      pItem->uid = uid;
9,521,723✔
3828

3829
      // save the data of this tuple by over writing the old data
3830
      if (pCtx->subsidiaries.num > 0) {
9,521,723✔
3831
        code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
7,024,363✔
3832
        if (code != TSDB_CODE_SUCCESS) {
7,021,141!
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,
9,518,501✔
3840
                            topBotResComparFn, NULL, !isTopQuery);
9,518,501✔
3841
      if (code != TSDB_CODE_SUCCESS) {
9,481,148!
3842
        return code;
×
3843
      }
3844
    }
3845
  }
3846

3847
  return TSDB_CODE_SUCCESS;
124,529,050✔
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,
258,401,243✔
3857
                           char* buf, char** res) {
3858
  char* nullList = buf;
258,401,243✔
3859
  char* pStart = (char*)(nullList + sizeof(bool) * pSubsidiaryies->num);
258,401,243✔
3860

3861
  int32_t offset = 0;
258,401,243✔
3862
  for (int32_t i = 0; i < pSubsidiaryies->num; ++i) {
514,337,163✔
3863
    SqlFunctionCtx* pc = pSubsidiaryies->pCtx[i];
258,467,120✔
3864

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

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

3874
    SColumnInfoData* pCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
258,426,451✔
3875
    if (NULL == pCol) {
255,935,920!
3876
      return TSDB_CODE_OUT_OF_RANGE;
×
3877
    }
3878
    if ((nullList[i] = colDataIsNull_s(pCol, rowIndex)) == true) {
511,871,840✔
3879
      offset += pCol->info.bytes;
883✔
3880
      continue;
883✔
3881
    }
3882

3883
    char* p = colDataGetData(pCol, rowIndex);
255,935,037!
3884
    if (IS_VAR_DATA_TYPE(pCol->info.type)) {
255,935,037!
3885
      (void)memcpy(pStart + offset, p, (pCol->info.type == TSDB_DATA_TYPE_JSON) ? getJsonValueLen(p) : varDataTLen(p));
29,568!
3886
    } else {
3887
      (void)memcpy(pStart + offset, p, pCol->info.bytes);
255,905,469✔
3888
    }
3889

3890
    offset += pCol->info.bytes;
255,935,037✔
3891
  }
3892

3893
  *res = buf;
255,870,043✔
3894
  return TSDB_CODE_SUCCESS;
255,870,043✔
3895
}
3896

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

3903
    if (pHandle->currentPage == -1) {
195,073,622✔
3904
      pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
678,407✔
3905
      if (pPage == NULL) {
678,416✔
3906
        return terrno;
2✔
3907
      }
3908
      pPage->num = sizeof(SFilePage);
678,414✔
3909
    } else {
3910
      pPage = getBufPage(pHandle->pBuf, pHandle->currentPage);
194,395,215✔
3911
      if (pPage == NULL) {
194,995,376!
3912
        return terrno;
×
3913
      }
3914
      if (pPage->num + length > getBufPageSize(pHandle->pBuf)) {
194,995,376✔
3915
        // current page is all used, let's prepare a new buffer page
3916
        releaseBufPage(pHandle->pBuf, pPage);
465,488✔
3917
        pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
465,487✔
3918
        if (pPage == NULL) {
465,488!
3919
          return terrno;
×
3920
        }
3921
        pPage->num = sizeof(SFilePage);
465,488✔
3922
      }
3923
    }
3924

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

3928
    pPage->num += length;
195,650,560✔
3929
    setBufPageDirty(pPage, true);
195,650,560✔
3930
    releaseBufPage(pHandle->pBuf, pPage);
195,626,391✔
3931
  } else {  // other tuple save policy
3932
    if (pStore->streamStateFuncPut(pHandle->pState, key, pBuf, length) >= 0) {
37,381!
3933
      p.streamTupleKey = *key;
68,456✔
3934
    }
3935
  }
3936

3937
  *pPos = p;
195,551,807✔
3938
  return TSDB_CODE_SUCCESS;
195,551,807✔
3939
}
3940

3941
int32_t saveTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
169,607,935✔
3942
  int32_t code = prepareBuf(pCtx);
169,607,935✔
3943
  if (TSDB_CODE_SUCCESS != code) {
169,579,263!
3944
    return code;
×
3945
  }
3946

3947
  SWinKey key = {0};
169,579,263✔
3948
  if (pCtx->saveHandle.pBuf == NULL) {
169,579,263✔
3949
    SColumnInfoData* pColInfo = taosArrayGet(pSrcBlock->pDataBlock, pCtx->saveHandle.pState->tsIndex);
68,461✔
3950
    if (NULL == pColInfo) {
68,463!
3951
      return TSDB_CODE_OUT_OF_RANGE;
×
3952
    }
3953
    if (pColInfo->info.type != TSDB_DATA_TYPE_TIMESTAMP) {
68,463!
3954
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3955
    }
3956
    key.groupId = pSrcBlock->info.id.groupId;
68,463✔
3957
    key.ts = *(int64_t*)colDataGetData(pColInfo, rowIndex);
68,463!
3958
    key.numInGroup = pCtx->pExpr->pExpr->_function.bindExprID;
68,463✔
3959
  }
3960

3961
  char* buf = NULL;
169,579,265✔
3962
  code = serializeTupleData(pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
169,579,265✔
3963
  if (TSDB_CODE_SUCCESS != code) {
168,853,026!
3964
    return code;
×
3965
  }
3966
  return doSaveTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, &key, pPos, pCtx->pStore);
168,853,026✔
3967
}
3968

3969
static int32_t doUpdateTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, STuplePos* pPos,
88,865,538✔
3970
                                 SFunctionStateStore* pStore) {
3971
  if (pHandle->pBuf != NULL) {
88,865,538✔
3972
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
88,744,882✔
3973
    if (pPage == NULL) {
88,808,768!
3974
      return terrno;
×
3975
    }
3976
    (void)memcpy(pPage->data + pPos->offset, pBuf, length);
88,808,768✔
3977
    setBufPageDirty(pPage, true);
88,808,768✔
3978
    releaseBufPage(pHandle->pBuf, pPage);
88,805,261✔
3979
  } else {
3980
    int32_t code = pStore->streamStateFuncPut(pHandle->pState, &pPos->streamTupleKey, pBuf, length);
120,656✔
3981
    if (TSDB_CODE_SUCCESS != code) {
122,027!
3982
      return code;
×
3983
    }
3984
  }
3985

3986
  return TSDB_CODE_SUCCESS;
88,917,184✔
3987
}
3988

3989
int32_t updateTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
88,954,948✔
3990
  int32_t code = prepareBuf(pCtx);
88,954,948✔
3991
  if (TSDB_CODE_SUCCESS != code) {
88,951,175!
3992
    return code;
×
3993
  }
3994

3995
  char* buf = NULL;
88,951,175✔
3996
  code = serializeTupleData(pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
88,951,175✔
3997
  if (TSDB_CODE_SUCCESS != code) {
88,864,661!
3998
    return code;
×
3999
  }
4000
  return doUpdateTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, pPos, pCtx->pStore);
88,864,661✔
4001
}
4002

4003
static int32_t doLoadTupleData(SSerializeDataHandle* pHandle, const STuplePos* pPos, SFunctionStateStore* pStore,
155,659,387✔
4004
                               char** value) {
4005
  if (pHandle->pBuf != NULL) {
155,659,387✔
4006
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
155,603,761✔
4007
    if (pPage == NULL) {
155,957,048!
4008
      *value = NULL;
×
4009
      return terrno;
×
4010
    }
4011
    *value = pPage->data + pPos->offset;
155,957,048✔
4012
    releaseBufPage(pHandle->pBuf, pPage);
155,957,048✔
4013
    return TSDB_CODE_SUCCESS;
155,878,456✔
4014
  } else {
4015
    *value = NULL;
55,626✔
4016
    int32_t vLen;
4017
    int32_t code = pStore->streamStateFuncGet(pHandle->pState, &pPos->streamTupleKey, (void**)(value), &vLen);
55,626✔
4018
    if (TSDB_CODE_SUCCESS != code) {
69,225!
4019
      return code;
×
4020
    }
4021
    return TSDB_CODE_SUCCESS;
69,225✔
4022
  }
4023
}
4024

4025
int32_t loadTupleData(SqlFunctionCtx* pCtx, const STuplePos* pPos, char** value) {
155,272,787✔
4026
  return doLoadTupleData(&pCtx->saveHandle, pPos, pCtx->pStore, value);
155,272,787✔
4027
}
4028

4029
int32_t topBotFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
46,545,300✔
4030
  int32_t code = TSDB_CODE_SUCCESS;
46,545,300✔
4031

4032
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
46,545,300✔
4033
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
46,545,300✔
4034

4035
  int16_t type = pCtx->pExpr->base.resSchema.type;
46,544,182✔
4036
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
46,544,182✔
4037

4038
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
46,544,182✔
4039
  if (NULL == pCol) {
46,364,523!
4040
    return TSDB_CODE_OUT_OF_RANGE;
×
4041
  }
4042

4043
  // todo assign the tag value and the corresponding row data
4044
  int32_t currentRow = pBlock->info.rows;
46,364,523✔
4045
  if (pEntryInfo->numOfRes <= 0) {
46,364,523✔
4046
    colDataSetNULL(pCol, currentRow);
595!
4047
    code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, currentRow);
595✔
4048
    return code;
595✔
4049
  }
4050
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
133,874,453✔
4051
    STopBotResItem* pItem = &pRes->pItems[i];
87,494,798✔
4052
    code = colDataSetVal(pCol, currentRow, (const char*)&pItem->v.i, false);
87,494,798✔
4053
    if (TSDB_CODE_SUCCESS != code) {
87,481,973!
4054
      return code;
×
4055
    }
4056
#ifdef BUF_PAGE_DEBUG
4057
    qDebug("page_finalize i:%d,item:%p,pageId:%d, offset:%d\n", i, pItem, pItem->tuplePos.pageId,
4058
           pItem->tuplePos.offset);
4059
#endif
4060
    code = setSelectivityValue(pCtx, pBlock, &pRes->pItems[i].tuplePos, currentRow);
87,481,973✔
4061
    if (TSDB_CODE_SUCCESS != code) {
87,510,525!
4062
      return code;
×
4063
    }
4064
    currentRow += 1;
87,510,525✔
4065
  }
4066

4067
  return code;
46,379,655✔
4068
}
4069

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

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

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

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

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

4143
int32_t getSpreadInfoSize() { return (int32_t)sizeof(SSpreadInfo); }
1,059,527✔
4144

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

4150
int32_t spreadFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
3,470,278✔
4151
  if (pResultInfo->initialized) {
3,470,278!
4152
    return TSDB_CODE_SUCCESS;
×
4153
  }
4154
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
3,470,278!
4155
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4156
  }
4157

4158
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
3,470,295✔
4159
  SET_DOUBLE_VAL(&pInfo->min, DBL_MAX);
3,470,295✔
4160
  SET_DOUBLE_VAL(&pInfo->max, -DBL_MAX);
3,470,295✔
4161
  pInfo->hasResult = false;
3,470,295✔
4162
  return TSDB_CODE_SUCCESS;
3,470,295✔
4163
}
4164

4165
int32_t spreadFunction(SqlFunctionCtx* pCtx) {
2,470,208✔
4166
  int32_t numOfElems = 0;
2,470,208✔
4167

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

4173
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,470,208✔
4174

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

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

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

4200
  } else {  // computing based on the true data block
4201
    SColumnInfoData* pCol = pInput->pData[0];
2,470,208✔
4202

4203
    int32_t start = pInput->startRowIndex;
2,470,208✔
4204
    // check the valid data one by one
4205
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
11,428,047✔
4206
      if (colDataIsNull_f(pCol->nullbitmap, i)) {
8,957,852✔
4207
        continue;
1,357,193✔
4208
      }
4209

4210
      char* data = colDataGetData(pCol, i);
7,600,659!
4211

4212
      double v = 0;
7,600,659✔
4213
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
7,600,659!
4214
      if (v < GET_DOUBLE_VAL(&pInfo->min)) {
7,600,646✔
4215
        SET_DOUBLE_VAL(&pInfo->min, v);
2,577,096✔
4216
      }
4217

4218
      if (v > GET_DOUBLE_VAL(&pInfo->max)) {
7,600,646✔
4219
        SET_DOUBLE_VAL(&pInfo->max, v);
3,022,025✔
4220
      }
4221

4222
      numOfElems += 1;
7,600,646✔
4223
    }
4224
  }
4225

4226
_spread_over:
2,470,195✔
4227
  // data in the check operation are all null, not output
4228
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
2,470,195✔
4229
  if (numOfElems > 0) {
2,470,195✔
4230
    pInfo->hasResult = true;
2,427,076✔
4231
  }
4232

4233
  return TSDB_CODE_SUCCESS;
2,470,195✔
4234
}
4235

4236
static void spreadTransferInfo(SSpreadInfo* pInput, SSpreadInfo* pOutput) {
1,057,751✔
4237
  pOutput->hasResult = pInput->hasResult;
1,057,751✔
4238
  if (pInput->max > pOutput->max) {
1,057,751✔
4239
    pOutput->max = pInput->max;
1,049,310✔
4240
  }
4241

4242
  if (pInput->min < pOutput->min) {
1,057,751✔
4243
    pOutput->min = pInput->min;
1,049,314✔
4244
  }
4245
}
1,057,751✔
4246

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

4251
  if (IS_NULL_TYPE(pCol->info.type)) {
1,049,751!
4252
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
4253
    return TSDB_CODE_SUCCESS;
×
4254
  }
4255

4256
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
1,049,751!
4257
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4258
  }
4259

4260
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,049,751✔
4261

4262
  int32_t start = pInput->startRowIndex;
1,049,751✔
4263
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
2,107,634✔
4264
    if (colDataIsNull_s(pCol, i)) continue;
2,115,766!
4265
    char*        data = colDataGetData(pCol, i);
1,057,883!
4266
    SSpreadInfo* pInputInfo = (SSpreadInfo*)varDataVal(data);
1,057,883✔
4267
    if (pInputInfo->hasResult) {
1,057,883✔
4268
      spreadTransferInfo(pInputInfo, pInfo);
1,057,750✔
4269
    }
4270
  }
4271

4272
  if (pInfo->hasResult) {
1,049,751✔
4273
    GET_RES_INFO(pCtx)->numOfRes = 1;
1,049,618✔
4274
  }
4275

4276
  return TSDB_CODE_SUCCESS;
1,049,751✔
4277
}
4278

4279
int32_t spreadFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,398,006✔
4280
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,398,006✔
4281
  if (pInfo->hasResult == true) {
2,398,006✔
4282
    SET_DOUBLE_VAL(&pInfo->result, pInfo->max - pInfo->min);
2,354,955✔
4283
  } else {
4284
    GET_RES_INFO(pCtx)->isNullRes = 1;
43,051✔
4285
  }
4286
  return functionFinalize(pCtx, pBlock);
2,398,006✔
4287
}
4288

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

4295
  if (NULL == res) {
1,057,716!
4296
    return terrno;
×
4297
  }
4298
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
1,057,716✔
4299
  varDataSetLen(res, resultBytes);
1,057,716✔
4300

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

4309
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
1,057,715✔
4310
  if (TSDB_CODE_SUCCESS != code) {
1,057,717!
4311
    goto _exit;
×
4312
  }
4313

4314
_exit:
1,057,717✔
4315
  taosMemoryFree(res);
1,057,717!
4316
  return code;
1,057,717✔
4317
}
4318

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

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

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

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

4338
int32_t elapsedFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
12,594,369✔
4339
  if (pResultInfo->initialized) {
12,594,369!
4340
    return TSDB_CODE_SUCCESS;
×
4341
  }
4342
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
12,594,369!
4343
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4344
  }
4345

4346
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
12,594,378✔
4347
  pInfo->result = 0;
12,594,378✔
4348
  pInfo->min = TSKEY_MAX;
12,594,378✔
4349
  pInfo->max = 0;
12,594,378✔
4350

4351
  if (pCtx->numOfParams > 1) {
12,594,378✔
4352
    pInfo->timeUnit = pCtx->param[1].param.i;
12,577,434✔
4353
  } else {
4354
    pInfo->timeUnit = 1;
16,944✔
4355
  }
4356

4357
  return TSDB_CODE_SUCCESS;
12,594,378✔
4358
}
4359

4360
int32_t elapsedFunction(SqlFunctionCtx* pCtx) {
12,594,409✔
4361
  int32_t numOfElems = 0;
12,594,409✔
4362

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

4367
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
12,594,409✔
4368

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

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

4403
    SColumnInfoData* pCol = pInput->pData[0];
12,594,357✔
4404

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

4414
      if (pCtx->end.key == INT64_MIN) {
799!
4415
        pInfo->min =
799✔
4416
            (pInfo->min > ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->min;
799✔
4417
      } else {
4418
        pInfo->min = pCtx->end.key;
×
4419
      }
4420
    } else {
4421
      if (pCtx->start.key == INT64_MIN) {
12,593,558✔
4422
        pInfo->min = (pInfo->min > ptsList[start]) ? ptsList[start] : pInfo->min;
7,769,886✔
4423
      } else {
4424
        pInfo->min = pCtx->start.key;
4,823,672✔
4425
      }
4426

4427
      if (pCtx->end.key == INT64_MIN) {
12,593,558✔
4428
        pInfo->max =
7,552,608✔
4429
            (pInfo->max < ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->max;
7,552,608✔
4430
      } else {
4431
        pInfo->max = pCtx->end.key + 1;
5,040,950✔
4432
      }
4433
    }
4434
  }
4435

4436
_elapsed_over:
12,594,409✔
4437
  // data in the check operation are all null, not output
4438
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
12,594,409✔
4439

4440
  return TSDB_CODE_SUCCESS;
12,594,409✔
4441
}
4442

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

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

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

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

4463
  int32_t start = pInput->startRowIndex;
×
4464

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

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

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

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

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

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

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

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

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

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

4525
int32_t getHistogramInfoSize() {
1,716,175✔
4526
  return (int32_t)sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
1,716,175✔
4527
}
4528

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

4534
static int8_t getHistogramBinType(char* binTypeStr) {
12,676,328✔
4535
  int8_t binType;
4536
  if (strcasecmp(binTypeStr, "user_input") == 0) {
12,676,328✔
4537
    binType = USER_INPUT_BIN;
3,554✔
4538
  } else if (strcasecmp(binTypeStr, "linear_bin") == 0) {
12,672,774✔
4539
    binType = LINEAR_BIN;
4,236✔
4540
  } else if (strcasecmp(binTypeStr, "log_bin") == 0) {
12,668,538!
4541
    binType = LOG_BIN;
12,668,910✔
4542
  } else {
4543
    binType = UNKNOWN_BIN;
×
4544
  }
4545

4546
  return binType;
12,676,328✔
4547
}
4548

4549
static int32_t getHistogramBinDesc(SHistoFuncInfo* pInfo, char* binDescStr, int8_t binType, bool normalized) {
12,676,252✔
4550
  cJSON*  binDesc = cJSON_Parse(binDescStr);
12,676,252✔
4551
  int32_t numOfBins;
4552
  double* intervals;
4553
  if (cJSON_IsObject(binDesc)) { /* linaer/log bins */
12,677,654✔
4554
    int32_t numOfParams = cJSON_GetArraySize(binDesc);
12,674,153✔
4555
    int32_t startIndex;
4556
    if (numOfParams != 4) {
12,674,091!
4557
      cJSON_Delete(binDesc);
×
4558
      return TSDB_CODE_FAILED;
×
4559
    }
4560

4561
    cJSON* start = cJSON_GetObjectItem(binDesc, "start");
12,674,091✔
4562
    cJSON* factor = cJSON_GetObjectItem(binDesc, "factor");
12,673,815✔
4563
    cJSON* width = cJSON_GetObjectItem(binDesc, "width");
12,673,721✔
4564
    cJSON* count = cJSON_GetObjectItem(binDesc, "count");
12,673,858✔
4565
    cJSON* infinity = cJSON_GetObjectItem(binDesc, "infinity");
12,674,051✔
4566

4567
    if (!cJSON_IsNumber(start) || !cJSON_IsNumber(count) || !cJSON_IsBool(infinity)) {
12,674,091!
4568
      cJSON_Delete(binDesc);
×
4569
      return TSDB_CODE_FAILED;
×
4570
    }
4571

4572
    if (count->valueint <= 0 || count->valueint > 1000) {  // limit count to 1000
12,674,077!
4573
      cJSON_Delete(binDesc);
×
4574
      return TSDB_CODE_FAILED;
×
4575
    }
4576

4577
    if (isinf(start->valuedouble) || (width != NULL && isinf(width->valuedouble)) ||
12,674,086!
4578
        (factor != NULL && isinf(factor->valuedouble)) || (count != NULL && isinf(count->valuedouble))) {
12,674,086!
4579
      cJSON_Delete(binDesc);
×
4580
      return TSDB_CODE_FAILED;
×
4581
    }
4582

4583
    int32_t counter = (int32_t)count->valueint;
12,674,086✔
4584
    if (infinity->valueint == false) {
12,674,086✔
4585
      startIndex = 0;
3,644,983✔
4586
      numOfBins = counter + 1;
3,644,983✔
4587
    } else {
4588
      startIndex = 1;
9,029,103✔
4589
      numOfBins = counter + 3;
9,029,103✔
4590
    }
4591

4592
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
12,674,086!
4593
    if (NULL == intervals) {
12,673,495!
4594
      cJSON_Delete(binDesc);
×
4595
      qError("histogram function out of memory");
×
4596
      return terrno;
×
4597
    }
4598
    if (cJSON_IsNumber(width) && factor == NULL && binType == LINEAR_BIN) {
12,673,495!
4599
      // linear bin process
4600
      if (width->valuedouble == 0) {
4,235!
4601
        taosMemoryFree(intervals);
×
4602
        cJSON_Delete(binDesc);
×
4603
        return TSDB_CODE_FAILED;
×
4604
      }
4605
      for (int i = 0; i < counter + 1; ++i) {
38,396✔
4606
        intervals[startIndex] = start->valuedouble + i * width->valuedouble;
34,161✔
4607
        if (isinf(intervals[startIndex])) {
34,161!
4608
          taosMemoryFree(intervals);
×
4609
          cJSON_Delete(binDesc);
×
4610
          return TSDB_CODE_FAILED;
×
4611
        }
4612
        startIndex++;
34,161✔
4613
      }
4614
    } else if (cJSON_IsNumber(factor) && width == NULL && binType == LOG_BIN) {
12,669,218!
4615
      // log bin process
4616
      if (start->valuedouble == 0) {
12,669,178!
4617
        taosMemoryFree(intervals);
×
4618
        cJSON_Delete(binDesc);
×
4619
        return TSDB_CODE_FAILED;
×
4620
      }
4621
      if (factor->valuedouble < 0 || factor->valuedouble == 0 || factor->valuedouble == 1) {
12,669,178!
4622
        taosMemoryFree(intervals);
55!
4623
        cJSON_Delete(binDesc);
×
4624
        return TSDB_CODE_FAILED;
×
4625
      }
4626
      for (int i = 0; i < counter + 1; ++i) {
88,672,242✔
4627
        intervals[startIndex] = start->valuedouble * pow(factor->valuedouble, i * 1.0);
76,003,119✔
4628
        if (isinf(intervals[startIndex])) {
76,003,119!
4629
          taosMemoryFree(intervals);
×
4630
          cJSON_Delete(binDesc);
×
4631
          return TSDB_CODE_FAILED;
×
4632
        }
4633
        startIndex++;
76,003,119✔
4634
      }
4635
    } else {
UNCOV
4636
      taosMemoryFree(intervals);
×
4637
      cJSON_Delete(binDesc);
×
4638
      return TSDB_CODE_FAILED;
×
4639
    }
4640

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

4691
  pInfo->numOfBins = numOfBins - 1;
12,676,913✔
4692
  pInfo->normalized = normalized;
12,676,913✔
4693
  for (int32_t i = 0; i < pInfo->numOfBins; ++i) {
94,114,594✔
4694
    pInfo->bins[i].lower = intervals[i] < intervals[i + 1] ? intervals[i] : intervals[i + 1];
81,437,681✔
4695
    pInfo->bins[i].upper = intervals[i + 1] > intervals[i] ? intervals[i + 1] : intervals[i];
81,437,681✔
4696
    pInfo->bins[i].count = 0;
81,437,681✔
4697
  }
4698

4699
  taosMemoryFree(intervals);
12,676,913!
4700
  cJSON_Delete(binDesc);
12,677,074✔
4701

4702
  return TSDB_CODE_SUCCESS;
12,677,313✔
4703
}
4704

4705
int32_t histogramFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
12,676,169✔
4706
  if (pResultInfo->initialized) {
12,676,169!
4707
    return TSDB_CODE_SUCCESS;
×
4708
  }
4709
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
12,676,169!
4710
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4711
  }
4712

4713
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
12,677,003✔
4714
  pInfo->numOfBins = 0;
12,677,003✔
4715
  pInfo->totalCount = 0;
12,677,003✔
4716
  pInfo->normalized = 0;
12,677,003✔
4717

4718
  char* binTypeStr = taosStrndup(varDataVal(pCtx->param[1].param.pz), varDataLen(pCtx->param[1].param.pz));
12,677,003!
4719
  if (binTypeStr == NULL) {
12,676,426!
4720
    return terrno;
×
4721
  }
4722
  int8_t binType = getHistogramBinType(binTypeStr);
12,676,426✔
4723
  taosMemoryFree(binTypeStr);
12,676,548!
4724

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

4744
  return TSDB_CODE_SUCCESS;
12,676,819✔
4745
}
4746

4747
static int32_t histogramFunctionImpl(SqlFunctionCtx* pCtx, bool isPartial) {
14,436,965✔
4748
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
14,436,965✔
4749

4750
  SInputColumnInfoData* pInput = &pCtx->input;
14,436,965✔
4751
  SColumnInfoData*      pCol = pInput->pData[0];
14,436,965✔
4752

4753
  int32_t type = pInput->pData[0]->info.type;
14,436,965✔
4754

4755
  int32_t start = pInput->startRowIndex;
14,436,965✔
4756
  int32_t numOfRows = pInput->numOfRows;
14,436,965✔
4757

4758
  int32_t numOfElems = 0;
14,436,965✔
4759
  for (int32_t i = start; i < numOfRows + start; ++i) {
53,573,804✔
4760
    if (pCol->hasNull && colDataIsNull_f(pCol->nullbitmap, i)) {
39,137,208✔
4761
      continue;
699,304✔
4762
    }
4763

4764
    numOfElems++;
38,437,904✔
4765

4766
    char*  data = colDataGetData(pCol, i);
38,437,904!
4767
    double v;
4768
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
38,437,904!
4769

4770
    for (int32_t k = 0; k < pInfo->numOfBins; ++k) {
113,843,232✔
4771
      if (v > pInfo->bins[k].lower && v <= pInfo->bins[k].upper) {
105,262,447✔
4772
        pInfo->bins[k].count++;
29,856,750✔
4773
        pInfo->totalCount++;
29,856,750✔
4774
        break;
29,856,750✔
4775
      }
4776
    }
4777
  }
4778

4779
  if (!isPartial) {
14,436,596✔
4780
    GET_RES_INFO(pCtx)->numOfRes = pInfo->numOfBins;
11,008,418✔
4781
  } else {
4782
    GET_RES_INFO(pCtx)->numOfRes = 1;
3,428,178✔
4783
  }
4784
  return TSDB_CODE_SUCCESS;
14,436,596✔
4785
}
4786

4787
int32_t histogramFunction(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, false); }
11,008,181✔
4788

4789
int32_t histogramFunctionPartial(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, true); }
3,429,211✔
4790

4791
static void histogramTransferInfo(SHistoFuncInfo* pInput, SHistoFuncInfo* pOutput) {
1,697,494✔
4792
  pOutput->normalized = pInput->normalized;
1,697,494✔
4793
  pOutput->numOfBins = pInput->numOfBins;
1,697,494✔
4794
  pOutput->totalCount += pInput->totalCount;
1,697,494✔
4795
  for (int32_t k = 0; k < pOutput->numOfBins; ++k) {
13,584,769✔
4796
    pOutput->bins[k].lower = pInput->bins[k].lower;
11,887,275✔
4797
    pOutput->bins[k].upper = pInput->bins[k].upper;
11,887,275✔
4798
    pOutput->bins[k].count += pInput->bins[k].count;
11,887,275✔
4799
  }
4800
}
1,697,494✔
4801

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

4809
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,697,494✔
4810

4811
  int32_t start = pInput->startRowIndex;
1,697,494✔
4812

4813
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
3,394,988✔
4814
    char*           data = colDataGetData(pCol, i);
1,697,494!
4815
    SHistoFuncInfo* pInputInfo = (SHistoFuncInfo*)varDataVal(data);
1,697,494✔
4816
    histogramTransferInfo(pInputInfo, pInfo);
1,697,494✔
4817
  }
4818

4819
  SET_VAL(GET_RES_INFO(pCtx), pInfo->numOfBins, pInfo->numOfBins);
1,697,494!
4820
  return TSDB_CODE_SUCCESS;
1,697,494✔
4821
}
4822

4823
int32_t histogramFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
12,630,526✔
4824
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
12,630,526✔
4825
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
12,630,526✔
4826
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
12,630,526✔
4827
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
12,630,526✔
4828
  int32_t              code = TSDB_CODE_SUCCESS;
12,622,130✔
4829

4830
  int32_t currentRow = pBlock->info.rows;
12,622,130✔
4831
  if (NULL == pCol) {
12,622,130!
4832
    return TSDB_CODE_OUT_OF_RANGE;
×
4833
  }
4834

4835
  if (pInfo->normalized) {
12,622,130✔
4836
    for (int32_t k = 0; k < pResInfo->numOfRes; ++k) {
68,037✔
4837
      if (pInfo->totalCount != 0) {
56,841✔
4838
        pInfo->bins[k].percentage = pInfo->bins[k].count / (double)pInfo->totalCount;
28,243✔
4839
      } else {
4840
        pInfo->bins[k].percentage = 0;
28,598✔
4841
      }
4842
    }
4843
  }
4844

4845
  for (int32_t i = 0; i < pResInfo->numOfRes; ++i) {
93,533,735✔
4846
    int32_t len;
4847
    char    buf[512] = {0};
81,146,246✔
4848
    if (!pInfo->normalized) {
81,146,246✔
4849
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
81,089,405✔
4850
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%" PRId64 "}", pInfo->bins[i].lower,
4851
                      pInfo->bins[i].upper, pInfo->bins[i].count);
4852
    } else {
4853
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
56,841✔
4854
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%lf}", pInfo->bins[i].lower, pInfo->bins[i].upper,
4855
                      pInfo->bins[i].percentage);
4856
    }
4857
    varDataSetLen(buf, len);
81,152,961✔
4858
    code = colDataSetVal(pCol, currentRow, buf, false);
81,152,961✔
4859
    if (TSDB_CODE_SUCCESS != code) {
80,911,605!
4860
      return code;
×
4861
    }
4862
    currentRow++;
80,911,605✔
4863
  }
4864

4865
  return code;
12,387,489✔
4866
}
4867

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

4874
  if (NULL == res) {
1,709,173!
4875
    return terrno;
×
4876
  }
4877
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
1,709,173✔
4878
  varDataSetLen(res, resultBytes);
1,709,173✔
4879

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

4889
_exit:
1,709,173✔
4890
  taosMemoryFree(res);
1,709,173!
4891
  return code;
1,709,174✔
4892
}
4893

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

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

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

4907
int32_t getHLLInfoSize() { return (int32_t)sizeof(SHLLInfo); }
10,839✔
4908

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

4914
static uint8_t hllCountNum(void* data, int32_t bytes, int32_t* buk) {
3,363,782✔
4915
  uint64_t hash = MurmurHash3_64(data, bytes);
3,363,782✔
4916
  int32_t  index = hash & HLL_BUCKET_MASK;
3,362,635✔
4917
  hash >>= HLL_BUCKET_BITS;
3,362,635✔
4918
  hash |= ((uint64_t)1 << HLL_DATA_BITS);
3,362,635✔
4919
  uint64_t bit = 1;
3,362,635✔
4920
  uint8_t  count = 1;
3,362,635✔
4921
  while ((hash & bit) == 0) {
6,278,189✔
4922
    count++;
2,915,554✔
4923
    bit <<= 1;
2,915,554✔
4924
  }
4925
  *buk = index;
3,362,635✔
4926
  return count;
3,362,635✔
4927
}
4928

4929
static void hllBucketHisto(uint8_t* buckets, int32_t* bucketHisto) {
162,862✔
4930
  uint64_t* word = (uint64_t*)buckets;
162,862✔
4931
  uint8_t*  bytes;
4932

4933
  for (int32_t j = 0; j < HLL_BUCKETS >> 3; j++) {
326,958,038✔
4934
    if (*word == 0) {
326,795,176✔
4935
      bucketHisto[0] += 8;
326,024,831✔
4936
    } else {
4937
      bytes = (uint8_t*)word;
770,345✔
4938
      bucketHisto[bytes[0]]++;
770,345✔
4939
      bucketHisto[bytes[1]]++;
770,345✔
4940
      bucketHisto[bytes[2]]++;
770,345✔
4941
      bucketHisto[bytes[3]]++;
770,345✔
4942
      bucketHisto[bytes[4]]++;
770,345✔
4943
      bucketHisto[bytes[5]]++;
770,345✔
4944
      bucketHisto[bytes[6]]++;
770,345✔
4945
      bucketHisto[bytes[7]]++;
770,345✔
4946
    }
4947
    word++;
326,795,176✔
4948
  }
4949
}
162,862✔
4950
static double hllTau(double x) {
162,868✔
4951
  if (x == 0. || x == 1.) return 0.;
162,868!
4952
  double zPrime;
4953
  double y = 1.0;
×
4954
  double z = 1 - x;
×
4955
  do {
4956
    x = sqrt(x);
×
4957
    zPrime = z;
×
4958
    y *= 0.5;
×
4959
    z -= pow(1 - x, 2) * y;
×
4960
  } while (zPrime != z);
×
4961
  return z / 3;
×
4962
}
4963

4964
static double hllSigma(double x) {
162,878✔
4965
  if (x == 1.0) return INFINITY;
162,878✔
4966
  double zPrime;
4967
  double y = 1;
124,953✔
4968
  double z = x;
124,953✔
4969
  do {
4970
    x *= x;
2,441,902✔
4971
    zPrime = z;
2,441,902✔
4972
    z += x * y;
2,441,902✔
4973
    y += y;
2,441,902✔
4974
  } while (zPrime != z);
2,441,902✔
4975
  return z;
124,953✔
4976
}
4977

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

4985
  double z = m * hllTau((m - buckethisto[HLL_DATA_BITS + 1]) / (double)m);
162,868✔
4986
  for (int j = HLL_DATA_BITS; j >= 1; --j) {
8,303,337✔
4987
    z += buckethisto[j];
8,140,461✔
4988
    z *= 0.5;
8,140,461✔
4989
  }
4990

4991
  z += m * hllSigma(buckethisto[0] / (double)m);
162,876✔
4992
  double E = (double)llroundl(HLL_ALPHA_INF * m * m / z);
162,887✔
4993

4994
  return (uint64_t)E;
162,887✔
4995
}
4996

4997
int32_t hllFunction(SqlFunctionCtx* pCtx) {
180,865✔
4998
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
180,865✔
4999

5000
  SInputColumnInfoData* pInput = &pCtx->input;
180,865✔
5001
  SColumnInfoData*      pCol = pInput->pData[0];
180,865✔
5002

5003
  int32_t type = pCol->info.type;
180,865✔
5004
  int32_t bytes = pCol->info.bytes;
180,865✔
5005

5006
  int32_t start = pInput->startRowIndex;
180,865✔
5007
  int32_t numOfRows = pInput->numOfRows;
180,865✔
5008

5009
  int32_t numOfElems = 0;
180,865✔
5010
  if (IS_NULL_TYPE(type)) {
180,865✔
5011
    goto _hll_over;
1,704✔
5012
  }
5013

5014
  for (int32_t i = start; i < numOfRows + start; ++i) {
4,574,635✔
5015
    if (pCol->hasNull && colDataIsNull_s(pCol, i)) {
6,119,952!
5016
      continue;
1,030,853✔
5017
    }
5018

5019
    numOfElems++;
3,365,778✔
5020

5021
    char* data = colDataGetData(pCol, i);
3,365,778!
5022
    if (IS_VAR_DATA_TYPE(type)) {
3,365,778!
5023
      bytes = varDataLen(data);
806,355✔
5024
      data = varDataVal(data);
806,355✔
5025
    }
5026

5027
    int32_t index = 0;
3,365,778✔
5028
    uint8_t count = hllCountNum(data, bytes, &index);
3,365,778✔
5029
    uint8_t oldcount = pInfo->buckets[index];
3,364,621✔
5030
    if (count > oldcount) {
3,364,621✔
5031
      pInfo->buckets[index] = count;
799,245✔
5032
    }
5033
  }
5034

5035
_hll_over:
178,004✔
5036
  pInfo->totalCount += numOfElems;
179,708✔
5037

5038
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
179,708✔
5039
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
957✔
5040
  } else {
5041
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
178,751✔
5042
  }
5043

5044
  return TSDB_CODE_SUCCESS;
179,708✔
5045
}
5046

5047
static void hllTransferInfo(SHLLInfo* pInput, SHLLInfo* pOutput) {
11,058✔
5048
  for (int32_t k = 0; k < HLL_BUCKETS; ++k) {
177,424,510✔
5049
    if (pOutput->buckets[k] < pInput->buckets[k]) {
177,413,452✔
5050
      pOutput->buckets[k] = pInput->buckets[k];
248,027✔
5051
    }
5052
  }
5053
  pOutput->totalCount += pInput->totalCount;
11,058✔
5054
}
11,058✔
5055

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

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

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

5069
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
10,987✔
5070

5071
  int32_t start = pInput->startRowIndex;
10,987✔
5072

5073
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
22,045✔
5074
    if (colDataIsNull_s(pCol, i)) continue;
22,114!
5075
    char*     data = colDataGetData(pCol, i);
11,057!
5076
    SHLLInfo* pInputInfo = (SHLLInfo*)varDataVal(data);
11,057✔
5077
    hllTransferInfo(pInputInfo, pInfo);
11,057✔
5078
  }
5079

5080
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
10,988✔
5081
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
5✔
5082
  } else {
5083
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
10,983✔
5084
  }
5085

5086
  return TSDB_CODE_SUCCESS;
10,988✔
5087
}
5088

5089
int32_t hllFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
162,837✔
5090
  SResultRowEntryInfo* pInfo = GET_RES_INFO(pCtx);
162,837✔
5091

5092
  SHLLInfo* pHllInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
162,837✔
5093
  pHllInfo->result = hllCountCnt(pHllInfo->buckets);
162,837✔
5094
  if (tsCountAlwaysReturnValue && pHllInfo->result == 0) {
162,887✔
5095
    pInfo->numOfRes = 1;
37,003✔
5096
  }
5097

5098
  return functionFinalize(pCtx, pBlock);
162,887✔
5099
}
5100

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

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

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

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

5123
_exit:
10,840✔
5124
  taosMemoryFree(res);
10,840!
5125
  return code;
10,841✔
5126
}
5127

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

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

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

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

5146
static int8_t getStateOpType(char* opStr) {
41,133✔
5147
  int8_t opType;
5148
  if (strncasecmp(opStr, "LT", 2) == 0) {
41,133✔
5149
    opType = STATE_OPER_LT;
2,702✔
5150
  } else if (strncasecmp(opStr, "GT", 2) == 0) {
38,431✔
5151
    opType = STATE_OPER_GT;
20,166✔
5152
  } else if (strncasecmp(opStr, "LE", 2) == 0) {
18,265✔
5153
    opType = STATE_OPER_LE;
992✔
5154
  } else if (strncasecmp(opStr, "GE", 2) == 0) {
17,273✔
5155
    opType = STATE_OPER_GE;
2,796✔
5156
  } else if (strncasecmp(opStr, "NE", 2) == 0) {
14,477✔
5157
    opType = STATE_OPER_NE;
13,401✔
5158
  } else if (strncasecmp(opStr, "EQ", 2) == 0) {
1,076!
5159
    opType = STATE_OPER_EQ;
1,076✔
5160
  } else {
5161
    opType = STATE_OPER_INVALID;
×
5162
  }
5163

5164
  return opType;
41,133✔
5165
}
5166

5167
static bool checkStateOp(int8_t op, SColumnInfoData* pCol, int32_t index, SVariant param) {
35,335,878✔
5168
  char* data = colDataGetData(pCol, index);
35,335,878!
5169
  switch (pCol->info.type) {
35,335,878!
5170
    case TSDB_DATA_TYPE_TINYINT: {
34,396✔
5171
      int8_t v = *(int8_t*)data;
34,396✔
5172
      STATE_COMP(op, v, param);
34,396!
5173
      break;
×
5174
    }
5175
    case TSDB_DATA_TYPE_UTINYINT: {
5,760✔
5176
      uint8_t v = *(uint8_t*)data;
5,760✔
5177
      STATE_COMP(op, v, param);
5,760!
5178
      break;
×
5179
    }
5180
    case TSDB_DATA_TYPE_SMALLINT: {
22,604,301✔
5181
      int16_t v = *(int16_t*)data;
22,604,301✔
5182
      STATE_COMP(op, v, param);
22,604,301!
5183
      break;
×
5184
    }
5185
    case TSDB_DATA_TYPE_USMALLINT: {
5,760✔
5186
      uint16_t v = *(uint16_t*)data;
5,760✔
5187
      STATE_COMP(op, v, param);
5,760!
5188
      break;
×
5189
    }
5190
    case TSDB_DATA_TYPE_INT: {
68,024✔
5191
      int32_t v = *(int32_t*)data;
68,024✔
5192
      STATE_COMP(op, v, param);
68,024!
5193
      break;
×
5194
    }
5195
    case TSDB_DATA_TYPE_UINT: {
5,760✔
5196
      uint32_t v = *(uint32_t*)data;
5,760✔
5197
      STATE_COMP(op, v, param);
5,760!
5198
      break;
×
5199
    }
5200
    case TSDB_DATA_TYPE_BIGINT: {
92,968✔
5201
      int64_t v = *(int64_t*)data;
92,968✔
5202
      STATE_COMP(op, v, param);
92,968!
5203
      break;
×
5204
    }
5205
    case TSDB_DATA_TYPE_UBIGINT: {
5,760✔
5206
      uint64_t v = *(uint64_t*)data;
5,760✔
5207
      STATE_COMP(op, v, param);
5,760!
5208
      break;
×
5209
    }
5210
    case TSDB_DATA_TYPE_FLOAT: {
12,318,993✔
5211
      float v = *(float*)data;
12,318,993✔
5212
      STATE_COMP(op, v, param);
12,318,993!
5213
      break;
×
5214
    }
5215
    case TSDB_DATA_TYPE_DOUBLE: {
194,156✔
5216
      double v = *(double*)data;
194,156✔
5217
      STATE_COMP(op, v, param);
194,156!
5218
      break;
×
5219
    }
5220
    default: {
×
5221
      return false;
×
5222
    }
5223
  }
5224
  return false;
×
5225
}
5226

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

5232
  SInputColumnInfoData* pInput = &pCtx->input;
20,567✔
5233
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
20,567✔
5234

5235
  SColumnInfoData* pInputCol = pInput->pData[0];
20,567✔
5236

5237
  int32_t          numOfElems = 0;
20,567✔
5238
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
20,567✔
5239

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

5245
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
22,894,292✔
5246
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
22,873,725!
5247
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5248
    } else {
5249
      pInfo->prevTs = tsList[i];
22,873,725✔
5250
    }
5251

5252
    pInfo->isPrevTsSet = true;
22,873,725✔
5253
    numOfElems++;
22,873,725✔
5254

5255
    if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
22,873,725✔
5256
      colDataSetNULL(pOutput, i);
144,324!
5257
      // handle selectivity
5258
      if (pCtx->subsidiaries.num > 0) {
144,324✔
5259
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
36✔
5260
        if (TSDB_CODE_SUCCESS != code) {
36!
5261
          return code;
×
5262
        }
5263
      }
5264
      continue;
144,324✔
5265
    }
5266

5267
    bool ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
22,729,401✔
5268

5269
    int64_t output = -1;
22,729,401✔
5270
    if (ret) {
22,729,401✔
5271
      output = ++pInfo->count;
11,093,323✔
5272
    } else {
5273
      pInfo->count = 0;
11,636,078✔
5274
    }
5275
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
22,729,401✔
5276
    if (TSDB_CODE_SUCCESS != code) {
22,729,401!
5277
      return code;
×
5278
    }
5279

5280
    // handle selectivity
5281
    if (pCtx->subsidiaries.num > 0) {
22,729,401✔
5282
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
16,531,884✔
5283
      if (TSDB_CODE_SUCCESS != code) {
16,531,884!
5284
        return code;
×
5285
      }
5286
    }
5287
  }
5288

5289
  pResInfo->numOfRes = numOfElems;
20,567✔
5290
  return TSDB_CODE_SUCCESS;
20,567✔
5291
}
5292

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

5298
  SInputColumnInfoData* pInput = &pCtx->input;
20,566✔
5299
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
20,566✔
5300

5301
  SColumnInfoData* pInputCol = pInput->pData[0];
20,566✔
5302

5303
  int32_t          numOfElems = 0;
20,566✔
5304
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
20,566✔
5305

5306
  // TODO: process timeUnit for different db precisions
5307
  int32_t timeUnit = 1;
20,566✔
5308
  if (pCtx->numOfParams == 5) {  // TODO: param number incorrect
20,566✔
5309
    timeUnit = pCtx->param[3].param.i;
18,606✔
5310
  }
5311

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

5317
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
12,877,427✔
5318
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
12,856,861!
5319
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5320
    } else {
5321
      pInfo->prevTs = tsList[i];
12,856,861✔
5322
    }
5323

5324
    pInfo->isPrevTsSet = true;
12,856,861✔
5325
    numOfElems++;
12,856,861✔
5326

5327
    if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
12,856,861✔
5328
      colDataSetNULL(pOutput, i);
250,384!
5329
      // handle selectivity
5330
      if (pCtx->subsidiaries.num > 0) {
250,384✔
5331
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
52✔
5332
        if (TSDB_CODE_SUCCESS != code) {
52!
5333
          return code;
×
5334
        }
5335
      }
5336
      continue;
250,384✔
5337
    }
5338

5339
    bool    ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
12,606,477✔
5340
    int64_t output = -1;
12,606,477✔
5341
    if (ret) {
12,606,477✔
5342
      if (pInfo->durationStart == 0) {
12,422,292✔
5343
        output = 0;
74,108✔
5344
        pInfo->durationStart = tsList[i];
74,108✔
5345
      } else {
5346
        output = (tsList[i] - pInfo->durationStart) / timeUnit;
12,348,184✔
5347
      }
5348
    } else {
5349
      pInfo->durationStart = 0;
184,185✔
5350
    }
5351
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
12,606,477✔
5352
    if (TSDB_CODE_SUCCESS != code) {
12,606,477!
5353
      return code;
×
5354
    }
5355

5356
    // handle selectivity
5357
    if (pCtx->subsidiaries.num > 0) {
12,606,477✔
5358
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
3,686,934✔
5359
      if (TSDB_CODE_SUCCESS != code) {
3,686,934!
5360
        return code;
×
5361
      }
5362
    }
5363
  }
5364

5365
  pResInfo->numOfRes = numOfElems;
20,566✔
5366
  return TSDB_CODE_SUCCESS;
20,566✔
5367
}
5368

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

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

5379
  SInputColumnInfoData* pInput = &pCtx->input;
23,738✔
5380
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
23,738✔
5381

5382
  SColumnInfoData* pInputCol = pInput->pData[0];
23,738✔
5383
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
23,738✔
5384

5385
  int32_t numOfElems = 0;
23,738✔
5386
  int32_t type = pInputCol->info.type;
23,738✔
5387
  int32_t startOffset = pCtx->offset;
23,738✔
5388
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
3,321,049✔
5389
    if (pSumRes->isPrevTsSet == true && tsList[i] == pSumRes->prevTs) {
3,297,343✔
5390
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
27✔
5391
    } else {
5392
      pSumRes->prevTs = tsList[i];
3,297,316✔
5393
    }
5394
    pSumRes->isPrevTsSet = true;
3,297,316✔
5395

5396
    int32_t pos = startOffset + numOfElems;
3,297,316✔
5397
    if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
3,297,316✔
5398
      // colDataSetNULL(pOutput, i);
5399
      continue;
418,669✔
5400
    }
5401

5402
    char* data = colDataGetData(pInputCol, i);
2,878,647!
5403
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
5,533,581✔
5404
      int64_t v;
5405
      GET_TYPED_DATA(v, int64_t, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
2,654,934!
5406
      pSumRes->isum += v;
2,654,934✔
5407
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->isum, false);
2,654,934✔
5408
      if (TSDB_CODE_SUCCESS != code) {
2,654,934!
5409
        return code;
×
5410
      }
5411
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
224,393!
5412
      uint64_t v;
5413
      GET_TYPED_DATA(v, uint64_t, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
680!
5414
      pSumRes->usum += v;
680✔
5415
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->usum, false);
680✔
5416
      if (TSDB_CODE_SUCCESS != code) {
680!
5417
        return code;
×
5418
      }
5419
    } else if (IS_FLOAT_TYPE(type)) {
223,033!
5420
      double v;
5421
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
223,900!
5422
      pSumRes->dsum += v;
223,895✔
5423
      // check for overflow
5424
      if (isinf(pSumRes->dsum) || isnan(pSumRes->dsum)) {
223,895!
5425
        colDataSetNULL(pOutput, pos);
8!
5426
      } else {
5427
        code = colDataSetVal(pOutput, pos, (char*)&pSumRes->dsum, false);
223,887✔
5428
        if (TSDB_CODE_SUCCESS != code) {
223,887!
5429
          return code;
×
5430
        }
5431
      }
5432
    }
5433

5434
    // handle selectivity
5435
    if (pCtx->subsidiaries.num > 0) {
2,878,642✔
5436
      code = appendSelectivityValue(pCtx, i, pos);
1,653,676✔
5437
      if (TSDB_CODE_SUCCESS != code) {
1,653,676!
5438
        return code;
×
5439
      }
5440
    }
5441

5442
    numOfElems++;
2,878,642✔
5443
  }
5444

5445
  pResInfo->numOfRes = numOfElems;
23,706✔
5446
  return TSDB_CODE_SUCCESS;
23,706✔
5447
}
5448

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

5454
int32_t mavgFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
253,642✔
5455
  if (pResultInfo->initialized) {
253,642✔
5456
    return TSDB_CODE_SUCCESS;
238,934✔
5457
  }
5458
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
14,708!
5459
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5460
  }
5461

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

5473
  return TSDB_CODE_SUCCESS;
14,707✔
5474
}
5475

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

5481
  SInputColumnInfoData* pInput = &pCtx->input;
239,943✔
5482
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
239,943✔
5483

5484
  SColumnInfoData* pInputCol = pInput->pData[0];
239,943✔
5485
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
239,943✔
5486
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
239,943✔
5487

5488
  int32_t numOfElems = 0;
239,943✔
5489
  int32_t type = pInputCol->info.type;
239,943✔
5490
  int32_t startOffset = pCtx->offset;
239,943✔
5491
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
59,150,435✔
5492
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
58,910,492!
5493
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5494
    } else {
5495
      pInfo->prevTs = tsList[i];
58,910,492✔
5496
    }
5497
    pInfo->isPrevTsSet = true;
58,910,492✔
5498

5499
    int32_t pos = startOffset + numOfElems;
58,910,492✔
5500
    if (colDataIsNull_f(pInputCol->nullbitmap, i)) {
58,910,492✔
5501
      // colDataSetNULL(pOutput, i);
5502
      continue;
387,626✔
5503
    }
5504

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

5509
    if (!pInfo->pointsMeet && (pInfo->pos < pInfo->numOfPoints - 1)) {
58,522,866✔
5510
      pInfo->points[pInfo->pos] = v;
6,047,980✔
5511
      pInfo->sum += v;
6,047,980✔
5512
    } else {
5513
      if (!pInfo->pointsMeet && (pInfo->pos == pInfo->numOfPoints - 1)) {
52,474,886!
5514
        pInfo->sum += v;
10,729✔
5515
        pInfo->pointsMeet = true;
10,729✔
5516
      } else {
5517
        pInfo->sum = pInfo->sum + v - pInfo->points[pInfo->pos];
52,464,157✔
5518
      }
5519

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

5532
      // handle selectivity
5533
      if (pCtx->subsidiaries.num > 0) {
52,474,886✔
5534
        code = appendSelectivityValue(pCtx, i, pos);
33,356,479✔
5535
        if (TSDB_CODE_SUCCESS != code) {
33,356,479!
5536
          return code;
×
5537
        }
5538
      }
5539

5540
      numOfElems++;
52,474,886✔
5541
    }
5542

5543
    pInfo->pos++;
58,522,866✔
5544
    if (pInfo->pos == pInfo->numOfPoints) {
58,522,866✔
5545
      pInfo->pos = 0;
112,319✔
5546
    }
5547
  }
5548

5549
  pResInfo->numOfRes = numOfElems;
239,943✔
5550
  return TSDB_CODE_SUCCESS;
239,943✔
5551
}
5552

5553
static SSampleInfo* getSampleOutputInfo(SqlFunctionCtx* pCtx) {
14,293,097✔
5554
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
14,293,097✔
5555
  SSampleInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
14,293,097✔
5556

5557
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
14,293,097✔
5558
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
14,293,097✔
5559

5560
  return pInfo;
14,293,097✔
5561
}
5562

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

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

5579
  taosSeedRand(taosSafeRand());
7,225,773✔
5580

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

5592
  return TSDB_CODE_SUCCESS;
7,225,773✔
5593
}
5594

5595
static void sampleAssignResult(SSampleInfo* pInfo, char* data, int32_t index) {
15,772,399✔
5596
  assignVal(pInfo->data + index * pInfo->colBytes, data, pInfo->colBytes, pInfo->colType);
15,772,399✔
5597
}
15,772,431✔
5598

5599
static int32_t doReservoirSample(SqlFunctionCtx* pCtx, SSampleInfo* pInfo, char* data, int32_t index) {
16,157,322✔
5600
  pInfo->totalPoints++;
16,157,322✔
5601
  if (pInfo->numSampled < pInfo->samples) {
16,157,322✔
5602
    sampleAssignResult(pInfo, data, pInfo->numSampled);
15,243,894✔
5603
    if (pCtx->subsidiaries.num > 0) {
15,243,865✔
5604
      int32_t code = saveTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[pInfo->numSampled]);
1,003,000✔
5605
      if (code != TSDB_CODE_SUCCESS) {
1,003,023!
5606
        return code;
×
5607
      }
5608
    }
5609
    pInfo->numSampled++;
15,243,888✔
5610
  } else {
5611
    int32_t j = taosRand() % (pInfo->totalPoints);
913,428✔
5612
    if (j < pInfo->samples) {
914,655✔
5613
      sampleAssignResult(pInfo, data, j);
528,978✔
5614
      if (pCtx->subsidiaries.num > 0) {
528,972✔
5615
        int32_t code = updateTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[j]);
452,927✔
5616
        if (code != TSDB_CODE_SUCCESS) {
451,985!
5617
          return code;
×
5618
        }
5619
      }
5620
    }
5621
  }
5622

5623
  return TSDB_CODE_SUCCESS;
16,157,595✔
5624
}
5625

5626
int32_t sampleFunction(SqlFunctionCtx* pCtx) {
7,229,296✔
5627
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,229,296✔
5628
  SSampleInfo*         pInfo = getSampleOutputInfo(pCtx);
7,229,296✔
5629

5630
  SInputColumnInfoData* pInput = &pCtx->input;
7,229,295✔
5631

5632
  SColumnInfoData* pInputCol = pInput->pData[0];
7,229,295✔
5633
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
23,998,732✔
5634
    if (colDataIsNull_s(pInputCol, i)) {
33,538,938✔
5635
      continue;
611,922✔
5636
    }
5637

5638
    char*   data = colDataGetData(pInputCol, i);
16,157,547!
5639
    int32_t code = doReservoirSample(pCtx, pInfo, data, i);
16,157,547✔
5640
    if (code != TSDB_CODE_SUCCESS) {
16,157,515!
5641
      return code;
×
5642
    }
5643
  }
5644

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

5653
  SET_VAL(pResInfo, pInfo->numSampled, pInfo->numSampled);
7,229,263✔
5654
  return TSDB_CODE_SUCCESS;
7,229,263✔
5655
}
5656

5657
int32_t sampleFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
7,063,804✔
5658
  int32_t              code = TSDB_CODE_SUCCESS;
7,063,804✔
5659
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
7,063,804✔
5660

5661
  SSampleInfo* pInfo = getSampleOutputInfo(pCtx);
7,063,804✔
5662
  pEntryInfo->complete = true;
7,063,805✔
5663

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

5670
  int32_t currentRow = pBlock->info.rows;
7,063,805✔
5671
  if (pInfo->numSampled == 0) {
7,063,805✔
5672
    colDataSetNULL(pCol, currentRow);
3,589✔
5673
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
3,589✔
5674
    return code;
3,588✔
5675
  }
5676
  for (int32_t i = 0; i < pInfo->numSampled; ++i) {
22,007,428✔
5677
    code = colDataSetVal(pCol, currentRow + i, pInfo->data + i * pInfo->colBytes, false);
14,947,368✔
5678
    if (TSDB_CODE_SUCCESS != code) {
14,947,120!
5679
      return code;
×
5680
    }
5681
    code = setSelectivityValue(pCtx, pBlock, &pInfo->tuplePos[i], currentRow + i);
14,947,120✔
5682
    if (TSDB_CODE_SUCCESS != code) {
14,947,212!
5683
      return code;
×
5684
    }
5685
  }
5686

5687
  return code;
7,060,060✔
5688
}
5689

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

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

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

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

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

5731
  return TSDB_CODE_SUCCESS;
×
5732
}
5733

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5829
bool getUniqueFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
5830
#if 0
5831
  pEnv->calcMemSize = sizeof(SUniqueInfo) + UNIQUE_MAX_RESULT_SIZE;
5832
#endif
5833
  return true;
×
5834
}
5835

5836
int32_t uniqueFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
×
5837
#if 0
5838
  if (!functionSetup(pCtx, pResInfo)) {
5839
    return false;
5840
  }
5841

5842
  SUniqueInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5843
  pInfo->numOfPoints = 0;
5844
  pInfo->colType = pCtx->resDataInfo.type;
5845
  pInfo->colBytes = pCtx->resDataInfo.bytes;
5846
  if (pInfo->pHash != NULL) {
5847
    taosHashClear(pInfo->pHash);
5848
  } else {
5849
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
5850
  }
5851
#endif
5852
  return TSDB_CODE_SUCCESS;
×
5853
}
5854

5855
#if 0
5856
static void doUniqueAdd(SUniqueInfo* pInfo, char* data, TSKEY ts, bool isNull) {
5857
  // handle null elements
5858
  if (isNull == true) {
5859
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
5860
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
5861
    if (pInfo->hasNull == false && pItem->isNull == false) {
5862
      pItem->timestamp = ts;
5863
      pItem->isNull = true;
5864
      pInfo->numOfPoints++;
5865
      pInfo->hasNull = true;
5866
    } else if (pItem->timestamp > ts && pItem->isNull == true) {
5867
      pItem->timestamp = ts;
5868
    }
5869
    return;
5870
  }
5871

5872
  int32_t      hashKeyBytes = IS_VAR_DATA_TYPE(pInfo->colType) ? varDataTLen(data) : pInfo->colBytes;
5873
  SUniqueItem* pHashItem = taosHashGet(pInfo->pHash, data, hashKeyBytes);
5874
  if (pHashItem == NULL) {
5875
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
5876
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
5877
    pItem->timestamp = ts;
5878
    memcpy(pItem->data, data, pInfo->colBytes);
5879

5880
    taosHashPut(pInfo->pHash, data, hashKeyBytes, (char*)pItem, sizeof(SUniqueItem*));
5881
    pInfo->numOfPoints++;
5882
  } else if (pHashItem->timestamp > ts) {
5883
    pHashItem->timestamp = ts;
5884
  }
5885
}
5886
#endif
5887

5888
int32_t uniqueFunction(SqlFunctionCtx* pCtx) {
×
5889
#if 0
5890
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5891
  SUniqueInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5892

5893
  SInputColumnInfoData* pInput = &pCtx->input;
5894
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
5895

5896
  SColumnInfoData* pInputCol = pInput->pData[0];
5897
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
5898
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
5899

5900
  int32_t startOffset = pCtx->offset;
5901
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
5902
    char* data = colDataGetData(pInputCol, i);
5903
    doUniqueAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
5904

5905
    if (sizeof(SUniqueInfo) + pInfo->numOfPoints * (sizeof(SUniqueItem) + pInfo->colBytes) >= UNIQUE_MAX_RESULT_SIZE) {
5906
      taosHashCleanup(pInfo->pHash);
5907
      return 0;
5908
    }
5909
  }
5910

5911
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5912
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + i * (sizeof(SUniqueItem) + pInfo->colBytes));
5913
    if (pItem->isNull == true) {
5914
      colDataSetNULL(pOutput, i);
5915
    } else {
5916
      colDataSetVal(pOutput, i, pItem->data, false);
5917
    }
5918
    if (pTsOutput != NULL) {
5919
      colDataSetInt64(pTsOutput, i, &pItem->timestamp);
5920
    }
5921
  }
5922

5923
  return pInfo->numOfPoints;
5924
#endif
5925
  return 0;
×
5926
}
5927

5928
bool getModeFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
25,039✔
5929
  pEnv->calcMemSize = sizeof(SModeInfo);
25,039✔
5930
  return true;
25,039✔
5931
}
5932

5933
int32_t modeFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
26,004✔
5934
  if (pResInfo->initialized) {
26,004!
5935
    return TSDB_CODE_SUCCESS;
×
5936
  }
5937
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
26,004!
5938
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5939
  }
5940

5941
  SModeInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
26,004✔
5942
  pInfo->colType = pCtx->resDataInfo.type;
26,004✔
5943
  pInfo->colBytes = pCtx->resDataInfo.bytes;
26,004✔
5944
  if (pInfo->pHash != NULL) {
26,004!
5945
    taosHashClear(pInfo->pHash);
×
5946
  } else {
5947
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
26,004✔
5948
    if (NULL == pInfo->pHash) {
26,006!
5949
      return terrno;
×
5950
    }
5951
  }
5952
  pInfo->nullTupleSaved = false;
26,006✔
5953
  pInfo->nullTuplePos.pageId = -1;
26,006✔
5954

5955
  pInfo->buf = taosMemoryMalloc(pInfo->colBytes);
26,006!
5956
  if (NULL == pInfo->buf) {
26,006!
5957
    taosHashCleanup(pInfo->pHash);
×
5958
    pInfo->pHash = NULL;
×
5959
    return terrno;
×
5960
  }
5961
  pCtx->needCleanup = true;
26,006✔
5962
  return TSDB_CODE_SUCCESS;
26,006✔
5963
}
5964

5965
static void modeFunctionCleanup(SModeInfo* pInfo) {
26,005✔
5966
  taosHashCleanup(pInfo->pHash);
26,005✔
5967
  pInfo->pHash = NULL;
26,006✔
5968
  taosMemoryFreeClear(pInfo->buf);
26,006!
5969
}
26,005✔
5970

5971
void modeFunctionCleanupExt(SqlFunctionCtx* pCtx) {
×
5972
  if (pCtx == NULL || GET_RES_INFO(pCtx) == NULL || GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)) == NULL) {
×
5973
    return;
×
5974
  }
5975
  modeFunctionCleanup(GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)));
×
5976
}
5977

5978
static int32_t saveModeTupleData(SqlFunctionCtx* pCtx, char* data, SModeInfo* pInfo, STuplePos* pPos) {
26,350,246✔
5979
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
26,350,246!
5980
    if (pInfo->colType == TSDB_DATA_TYPE_JSON) {
2,886,634!
5981
      (void)memcpy(pInfo->buf, data, getJsonValueLen(data));
×
5982
    } else {
5983
      (void)memcpy(pInfo->buf, data, varDataTLen(data));
2,886,634✔
5984
    }
5985
  } else {
5986
    (void)memcpy(pInfo->buf, data, pInfo->colBytes);
23,463,612✔
5987
  }
5988

5989
  return doSaveTupleData(&pCtx->saveHandle, pInfo->buf, pInfo->colBytes, NULL, pPos, pCtx->pStore);
26,350,246✔
5990
}
5991

5992
static int32_t doModeAdd(SModeInfo* pInfo, int32_t rowIndex, SqlFunctionCtx* pCtx, char* data) {
124,279,012✔
5993
  int32_t code = TSDB_CODE_SUCCESS;
124,279,012✔
5994
  int32_t hashKeyBytes;
5995
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
124,279,012!
5996
    if (pInfo->colType == TSDB_DATA_TYPE_JSON) {
2,886,427!
5997
      hashKeyBytes = getJsonValueLen(data);
×
5998
    } else {
5999
      hashKeyBytes = varDataTLen(data);
2,886,427✔
6000
    }
6001
  } else {
6002
    hashKeyBytes = pInfo->colBytes;
121,392,585✔
6003
  }
6004

6005
  SModeItem* pHashItem = (SModeItem*)taosHashGet(pInfo->pHash, data, hashKeyBytes);
124,279,853✔
6006
  if (pHashItem == NULL) {
124,278,373✔
6007
    int32_t   size = sizeof(SModeItem);
26,350,304✔
6008
    SModeItem item = {0};
26,350,304✔
6009

6010
    item.count += 1;
26,350,304✔
6011
    code = saveModeTupleData(pCtx, data, pInfo, &item.dataPos);
26,350,304✔
6012
    if (code != TSDB_CODE_SUCCESS) {
26,349,313!
6013
      return code;
×
6014
    }
6015

6016
    if (pCtx->subsidiaries.num > 0) {
26,349,313✔
6017
      code = saveTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &item.tuplePos);
11,572,125✔
6018
      if (code != TSDB_CODE_SUCCESS) {
11,572,125!
6019
        return code;
×
6020
      }
6021
    }
6022

6023
    code = taosHashPut(pInfo->pHash, data, hashKeyBytes, &item, sizeof(SModeItem));
26,349,313✔
6024
    if (code != TSDB_CODE_SUCCESS) {
26,351,868!
6025
      return code;
×
6026
    }
6027
  } else {
6028
    pHashItem->count += 1;
97,928,069✔
6029
    if (pCtx->subsidiaries.num > 0) {
97,928,069✔
6030
      code = updateTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &pHashItem->tuplePos);
61,294,419✔
6031
      if (code != TSDB_CODE_SUCCESS) {
61,294,419!
6032
        return code;
×
6033
      }
6034
    }
6035
  }
6036

6037
  return code;
124,279,937✔
6038
}
6039

6040
int32_t modeFunction(SqlFunctionCtx* pCtx) {
2,112,214✔
6041
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,112,214✔
6042
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,112,214✔
6043

6044
  SInputColumnInfoData* pInput = &pCtx->input;
2,112,214✔
6045

6046
  SColumnInfoData* pInputCol = pInput->pData[0];
2,112,214✔
6047
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
2,112,214✔
6048

6049
  int32_t numOfElems = 0;
2,112,214✔
6050
  int32_t startOffset = pCtx->offset;
2,112,214✔
6051
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
126,704,301✔
6052
    if (colDataIsNull_s(pInputCol, i)) {
249,184,276✔
6053
      continue;
312,862✔
6054
    }
6055
    numOfElems++;
124,279,276✔
6056

6057
    char*   data = colDataGetData(pInputCol, i);
124,279,276!
6058
    int32_t code = doModeAdd(pInfo, i, pCtx, data);
124,279,276✔
6059
    if (code != TSDB_CODE_SUCCESS) {
124,279,920✔
6060
      modeFunctionCleanup(pInfo);
695✔
6061
      return code;
×
6062
    }
6063
  }
6064

6065
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
2,112,163!
6066
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
50✔
6067
    if (code != TSDB_CODE_SUCCESS) {
50!
6068
      modeFunctionCleanup(pInfo);
×
6069
      return code;
×
6070
    }
6071
    pInfo->nullTupleSaved = true;
50✔
6072
  }
6073

6074
  SET_VAL(pResInfo, numOfElems, 1);
2,112,163✔
6075

6076
  return TSDB_CODE_SUCCESS;
2,112,163✔
6077
}
6078

6079
int32_t modeFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
26,006✔
6080
  int32_t              code = TSDB_CODE_SUCCESS;
26,006✔
6081
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
26,006✔
6082
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
26,006✔
6083
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
26,006✔
6084
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
26,006✔
6085
  int32_t              currentRow = pBlock->info.rows;
26,005✔
6086
  if (NULL == pCol) {
26,005!
6087
    modeFunctionCleanup(pInfo);
×
6088
    return TSDB_CODE_OUT_OF_RANGE;
×
6089
  }
6090

6091
  STuplePos resDataPos, resTuplePos;
6092
  int32_t   maxCount = 0;
26,005✔
6093

6094
  void* pIter = taosHashIterate(pInfo->pHash, NULL);
26,005✔
6095
  while (pIter != NULL) {
26,378,521✔
6096
    SModeItem* pItem = (SModeItem*)pIter;
26,352,515✔
6097
    if (pItem->count >= maxCount) {
26,352,515✔
6098
      maxCount = pItem->count;
8,316,504✔
6099
      resDataPos = pItem->dataPos;
8,316,504✔
6100
      resTuplePos = pItem->tuplePos;
8,316,504✔
6101
    }
6102

6103
    pIter = taosHashIterate(pInfo->pHash, pIter);
26,352,515✔
6104
  }
6105

6106
  if (maxCount != 0) {
26,006✔
6107
    char* pData = NULL;
24,083✔
6108
    code = loadTupleData(pCtx, &resDataPos, &pData);
24,083✔
6109
    if (pData == NULL || TSDB_CODE_SUCCESS != code) {
24,083!
6110
      code = terrno = TSDB_CODE_NOT_FOUND;
×
6111
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
×
6112
             resDataPos.streamTupleKey.groupId, resDataPos.streamTupleKey.ts);
6113
      modeFunctionCleanup(pInfo);
×
6114
      return code;
×
6115
    }
6116

6117
    code = colDataSetVal(pCol, currentRow, pData, false);
24,083✔
6118
    if (TSDB_CODE_SUCCESS != code) {
24,083!
6119
      modeFunctionCleanup(pInfo);
×
6120
      return code;
×
6121
    }
6122
    code = setSelectivityValue(pCtx, pBlock, &resTuplePos, currentRow);
24,083✔
6123
  } else {
6124
    colDataSetNULL(pCol, currentRow);
1,923!
6125
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
1,923✔
6126
  }
6127

6128
  modeFunctionCleanup(pInfo);
26,005✔
6129

6130
  return code;
26,005✔
6131
}
6132

6133
bool getTwaFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
79,935✔
6134
  pEnv->calcMemSize = sizeof(STwaInfo);
79,935✔
6135
  return true;
79,935✔
6136
}
6137

6138
int32_t twaFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
11,322,156✔
6139
  if (pResultInfo->initialized) {
11,322,156!
6140
    return TSDB_CODE_SUCCESS;
×
6141
  }
6142
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
11,322,156!
6143
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6144
  }
6145

6146
  STwaInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
11,322,303✔
6147
  pInfo->numOfElems = 0;
11,322,303✔
6148
  pInfo->p.key = INT64_MIN;
11,322,303✔
6149
  pInfo->win = TSWINDOW_INITIALIZER;
11,322,303✔
6150
  return TSDB_CODE_SUCCESS;
11,322,303✔
6151
}
6152

6153
static double twa_get_area(SPoint1 s, SPoint1 e) {
34,578,784✔
6154
  if (e.key == INT64_MAX || s.key == INT64_MIN) {
34,578,784!
6155
    return 0;
×
6156
  }
6157

6158
  if ((s.val >= 0 && e.val >= 0) || (s.val <= 0 && e.val <= 0)) {
34,579,269✔
6159
    return (s.val + e.val) * (e.key - s.key) / 2;
17,779,926✔
6160
  }
6161

6162
  double x = (s.key * e.val - e.key * s.val) / (e.val - s.val);
16,799,343✔
6163
  double val = (s.val * (x - s.key) + e.val * (e.key - x)) / 2;
16,799,343✔
6164
  return val;
16,799,343✔
6165
}
6166

6167
int32_t twaFunction(SqlFunctionCtx* pCtx) {
11,328,642✔
6168
  int32_t               code = TSDB_CODE_SUCCESS;
11,328,642✔
6169
  SInputColumnInfoData* pInput = &pCtx->input;
11,328,642✔
6170
  SColumnInfoData*      pInputCol = pInput->pData[0];
11,328,642✔
6171

6172
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
11,328,642✔
6173
  STwaInfo*            pInfo = GET_ROWCELL_INTERBUF(pResInfo);
11,328,642✔
6174
  SPoint1*             last = &pInfo->p;
11,328,642✔
6175

6176
  if (IS_NULL_TYPE(pInputCol->info.type)) {
11,328,642!
6177
    pInfo->numOfElems = 0;
×
6178
    goto _twa_over;
×
6179
  }
6180

6181
  funcInputUpdate(pCtx);
11,328,642✔
6182
  SFuncInputRow row = {0};
11,328,770✔
6183
  bool          result = false;
11,328,770✔
6184
  if (pCtx->start.key != INT64_MIN && last->key == INT64_MIN) {
11,328,770✔
6185
    while (1) {
6186
      code = funcInputGetNextRow(pCtx, &row, &result);
4,083,495✔
6187
      if (TSDB_CODE_SUCCESS != code) {
4,083,460!
6188
        return code;
×
6189
      }
6190
      if (!result) {
4,083,460✔
6191
        break;
2✔
6192
      }
6193
      if (row.isDataNull) {
4,083,458✔
6194
        continue;
2✔
6195
      }
6196

6197
      last->key = row.ts;
4,083,456✔
6198

6199
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData, typeGetTypeModFromColInfo(&pInputCol->info));
4,083,456!
6200

6201
      pInfo->dOutput += twa_get_area(pCtx->start, *last);
4,083,456✔
6202
      pInfo->win.skey = pCtx->start.key;
4,083,459✔
6203
      pInfo->numOfElems++;
4,083,459✔
6204
      break;
4,083,459✔
6205
    }
6206
  } else if (pInfo->p.key == INT64_MIN) {
7,245,277✔
6207
    while (1) {
6208
      code = funcInputGetNextRow(pCtx, &row, &result);
7,362,490✔
6209
      if (TSDB_CODE_SUCCESS != code) {
7,362,181!
6210
        return code;
×
6211
      }
6212
      if (!result) {
7,362,181✔
6213
        break;
12,699✔
6214
      }
6215
      if (row.isDataNull) {
7,349,482✔
6216
        continue;
122,347✔
6217
      }
6218

6219
      last->key = row.ts;
7,227,135✔
6220

6221
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData, typeGetTypeModFromColInfo(&pInputCol->info));
7,227,135!
6222

6223
      pInfo->win.skey = last->key;
7,227,000✔
6224
      pInfo->numOfElems++;
7,227,000✔
6225
      break;
7,227,000✔
6226
    }
6227
  }
6228

6229
  SPoint1 st = {0};
11,328,294✔
6230

6231
  // calculate the value of
6232
  while (1) {
6233
    code = funcInputGetNextRow(pCtx, &row, &result);
37,656,007✔
6234
    if (TSDB_CODE_SUCCESS != code) {
37,654,463!
6235
      return code;
×
6236
    }
6237
    if (!result) {
37,654,463✔
6238
      break;
11,328,364✔
6239
    }
6240
    if (row.isDataNull) {
26,326,099✔
6241
      continue;
630✔
6242
    }
6243
    pInfo->numOfElems++;
26,325,469✔
6244
    switch (pInputCol->info.type) {
26,325,469!
6245
      case TSDB_DATA_TYPE_TINYINT: {
90,314✔
6246
        INIT_INTP_POINT(st, row.ts, *(int8_t*)row.pData);
90,314✔
6247
        break;
90,314✔
6248
      }
6249
      case TSDB_DATA_TYPE_SMALLINT: {
367,741✔
6250
        INIT_INTP_POINT(st, row.ts, *(int16_t*)row.pData);
367,741✔
6251
        break;
367,741✔
6252
      }
6253
      case TSDB_DATA_TYPE_INT: {
125,304✔
6254
        INIT_INTP_POINT(st, row.ts, *(int32_t*)row.pData);
125,304✔
6255
        break;
125,304✔
6256
      }
6257
      case TSDB_DATA_TYPE_BIGINT: {
22,876,338✔
6258
        INIT_INTP_POINT(st, row.ts, *(int64_t*)row.pData);
22,876,338✔
6259
        break;
22,876,338✔
6260
      }
6261
      case TSDB_DATA_TYPE_FLOAT: {
69,093✔
6262
        INIT_INTP_POINT(st, row.ts, *(float_t*)row.pData);
69,093✔
6263
        break;
69,093✔
6264
      }
6265
      case TSDB_DATA_TYPE_DOUBLE: {
2,534,080✔
6266
        INIT_INTP_POINT(st, row.ts, *(double*)row.pData);
2,534,080✔
6267
        break;
2,534,080✔
6268
      }
6269
      case TSDB_DATA_TYPE_UTINYINT: {
67,720✔
6270
        INIT_INTP_POINT(st, row.ts, *(uint8_t*)row.pData);
67,720✔
6271
        break;
67,720✔
6272
      }
6273
      case TSDB_DATA_TYPE_USMALLINT: {
68,035✔
6274
        INIT_INTP_POINT(st, row.ts, *(uint16_t*)row.pData);
68,035✔
6275
        break;
68,035✔
6276
      }
6277
      case TSDB_DATA_TYPE_UINT: {
70,442✔
6278
        INIT_INTP_POINT(st, row.ts, *(uint32_t*)row.pData);
70,442✔
6279
        break;
70,442✔
6280
      }
6281
      case TSDB_DATA_TYPE_UBIGINT: {
58,867✔
6282
        INIT_INTP_POINT(st, row.ts, *(uint64_t*)row.pData);
58,867✔
6283
        break;
58,867✔
6284
      }
UNCOV
6285
      default: {
×
UNCOV
6286
        return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
6287
      }
6288
    }
6289
    if (pInfo->p.key == st.key) {
26,327,934!
6290
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6291
    }
6292

6293
    pInfo->dOutput += twa_get_area(pInfo->p, st);
26,327,934✔
6294
    pInfo->p = st;
26,327,083✔
6295
  }
6296

6297
  // the last interpolated time window value
6298
  if (pCtx->end.key != INT64_MIN) {
11,328,364✔
6299
    pInfo->dOutput += twa_get_area(pInfo->p, pCtx->end);
4,170,205✔
6300
    pInfo->p = pCtx->end;
4,170,203✔
6301
    pInfo->numOfElems += 1;
4,170,203✔
6302
  }
6303

6304
  pInfo->win.ekey = pInfo->p.key;
11,328,362✔
6305

6306
_twa_over:
11,328,362✔
6307
  SET_VAL(pResInfo, 1, 1);
11,328,362✔
6308
  return TSDB_CODE_SUCCESS;
11,328,362✔
6309
}
6310

6311
/*
6312
 * To copy the input to interResBuf to avoid the input buffer space be over writen
6313
 * by next input data. The TWA function only applies to each table, so no merge procedure
6314
 * is required, we simply copy to the resut ot interResBuffer.
6315
 */
6316
// void twa_function_copy(SQLFunctionCtx *pCtx) {
6317
//   SResultRowEntryInfo *pResInfo = GET_RES_INFO(pCtx);
6318
//
6319
//   memcpy(GET_ROWCELL_INTERBUF(pResInfo), pCtx->pInput, (size_t)pCtx->inputBytes);
6320
//   pResInfo->hasResult = ((STwaInfo *)pCtx->pInput)->hasResult;
6321
// }
6322

6323
int32_t twaFinalize(struct SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
11,309,097✔
6324
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
11,309,097✔
6325

6326
  STwaInfo* pInfo = (STwaInfo*)GET_ROWCELL_INTERBUF(pResInfo);
11,309,097✔
6327
  if (pInfo->numOfElems == 0) {
11,309,097✔
6328
    pResInfo->numOfRes = 0;
12,505✔
6329
  } else {
6330
    if (pInfo->win.ekey == pInfo->win.skey) {
11,296,592✔
6331
      pInfo->dTwaRes = pInfo->p.val;
5,749,559✔
6332
    } else if (pInfo->win.ekey == INT64_MAX || pInfo->win.skey == INT64_MIN) {  // no data in timewindow
5,547,033!
UNCOV
6333
      pInfo->dTwaRes = 0;
×
6334
    } else {
6335
      pInfo->dTwaRes = pInfo->dOutput / (pInfo->win.ekey - pInfo->win.skey);
5,548,584✔
6336
    }
6337

6338
    pResInfo->numOfRes = 1;
11,296,592✔
6339
  }
6340

6341
  return functionFinalize(pCtx, pBlock);
11,309,097✔
6342
}
6343

6344
int32_t blockDistSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
1,635✔
6345
  if (pResultInfo->initialized) {
1,635!
6346
    return TSDB_CODE_SUCCESS;
×
6347
  }
6348
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
1,635!
6349
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6350
  }
6351

6352
  STableBlockDistInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,635✔
6353
  pInfo->minRows = INT32_MAX;
1,635✔
6354
  return TSDB_CODE_SUCCESS;
1,635✔
6355
}
6356

6357
int32_t blockDistFunction(SqlFunctionCtx* pCtx) {
3,264✔
6358
  const int32_t BLOCK_DIST_RESULT_ROWS = 25;
3,264✔
6359

6360
  SInputColumnInfoData* pInput = &pCtx->input;
3,264✔
6361
  SColumnInfoData*      pInputCol = pInput->pData[0];
3,264✔
6362
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
3,264✔
6363
  STableBlockDistInfo*  pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
3,264✔
6364

6365
  STableBlockDistInfo p1 = {0};
3,264✔
6366
  if (tDeserializeBlockDistInfo(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
3,264!
6367
    qError("failed to deserialize block dist info");
×
6368
    return TSDB_CODE_FAILED;
×
6369
  }
6370

6371
  pDistInfo->numOfBlocks += p1.numOfBlocks;
3,264✔
6372
  pDistInfo->numOfTables += p1.numOfTables;
3,264✔
6373
  pDistInfo->numOfInmemRows += p1.numOfInmemRows;
3,264✔
6374
  pDistInfo->numOfSttRows += p1.numOfSttRows;
3,264✔
6375
  pDistInfo->totalSize += p1.totalSize;
3,264✔
6376
  pDistInfo->totalRows += p1.totalRows;
3,264✔
6377
  pDistInfo->numOfFiles += p1.numOfFiles;
3,264✔
6378

6379
  pDistInfo->defMinRows = p1.defMinRows;
3,264✔
6380
  pDistInfo->defMaxRows = p1.defMaxRows;
3,264✔
6381
  pDistInfo->rowSize = p1.rowSize;
3,264✔
6382

6383
  if (pDistInfo->minRows > p1.minRows) {
3,264✔
6384
    pDistInfo->minRows = p1.minRows;
2✔
6385
  }
6386
  if (pDistInfo->maxRows < p1.maxRows) {
3,264✔
6387
    pDistInfo->maxRows = p1.maxRows;
2✔
6388
  }
6389
  pDistInfo->numOfVgroups += (p1.numOfTables != 0 ? 1 : 0);
3,264✔
6390
  for (int32_t i = 0; i < tListLen(pDistInfo->blockRowsHisto); ++i) {
68,544✔
6391
    pDistInfo->blockRowsHisto[i] += p1.blockRowsHisto[i];
65,280✔
6392
  }
6393

6394
  pResInfo->numOfRes = BLOCK_DIST_RESULT_ROWS;  // default output rows
3,264✔
6395
  return TSDB_CODE_SUCCESS;
3,264✔
6396
}
6397

6398
int32_t tSerializeBlockDistInfo(void* buf, int32_t bufLen, const STableBlockDistInfo* pInfo) {
6,508✔
6399
  SEncoder encoder = {0};
6,508✔
6400
  int32_t  code = 0;
6,508✔
6401
  int32_t  lino;
6402
  int32_t  tlen;
6403
  tEncoderInit(&encoder, buf, bufLen);
6,508✔
6404

6405
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
6,515!
6406
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->rowSize));
13,030!
6407

6408
  TAOS_CHECK_EXIT(tEncodeU16(&encoder, pInfo->numOfFiles));
13,030!
6409
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfBlocks));
13,030!
6410
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfTables));
13,030!
6411

6412
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalSize));
13,030!
6413
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalRows));
13,030!
6414
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->maxRows));
13,030!
6415
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->minRows));
13,030!
6416
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMaxRows));
13,030!
6417
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMinRows));
13,030!
6418
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfInmemRows));
13,030!
6419
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfSttRows));
13,030!
6420
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfVgroups));
13,030!
6421

6422
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
136,581✔
6423
    TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->blockRowsHisto[i]));
260,132!
6424
  }
6425

6426
  tEndEncode(&encoder);
6,515✔
6427

6428
_exit:
6,518✔
6429
  if (code) {
6,518!
6430
    tlen = code;
×
6431
  } else {
6432
    tlen = encoder.pos;
6,518✔
6433
  }
6434
  tEncoderClear(&encoder);
6,518✔
6435
  return tlen;
6,513✔
6436
}
6437

6438
int32_t tDeserializeBlockDistInfo(void* buf, int32_t bufLen, STableBlockDistInfo* pInfo) {
3,264✔
6439
  SDecoder decoder = {0};
3,264✔
6440
  int32_t  code = 0;
3,264✔
6441
  int32_t  lino;
6442
  tDecoderInit(&decoder, buf, bufLen);
3,264✔
6443

6444
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
3,264!
6445
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->rowSize));
6,528!
6446

6447
  TAOS_CHECK_EXIT(tDecodeU16(&decoder, &pInfo->numOfFiles));
6,528!
6448
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfBlocks));
6,528!
6449
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfTables));
6,528!
6450

6451
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalSize));
6,528!
6452
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalRows));
6,528!
6453
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->maxRows));
6,528!
6454
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->minRows));
6,528!
6455
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMaxRows));
6,528!
6456
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMinRows));
6,528!
6457
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfInmemRows));
6,528!
6458
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfSttRows));
6,528!
6459
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfVgroups));
6,528!
6460

6461
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
68,544✔
6462
    TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->blockRowsHisto[i]));
130,560!
6463
  }
6464

6465
_exit:
3,264✔
6466
  tDecoderClear(&decoder);
3,264✔
6467
  return code;
3,264✔
6468
}
6469

6470
int32_t blockDistFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,635✔
6471
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,635✔
6472
  STableBlockDistInfo* pData = GET_ROWCELL_INTERBUF(pResInfo);
1,635✔
6473

6474
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
1,635✔
6475
  if (NULL == pColInfo) {
1,635!
6476
    return TSDB_CODE_OUT_OF_RANGE;
×
6477
  }
6478

6479
  if (pData->totalRows == 0) {
1,635✔
6480
    pData->minRows = 0;
1,633✔
6481
  }
6482

6483
  int32_t row = 0;
1,635✔
6484
  char    st[256] = {0};
1,635✔
6485
  double  averageSize = 0;
1,635✔
6486
  if (pData->numOfBlocks != 0) {
1,635✔
6487
    averageSize = ((double)pData->totalSize) / pData->numOfBlocks;
2✔
6488
  }
6489
  uint64_t totalRawSize = pData->totalRows * pData->rowSize;
1,635✔
6490
  double   compRatio = 0;
1,635✔
6491
  if (totalRawSize != 0) {
1,635✔
6492
    compRatio = pData->totalSize * 100 / (double)totalRawSize;
2✔
6493
  }
6494

6495
  int32_t len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
3,270✔
6496
                          "Total_Blocks=[%d] Total_Size=[%.2f KiB] Average_size=[%.2f KiB] Compression_Ratio=[%.2f %c]",
6497
                          pData->numOfBlocks, pData->totalSize / 1024.0, averageSize / 1024.0, compRatio, '%');
1,635✔
6498

6499
  varDataSetLen(st, len);
1,635✔
6500
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
1,635✔
6501
  if (TSDB_CODE_SUCCESS != code) {
1,635!
6502
    return code;
×
6503
  }
6504

6505
  int64_t avgRows = 0;
1,635✔
6506
  if (pData->numOfBlocks > 0) {
1,635✔
6507
    avgRows = pData->totalRows / pData->numOfBlocks;
2✔
6508
  }
6509

6510
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
1,635✔
6511
                  "Block_Rows=[%" PRId64 "] MinRows=[%d] MaxRows=[%d] AvgRows=[%" PRId64 "]", pData->totalRows,
6512
                  pData->minRows, pData->maxRows, avgRows);
6513
  varDataSetLen(st, len);
1,635✔
6514
  code = colDataSetVal(pColInfo, row++, st, false);
1,635✔
6515
  if (TSDB_CODE_SUCCESS != code) {
1,635!
6516
    return code;
×
6517
  }
6518

6519
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Inmem_Rows=[%u] Stt_Rows=[%u] ",
1,635✔
6520
                  pData->numOfInmemRows, pData->numOfSttRows);
6521
  varDataSetLen(st, len);
1,635✔
6522
  code = colDataSetVal(pColInfo, row++, st, false);
1,635✔
6523
  if (TSDB_CODE_SUCCESS != code) {
1,635!
6524
    return code;
×
6525
  }
6526

6527
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
3,270✔
6528
                  "Total_Tables=[%d] Total_Filesets=[%d] Total_Vgroups=[%d]", pData->numOfTables, pData->numOfFiles,
1,635✔
6529
                  pData->numOfVgroups);
6530

6531
  varDataSetLen(st, len);
1,635✔
6532
  code = colDataSetVal(pColInfo, row++, st, false);
1,635✔
6533
  if (TSDB_CODE_SUCCESS != code) {
1,635!
6534
    return code;
×
6535
  }
6536

6537
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
1,635✔
6538
                  "--------------------------------------------------------------------------------");
6539
  varDataSetLen(st, len);
1,635✔
6540
  code = colDataSetVal(pColInfo, row++, st, false);
1,635✔
6541
  if (TSDB_CODE_SUCCESS != code) {
1,635!
6542
    return code;
×
6543
  }
6544

6545
  int32_t maxVal = 0;
1,635✔
6546
  int32_t minVal = INT32_MAX;
1,635✔
6547
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
34,335✔
6548
    if (maxVal < pData->blockRowsHisto[i]) {
32,700✔
6549
      maxVal = pData->blockRowsHisto[i];
3✔
6550
    }
6551

6552
    if (minVal > pData->blockRowsHisto[i]) {
32,700✔
6553
      minVal = pData->blockRowsHisto[i];
1,636✔
6554
    }
6555
  }
6556

6557
  // maximum number of step is 80
6558
  double factor = pData->numOfBlocks / 80.0;
1,635✔
6559

6560
  int32_t numOfBuckets = sizeof(pData->blockRowsHisto) / sizeof(pData->blockRowsHisto[0]);
1,635✔
6561
  int32_t bucketRange = ceil(((double)(pData->defMaxRows - pData->defMinRows)) / numOfBuckets);
1,635✔
6562

6563
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
34,335✔
6564
    len =
32,700✔
6565
        tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "%04d |", pData->defMinRows + bucketRange * (i + 1));
32,700✔
6566

6567
    int32_t num = 0;
32,700✔
6568
    if (pData->blockRowsHisto[i] > 0) {
32,700✔
6569
      num = (pData->blockRowsHisto[i]) / factor;
3✔
6570
    }
6571

6572
    for (int32_t j = 0; j < num; ++j) {
32,859✔
6573
      int32_t x = tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "%c", '|');
159✔
6574
      len += x;
159✔
6575
    }
6576

6577
    if (pData->blockRowsHisto[i] > 0) {
32,700✔
6578
      double v = pData->blockRowsHisto[i] * 100.0 / pData->numOfBlocks;
3✔
6579
      len += tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "  %d (%.2f%c)",
3✔
6580
                       pData->blockRowsHisto[i], v, '%');
6581
    }
6582

6583
    varDataSetLen(st, len);
32,700✔
6584
    code = colDataSetVal(pColInfo, row++, st, false);
32,700✔
6585
    if (TSDB_CODE_SUCCESS != code) {
32,700!
6586
      return code;
×
6587
    }
6588
  }
6589

6590
  return TSDB_CODE_SUCCESS;
1,635✔
6591
}
6592
int32_t blockDBUsageSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
3✔
6593
  if (pResultInfo->initialized) {
3!
6594
    return TSDB_CODE_SUCCESS;
×
6595
  }
6596
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
3!
6597
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6598
  }
6599

6600
  SDBBlockUsageInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
3✔
6601
  return TSDB_CODE_SUCCESS;
3✔
6602
}
6603
int32_t blockDBUsageFunction(SqlFunctionCtx* pCtx) {
6✔
6604
  const int32_t BLOCK_DISK_USAGE_RESULT_ROWS = 2;
6✔
6605

6606
  SInputColumnInfoData* pInput = &pCtx->input;
6✔
6607
  SColumnInfoData*      pInputCol = pInput->pData[0];
6✔
6608
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
6✔
6609
  SDBBlockUsageInfo*    pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
6✔
6610

6611
  SDBBlockUsageInfo p1 = {0};
6✔
6612
  if (tDeserializeBlockDbUsage(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
6!
6613
    qError("failed to deserialize block dist info");
×
6614
    return TSDB_CODE_FAILED;
×
6615
  }
6616

6617
  pDistInfo->dataInDiskSize += p1.dataInDiskSize;
6✔
6618
  pDistInfo->walInDiskSize += p1.walInDiskSize;
6✔
6619
  pDistInfo->rawDataSize += p1.rawDataSize;
6✔
6620
  pResInfo->numOfRes = BLOCK_DISK_USAGE_RESULT_ROWS;  // default output rows
6✔
6621
  return TSDB_CODE_SUCCESS;
6✔
6622
}
6623

6624
int32_t tSerializeBlockDbUsage(void* buf, int32_t bufLen, const SDBBlockUsageInfo* pInfo) {
12✔
6625
  SEncoder encoder = {0};
12✔
6626
  int32_t  code = 0;
12✔
6627
  int32_t  lino;
6628
  int32_t  tlen;
6629
  tEncoderInit(&encoder, buf, bufLen);
12✔
6630

6631
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
12!
6632

6633
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->dataInDiskSize));
24!
6634
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->walInDiskSize));
24!
6635
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->rawDataSize));
24!
6636

6637
  tEndEncode(&encoder);
12✔
6638

6639
_exit:
12✔
6640
  if (code) {
12!
6641
    tlen = code;
×
6642
  } else {
6643
    tlen = encoder.pos;
12✔
6644
  }
6645
  tEncoderClear(&encoder);
12✔
6646
  return tlen;
12✔
6647
}
6648
int32_t tDeserializeBlockDbUsage(void* buf, int32_t bufLen, SDBBlockUsageInfo* pInfo) {
6✔
6649
  SDecoder decoder = {0};
6✔
6650
  int32_t  code = 0;
6✔
6651
  int32_t  lino;
6652
  tDecoderInit(&decoder, buf, bufLen);
6✔
6653

6654
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
6!
6655
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->dataInDiskSize));
12!
6656
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->walInDiskSize));
12!
6657
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->rawDataSize));
12!
6658

6659
_exit:
6✔
6660
  tDecoderClear(&decoder);
6✔
6661
  return code;
6✔
6662
}
6663
int32_t blockDBUsageFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
3✔
6664
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
3✔
6665
  SDBBlockUsageInfo*   pData = GET_ROWCELL_INTERBUF(pResInfo);
3✔
6666

6667
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
3✔
6668
  if (NULL == pColInfo) {
3!
6669
    return TSDB_CODE_OUT_OF_RANGE;
×
6670
  }
6671
  int32_t len = 0;
3✔
6672
  int32_t row = 0;
3✔
6673
  char    st[256] = {0};
3✔
6674

6675
  uint64_t totalDiskSize = pData->dataInDiskSize;
3✔
6676
  uint64_t rawDataSize = pData->rawDataSize;
3✔
6677
  double   compressRatio = 0;
3✔
6678
  if (rawDataSize != 0) {
3✔
6679
    compressRatio = totalDiskSize * 100 / (double)rawDataSize;
2✔
6680
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[%.2f%]", compressRatio);
2✔
6681
  } else {
6682
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[NULL]");
1✔
6683
  }
6684

6685
  varDataSetLen(st, len);
3✔
6686
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
3✔
6687
  if (TSDB_CODE_SUCCESS != code) {
3!
6688
    return code;
×
6689
  }
6690

6691
  len =
3✔
6692
      tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Disk_occupied=[%" PRId64 "k]", pData->dataInDiskSize);
3✔
6693
  varDataSetLen(st, len);
3✔
6694
  code = colDataSetVal(pColInfo, row++, st, false);
3✔
6695
  if (TSDB_CODE_SUCCESS != code) {
3!
6696
    return code;
×
6697
  }
6698
  return code;
3✔
6699
}
6700

6701
bool getDerivativeFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
31,256✔
6702
  pEnv->calcMemSize = sizeof(SDerivInfo);
31,256✔
6703
  return true;
31,256✔
6704
}
6705

6706
int32_t derivativeFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
63,933✔
6707
  if (pResInfo->initialized) {
63,933✔
6708
    return TSDB_CODE_SUCCESS;
32,550✔
6709
  }
6710
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
31,383!
6711
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6712
  }
6713

6714
  SDerivInfo* pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
31,383✔
6715

6716
  pDerivInfo->ignoreNegative = pCtx->param[2].param.i;
31,383✔
6717
  pDerivInfo->prevTs = -1;
31,383✔
6718
  pDerivInfo->tsWindow = pCtx->param[1].param.i;
31,383✔
6719
  pDerivInfo->valueSet = false;
31,383✔
6720
  return TSDB_CODE_SUCCESS;
31,383✔
6721
}
6722

6723
int32_t derivativeFunction(SqlFunctionCtx* pCtx) {
32,677✔
6724
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
32,677✔
6725
  SDerivInfo*          pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
32,677✔
6726

6727
  SInputColumnInfoData* pInput = &pCtx->input;
32,677✔
6728
  SColumnInfoData*      pInputCol = pInput->pData[0];
32,677✔
6729

6730
  int32_t          numOfElems = 0;
32,677✔
6731
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
32,677✔
6732
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
32,677✔
6733
  int32_t          code = TSDB_CODE_SUCCESS;
32,677✔
6734

6735
  funcInputUpdate(pCtx);
32,677✔
6736

6737
  double v = 0;
32,677✔
6738
  if (pCtx->order == TSDB_ORDER_ASC) {
32,677✔
6739
    SFuncInputRow row = {0};
29,320✔
6740
    bool          result = false;
29,320✔
6741
    while (1) {
3,543,586✔
6742
      code = funcInputGetNextRow(pCtx, &row, &result);
3,572,906✔
6743
      if (TSDB_CODE_SUCCESS != code) {
3,572,906!
6744
        return code;
×
6745
      }
6746
      if (!result) {
3,572,906✔
6747
        break;
29,320✔
6748
      }
6749
      if (row.isDataNull) {
3,543,586✔
6750
        continue;
23,790✔
6751
      }
6752

6753
      char* d = row.pData;
3,519,796✔
6754
      GET_TYPED_DATA(v, double, pInputCol->info.type, d, typeGetTypeModFromColInfo(&pInputCol->info));
3,519,796!
6755

6756
      int32_t pos = pCtx->offset + numOfElems;
3,519,796✔
6757
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
3,519,796✔
6758
        pDerivInfo->valueSet = true;
27,767✔
6759
      } else {
6760
        if (row.ts == pDerivInfo->prevTs) {
3,492,029!
6761
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6762
        }
6763
        double r = ((v - pDerivInfo->prevValue) * pDerivInfo->tsWindow) / (row.ts - pDerivInfo->prevTs);
3,492,029✔
6764
        if (pDerivInfo->ignoreNegative && r < 0) {
3,492,029✔
6765
        } else {
6766
          if (isinf(r) || isnan(r)) {
2,104,721!
6767
            colDataSetNULL(pOutput, pos);
×
6768
          } else {
6769
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
2,104,721✔
6770
            if (code != TSDB_CODE_SUCCESS) {
2,104,721!
6771
              return code;
×
6772
            }
6773
          }
6774

6775
          if (pTsOutput != NULL) {
2,104,721!
6776
            colDataSetInt64(pTsOutput, pos, &row.ts);
×
6777
          }
6778

6779
          // handle selectivity
6780
          if (pCtx->subsidiaries.num > 0) {
2,104,721✔
6781
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
1,661,035✔
6782
            if (code != TSDB_CODE_SUCCESS) {
1,661,035!
6783
              return code;
×
6784
            }
6785
          }
6786

6787
          numOfElems++;
2,104,721✔
6788
        }
6789
      }
6790

6791
      pDerivInfo->prevValue = v;
3,519,796✔
6792
      pDerivInfo->prevTs = row.ts;
3,519,796✔
6793
    }
6794
  } else {
6795
    SFuncInputRow row = {0};
3,357✔
6796
    bool          result = false;
3,357✔
6797
    while (1) {
332,016✔
6798
      code = funcInputGetNextRow(pCtx, &row, &result);
335,373✔
6799
      if (TSDB_CODE_SUCCESS != code) {
335,373!
6800
        return code;
×
6801
      }
6802
      if (!result) {
335,373✔
6803
        break;
3,357✔
6804
      }
6805
      if (row.isDataNull) {
332,016✔
6806
        continue;
31✔
6807
      }
6808

6809
      char* d = row.pData;
331,985✔
6810
      GET_TYPED_DATA(v, double, pInputCol->info.type, d, typeGetTypeModFromColInfo(&pInputCol->info));
331,985!
6811

6812
      int32_t pos = pCtx->offset + numOfElems;
331,985✔
6813
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
331,985✔
6814
        pDerivInfo->valueSet = true;
3,340✔
6815
      } else {
6816
        if (row.ts == pDerivInfo->prevTs) {
328,645!
6817
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6818
        }
6819
        double r = ((pDerivInfo->prevValue - v) * pDerivInfo->tsWindow) / (pDerivInfo->prevTs - row.ts);
328,645✔
6820
        if (pDerivInfo->ignoreNegative && r < 0) {
328,645✔
6821
        } else {
6822
          if (isinf(r) || isnan(r)) {
182,618!
6823
            colDataSetNULL(pOutput, pos);
×
6824
          } else {
6825
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
182,618✔
6826
            if (code != TSDB_CODE_SUCCESS) {
182,618!
6827
              return code;
×
6828
            }
6829
          }
6830

6831
          if (pTsOutput != NULL) {
182,618!
6832
            colDataSetInt64(pTsOutput, pos, &pDerivInfo->prevTs);
×
6833
          }
6834

6835
          // handle selectivity
6836
          if (pCtx->subsidiaries.num > 0) {
182,618✔
6837
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
62,590✔
6838
            if (code != TSDB_CODE_SUCCESS) {
62,590!
6839
              return code;
×
6840
            }
6841
          }
6842
          numOfElems++;
182,618✔
6843
        }
6844
      }
6845

6846
      pDerivInfo->prevValue = v;
331,985✔
6847
      pDerivInfo->prevTs = row.ts;
331,985✔
6848
    }
6849
  }
6850

6851
  pResInfo->numOfRes = numOfElems;
32,677✔
6852

6853
  return TSDB_CODE_SUCCESS;
32,677✔
6854
}
6855

6856
int32_t getIrateInfoSize(int32_t pkBytes) { return (int32_t)sizeof(SRateInfo) + 2 * pkBytes; }
1,822,958✔
6857

6858
bool getIrateFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
125,436✔
6859
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
125,436✔
6860
  pEnv->calcMemSize = getIrateInfoSize(pkBytes);
125,436✔
6861
  return true;
125,599✔
6862
}
6863

6864
int32_t irateFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
8,780,578✔
6865
  if (pResInfo->initialized) {
8,780,578!
6866
    return TSDB_CODE_SUCCESS;
×
6867
  }
6868
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
8,780,578!
6869
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6870
  }
6871

6872
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
8,780,711✔
6873

6874
  pInfo->firstKey = INT64_MIN;
8,780,711✔
6875
  pInfo->lastKey = INT64_MIN;
8,780,711✔
6876
  pInfo->firstValue = (double)INT64_MIN;
8,780,711✔
6877
  pInfo->lastValue = (double)INT64_MIN;
8,780,711✔
6878

6879
  pInfo->hasResult = 0;
8,780,711✔
6880
  return TSDB_CODE_SUCCESS;
8,780,711✔
6881
}
6882

6883
static void doSaveRateInfo(SRateInfo* pRateInfo, bool isFirst, int64_t ts, char* pk, double v) {
26,097,091✔
6884
  if (isFirst) {
26,097,091✔
6885
    pRateInfo->firstValue = v;
9,514,288✔
6886
    pRateInfo->firstKey = ts;
9,514,288✔
6887
    if (pRateInfo->firstPk) {
9,514,288✔
6888
      int32_t pkBytes;
6889
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
35!
6890
        if (pRateInfo->pkType == TSDB_DATA_TYPE_JSON) {
8!
6891
          pkBytes = getJsonValueLen(pk);
×
6892
        } else {
6893
          pkBytes = varDataTLen(pk);
8✔
6894
        }
6895
      } else {
6896
        pkBytes = pRateInfo->pkBytes;
27✔
6897
      }
6898
      (void)memcpy(pRateInfo->firstPk, pk, pkBytes);
35✔
6899
    }
6900
  } else {
6901
    pRateInfo->lastValue = v;
16,582,803✔
6902
    pRateInfo->lastKey = ts;
16,582,803✔
6903
    if (pRateInfo->lastPk) {
16,582,803✔
6904
      int32_t pkBytes;
6905
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
52!
6906
        if (pRateInfo->pkType == TSDB_DATA_TYPE_JSON) {
12!
6907
          pkBytes = getJsonValueLen(pk);
×
6908
        } else {
6909
          pkBytes = varDataTLen(pk);
12✔
6910
        }
6911
      } else {
6912
        pkBytes = pRateInfo->pkBytes;
40✔
6913
      }
6914
      (void)memcpy(pRateInfo->lastPk, pk, pkBytes);
52✔
6915
    }
6916
  }
6917
}
26,097,091✔
6918

6919
static void initializeRateInfo(SqlFunctionCtx* pCtx, SRateInfo* pRateInfo, bool isMerge) {
10,495,270✔
6920
  if (pCtx->hasPrimaryKey) {
10,495,270✔
6921
    if (!isMerge) {
19✔
6922
      pRateInfo->pkType = pCtx->input.pPrimaryKey->info.type;
17✔
6923
      pRateInfo->pkBytes = pCtx->input.pPrimaryKey->info.bytes;
17✔
6924
      pRateInfo->firstPk = pRateInfo->pkData;
17✔
6925
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
17✔
6926
    } else {
6927
      pRateInfo->firstPk = pRateInfo->pkData;
2✔
6928
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
2✔
6929
    }
6930
  } else {
6931
    pRateInfo->firstPk = NULL;
10,495,251✔
6932
    pRateInfo->lastPk = NULL;
10,495,251✔
6933
  }
6934
}
10,495,270✔
6935

6936
int32_t irateFunction(SqlFunctionCtx* pCtx) {
7,101,135✔
6937
  int32_t              code = TSDB_CODE_SUCCESS;
7,101,135✔
6938
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,101,135✔
6939
  SRateInfo*           pRateInfo = GET_ROWCELL_INTERBUF(pResInfo);
7,101,135✔
6940

6941
  SInputColumnInfoData* pInput = &pCtx->input;
7,101,135✔
6942
  SColumnInfoData*      pInputCol = pInput->pData[0];
7,101,135✔
6943

6944
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
7,101,135✔
6945

6946
  funcInputUpdate(pCtx);
7,101,135✔
6947

6948
  initializeRateInfo(pCtx, pRateInfo, false);
7,101,187✔
6949

6950
  int32_t       numOfElems = 0;
7,101,152✔
6951
  int32_t       type = pInputCol->info.type;
7,101,152✔
6952
  SFuncInputRow row = {0};
7,101,152✔
6953
  bool          result = false;
7,101,152✔
6954
  while (1) {
15,149,612✔
6955
    code = funcInputGetNextRow(pCtx, &row, &result);
22,250,764✔
6956
    if (TSDB_CODE_SUCCESS != code) {
22,248,924!
6957
      return code;
×
6958
    }
6959
    if (!result) {
22,248,924✔
6960
      break;
7,100,818✔
6961
    }
6962
    if (row.isDataNull) {
15,148,106✔
6963
      continue;
134,625✔
6964
    }
6965

6966
    char*  data = row.pData;
15,013,481✔
6967
    double v = 0;
15,013,481✔
6968
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
15,013,481!
6969

6970
    if (INT64_MIN == pRateInfo->lastKey) {
15,016,020✔
6971
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
7,070,628✔
6972
      pRateInfo->hasResult = 1;
7,070,607✔
6973
      continue;
7,070,607✔
6974
    }
6975

6976
    if (row.ts > pRateInfo->lastKey) {
7,945,392✔
6977
      if ((INT64_MIN == pRateInfo->firstKey) || pRateInfo->lastKey > pRateInfo->firstKey) {
7,816,601!
6978
        doSaveRateInfo(pRateInfo, true, pRateInfo->lastKey, pRateInfo->lastPk, pRateInfo->lastValue);
7,816,601✔
6979
      }
6980
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
7,816,602✔
6981
      continue;
7,816,570✔
6982
    } else if (row.ts == pRateInfo->lastKey) {
128,791!
6983
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6984
    }
6985

6986
    if ((INT64_MIN == pRateInfo->firstKey) || row.ts > pRateInfo->firstKey) {
128,791!
6987
      doSaveRateInfo(pRateInfo, true, row.ts, row.pPk, v);
344✔
6988
    } else if (row.ts == pRateInfo->firstKey) {
128,447!
6989
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6990
    }
6991
  }
6992

6993
  numOfElems++;
7,100,818✔
6994

6995
  SET_VAL(pResInfo, numOfElems, 1);
7,100,818!
6996
  return TSDB_CODE_SUCCESS;
7,100,818✔
6997
}
6998

6999
static double doCalcRate(const SRateInfo* pRateInfo, double tickPerSec) {
7,075,129✔
7000
  if ((INT64_MIN == pRateInfo->lastKey) || (INT64_MIN == pRateInfo->firstKey) ||
7,075,129✔
7001
      (pRateInfo->firstKey >= pRateInfo->lastKey)) {
657,114!
7002
    return 0.0;
6,418,015✔
7003
  }
7004

7005
  double diff = 0;
657,114✔
7006
  // If the previous value of the last is greater than the last value, only keep the last point instead of the delta
7007
  // value between two values.
7008
  diff = pRateInfo->lastValue;
657,114✔
7009
  if (diff >= pRateInfo->firstValue) {
657,114✔
7010
    diff -= pRateInfo->firstValue;
311,080✔
7011
  }
7012

7013
  int64_t duration = pRateInfo->lastKey - pRateInfo->firstKey;
657,114✔
7014
  if (duration == 0) {
657,114!
7015
    return 0;
×
7016
  }
7017

7018
  return (duration > 0) ? ((double)diff) / (duration / tickPerSec) : 0.0;
657,114!
7019
}
7020

7021
static void irateTransferInfoImpl(TSKEY inputKey, SRateInfo* pInput, SRateInfo* pOutput, bool isFirstKey) {
290✔
7022
  if (inputKey > pOutput->lastKey) {
290✔
7023
    doSaveRateInfo(pOutput, true, pOutput->lastKey, pOutput->lastPk, pOutput->lastValue);
190✔
7024
    if (isFirstKey) {
190✔
7025
      doSaveRateInfo(pOutput, false, pInput->firstKey, pInput->firstPk, pInput->firstValue);
87✔
7026
    } else {
7027
      doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
103✔
7028
    }
7029
  } else if ((inputKey < pOutput->lastKey) && (inputKey > pOutput->firstKey)) {
100!
7030
    if (isFirstKey) {
28✔
7031
      doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
14✔
7032
    } else {
7033
      doSaveRateInfo(pOutput, true, pInput->lastKey, pInput->lastPk, pInput->lastValue);
14✔
7034
    }
7035
  } else {
7036
    // inputKey < pOutput->firstKey
7037
  }
7038
}
290✔
7039

7040
static void irateCopyInfo(SRateInfo* pInput, SRateInfo* pOutput) {
1,697,093✔
7041
  doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
1,697,093✔
7042
  doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
1,697,093✔
7043
}
1,697,093✔
7044

7045
static int32_t irateTransferInfo(SRateInfo* pInput, SRateInfo* pOutput) {
1,697,238✔
7046
  if ((pInput->firstKey != INT64_MIN &&
1,697,238✔
7047
       (pInput->firstKey == pOutput->firstKey || pInput->firstKey == pOutput->lastKey)) ||
137,711!
7048
      (pInput->lastKey != INT64_MIN && (pInput->lastKey == pOutput->firstKey || pInput->lastKey == pOutput->lastKey))) {
1,697,238!
7049
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7050
  }
7051

7052
  if (pOutput->hasResult == 0) {
1,697,238✔
7053
    irateCopyInfo(pInput, pOutput);
1,697,093✔
7054
    pOutput->hasResult = pInput->hasResult;
1,697,093✔
7055
    return TSDB_CODE_SUCCESS;
1,697,093✔
7056
  }
7057

7058
  if (pInput->firstKey != INT64_MIN) {
145!
7059
    irateTransferInfoImpl(pInput->firstKey, pInput, pOutput, true);
145✔
7060
  }
7061

7062
  if (pInput->lastKey != INT64_MIN) {
145!
7063
    irateTransferInfoImpl(pInput->lastKey, pInput, pOutput, false);
145✔
7064
  }
7065

7066
  pOutput->hasResult = pInput->hasResult;
145✔
7067
  return TSDB_CODE_SUCCESS;
145✔
7068
}
7069

7070
int32_t irateFunctionMerge(SqlFunctionCtx* pCtx) {
1,697,250✔
7071
  SInputColumnInfoData* pInput = &pCtx->input;
1,697,250✔
7072
  SColumnInfoData*      pCol = pInput->pData[0];
1,697,250✔
7073
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
1,697,250!
7074
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
7075
  }
7076

7077
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,697,250✔
7078
  initializeRateInfo(pCtx, pInfo, true);
1,697,250✔
7079

7080
  int32_t start = pInput->startRowIndex;
1,697,250✔
7081
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
3,394,500✔
7082
    char*      data = colDataGetData(pCol, i);
1,697,250!
7083
    SRateInfo* pInputInfo = (SRateInfo*)varDataVal(data);
1,697,250✔
7084
    initializeRateInfo(pCtx, pInfo, true);
1,697,250✔
7085
    if (pInputInfo->hasResult) {
1,697,250✔
7086
      int32_t code = irateTransferInfo(pInputInfo, pInfo);
1,697,238✔
7087
      if (code != TSDB_CODE_SUCCESS) {
1,697,238!
7088
        return code;
×
7089
      }
7090
    }
7091
  }
7092

7093
  if (pInfo->hasResult) {
1,697,250✔
7094
    GET_RES_INFO(pCtx)->numOfRes = 1;
1,697,238✔
7095
  }
7096

7097
  return TSDB_CODE_SUCCESS;
1,697,250✔
7098
}
7099

7100
int32_t iratePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,697,250✔
7101
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,697,250✔
7102
  SRateInfo*           pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,697,250✔
7103
  int32_t              resultBytes = getIrateInfoSize(pInfo->pkBytes);
1,697,250✔
7104
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
1,697,250!
7105

7106
  if (NULL == res) {
1,697,250!
7107
    return terrno;
×
7108
  }
7109
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
1,697,250✔
7110
  varDataSetLen(res, resultBytes);
1,697,250✔
7111

7112
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,697,250✔
7113
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,697,250✔
7114
  if (NULL == pCol) {
1,697,250!
7115
    taosMemoryFree(res);
×
7116
    return TSDB_CODE_OUT_OF_RANGE;
×
7117
  }
7118

7119
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
1,697,250✔
7120

7121
  taosMemoryFree(res);
1,697,250!
7122
  return code;
1,697,250✔
7123
}
7124

7125
int32_t irateFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
7,080,004✔
7126
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
7,080,004✔
7127
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
7,080,004✔
7128
  if (NULL == pCol) {
7,075,106!
7129
    return TSDB_CODE_OUT_OF_RANGE;
×
7130
  }
7131

7132
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,075,106✔
7133
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
7,075,106✔
7134

7135
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
7,075,106✔
7136
  double     result = doCalcRate(pInfo, (double)TSDB_TICK_PER_SECOND(pCtx->param[1].param.i));
7,075,106!
7137
  int32_t    code = colDataSetVal(pCol, pBlock->info.rows, (const char*)&result, pResInfo->isNullRes);
7,075,105✔
7138

7139
  return code;
7,076,720✔
7140
}
7141

7142
int32_t groupConstValueFunction(SqlFunctionCtx* pCtx) {
108,550,524✔
7143
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
108,550,524✔
7144
  SGroupKeyInfo*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
108,550,524✔
7145

7146
  SInputColumnInfoData* pInput = &pCtx->input;
108,550,524✔
7147
  SColumnInfoData*      pInputCol = pInput->pData[0];
108,550,524✔
7148

7149
  int32_t startIndex = pInput->startRowIndex;
108,550,524✔
7150

7151
  // escape rest of data blocks to avoid first entry to be overwritten.
7152
  if (pInfo->hasResult) {
108,550,524✔
7153
    goto _group_value_over;
12,037,107✔
7154
  }
7155

7156
  if (pInputCol->pData == NULL || colDataIsNull_s(pInputCol, startIndex)) {
192,583,639✔
7157
    pInfo->isNull = true;
2,641,722✔
7158
    pInfo->hasResult = true;
2,641,722✔
7159
    goto _group_value_over;
2,641,722✔
7160
  }
7161

7162
  char* data = colDataGetData(pInputCol, startIndex);
93,871,695!
7163
  if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
93,871,695!
7164
    (void)memcpy(pInfo->data, data,
74,321,777✔
7165
                 (pInputCol->info.type == TSDB_DATA_TYPE_JSON) ? getJsonValueLen(data) : varDataTLen(data));
74,321,777✔
7166
  } else {
7167
    (void)memcpy(pInfo->data, data, pInputCol->info.bytes);
19,549,918✔
7168
  }
7169
  pInfo->hasResult = true;
93,871,695✔
7170

7171
_group_value_over:
108,550,524✔
7172

7173
  SET_VAL(pResInfo, 1, 1);
108,550,524✔
7174
  return TSDB_CODE_SUCCESS;
108,550,524✔
7175
}
7176

7177
int32_t groupKeyFunction(SqlFunctionCtx* pCtx) { return groupConstValueFunction(pCtx); }
107,214,603✔
7178

7179
int32_t groupConstValueFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
94,490,647✔
7180
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
94,490,647✔
7181
  int32_t          code = TSDB_CODE_SUCCESS;
94,490,647✔
7182
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
94,490,647✔
7183
  if (NULL == pCol) {
94,430,438!
7184
    return TSDB_CODE_OUT_OF_RANGE;
×
7185
  }
7186

7187
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
94,430,438✔
7188

7189
  SGroupKeyInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
94,430,438✔
7190

7191
  if (pInfo->hasResult) {
94,430,438!
7192
    int32_t currentRow = pBlock->info.rows;
94,456,898✔
7193
    for (; currentRow < pBlock->info.rows + pResInfo->numOfRes; ++currentRow) {
189,509,819✔
7194
      code = colDataSetVal(pCol, currentRow, pInfo->data, pInfo->isNull ? true : false);
94,481,606✔
7195
      if (TSDB_CODE_SUCCESS != code) {
95,052,921!
7196
        return code;
×
7197
      }
7198
    }
7199
  } else {
7200
    pResInfo->numOfRes = 0;
×
7201
  }
7202

7203
  return code;
95,001,753✔
7204
}
7205

7206
int32_t groupKeyFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) { return groupConstValueFinalize(pCtx, pBlock); }
94,239,216✔
7207

7208
int32_t groupKeyCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
7209
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
7210
  SGroupKeyInfo*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
7211

7212
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
7213
  SGroupKeyInfo*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
7214

7215
  // escape rest of data blocks to avoid first entry to be overwritten.
7216
  if (pDBuf->hasResult) {
×
7217
    goto _group_key_over;
×
7218
  }
7219

7220
  if (pSBuf->isNull) {
×
7221
    pDBuf->isNull = true;
×
7222
    pDBuf->hasResult = true;
×
7223
    goto _group_key_over;
×
7224
  }
7225

7226
  if (IS_VAR_DATA_TYPE(pSourceCtx->resDataInfo.type)) {
×
7227
    (void)memcpy(pDBuf->data, pSBuf->data,
×
7228
                 (pSourceCtx->resDataInfo.type == TSDB_DATA_TYPE_JSON) ? getJsonValueLen(pSBuf->data)
×
7229
                                                                       : varDataTLen(pSBuf->data));
×
7230
  } else {
7231
    (void)memcpy(pDBuf->data, pSBuf->data, pSourceCtx->resDataInfo.bytes);
×
7232
  }
7233

7234
  pDBuf->hasResult = true;
×
7235

7236
_group_key_over:
×
7237

7238
  SET_VAL(pDResInfo, 1, 1);
×
7239
  return TSDB_CODE_SUCCESS;
×
7240
}
7241

7242
int32_t cachedLastRowFunction(SqlFunctionCtx* pCtx) {
8,177✔
7243
  int32_t numOfElems = 0;
8,177✔
7244

7245
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
8,177✔
7246
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
8,177✔
7247

7248
  SInputColumnInfoData* pInput = &pCtx->input;
8,177✔
7249
  SColumnInfoData*      pInputCol = pInput->pData[0];
8,177✔
7250

7251
  int32_t bytes = pInputCol->info.bytes;
8,177✔
7252
  pInfo->bytes = bytes;
8,177✔
7253

7254
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
8,177✔
7255
  pInfo->pkType = -1;
8,177✔
7256
  __compar_fn_t pkCompareFn = NULL;
8,177✔
7257
  if (pCtx->hasPrimaryKey) {
8,177✔
7258
    pInfo->pkType = pkCol->info.type;
2,535✔
7259
    pInfo->pkBytes = pkCol->info.bytes;
2,535✔
7260
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
2,535✔
7261
  }
7262

7263
  // TODO it traverse the different way.
7264
  // last_row function does not ignore the null value
7265
  for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
16,379✔
7266
    numOfElems++;
8,198✔
7267

7268
    bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
8,198✔
7269
    char* data = isNull ? NULL : colDataGetData(pInputCol, i);
8,198!
7270

7271
    TSKEY cts = getRowPTs(pInput->pPTS, i);
8,198!
7272
    if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
8,198✔
7273
      int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
6,338✔
7274
      if (code != TSDB_CODE_SUCCESS) {
6,339!
7275
        return code;
×
7276
      }
7277
      pResInfo->numOfRes = 1;
6,339✔
7278
    }
7279
  }
7280

7281
  SET_VAL(pResInfo, numOfElems, 1);
8,181!
7282
  return TSDB_CODE_SUCCESS;
8,181✔
7283
}
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