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

taosdata / TDengine / #4719

04 Sep 2025 12:33PM UTC coverage: 58.762% (+0.02%) from 58.739%
#4719

push

travis-ci

web-flow
test: update case description (#32878)

134842 of 291691 branches covered (46.23%)

Branch coverage included in aggregate %.

203081 of 283375 relevant lines covered (71.67%)

31931888.35 hits per line

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

68.69
/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; }
2,147,483,647✔
33
bool ignoreNull(int8_t ignoreOption) { return (ignoreOption & 0x2) == 0x2; }
4,138,424✔
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, 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, 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, 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, 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, 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) {
61,179,731✔
210
  SFuncInputRowIter* pIter = &pCtx->rowIter;
61,179,731✔
211

212
  if (!pCtx->bInputFinished) {
61,179,731!
213
    pIter->pInput = &pCtx->input;
61,179,950✔
214
    pIter->tsList = (TSKEY*)pIter->pInput->pPTS->pData;
61,179,950✔
215
    pIter->pDataCol = pIter->pInput->pData[0];
61,179,950✔
216
    pIter->pPkCol = pIter->pInput->pPrimaryKey;
61,179,950✔
217
    pIter->rowIndex = pIter->pInput->startRowIndex;
61,179,950✔
218
    pIter->inputEndIndex = pIter->rowIndex + pIter->pInput->numOfRows - 1;
61,179,950✔
219
    pIter->pSrcBlock = pCtx->pSrcBlock;
61,179,950✔
220
    if (!pIter->hasGroupId || pIter->groupId != pIter->pSrcBlock->info.id.groupId) {
61,179,950✔
221
      pIter->hasGroupId = true;
531,160✔
222
      pIter->groupId = pIter->pSrcBlock->info.id.groupId;
531,160✔
223
      pIter->hasPrev = false;
531,160✔
224
    }
225
  } else {
226
    pIter->finalRow = true;
×
227
  }
228
}
61,179,731✔
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, 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, 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, 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, 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) {
6,760✔
345
  int32_t idx = rowIndex + 1;
6,760✔
346
  while (idx <= pIter->inputEndIndex && pIter->tsList[idx] == pIter->tsList[rowIndex]) {
88,877!
347
    ++idx;
82,117✔
348
  }
349
  pIter->rowIndex = idx;
6,760✔
350
}
6,760✔
351

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

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

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

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

398
bool funcInputGetNextRowNoPk(SFuncInputRowIter* pIter, SFuncInputRow* pRow) {
2,147,483,647✔
399
  if (pIter->rowIndex <= pIter->inputEndIndex) {
2,147,483,647✔
400
    setInputRowInfo(pRow, pIter, pIter->rowIndex, false);
2,147,483,647✔
401
    ++pIter->rowIndex;
2,147,483,647✔
402
    return true;
2,147,483,647✔
403
  } else {
404
    return false;
61,068,949✔
405
  }
406
}
407

408
int32_t funcInputGetNextRow(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, bool* res) {
2,147,483,647✔
409
  SFuncInputRowIter* pIter = &pCtx->rowIter;
2,147,483,647✔
410
  if (pCtx->hasPrimaryKey) {
2,147,483,647✔
411
    if (pCtx->order == TSDB_ORDER_ASC) {
7,944!
412
      *res = funcInputGetNextRowAscPk(pIter, pRow);
7,944✔
413
      return TSDB_CODE_SUCCESS;
7,944✔
414
    } else {
415
      return funcInputGetNextRowDescPk(pIter, pRow, res);
×
416
    }
417
  } else {
418
    *res = funcInputGetNextRowNoPk(pIter, pRow);
2,147,483,647✔
419
    return TSDB_CODE_SUCCESS;
2,147,483,647✔
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) {
54,233,800✔
427
  if (pCtx->subsidiaries.num <= 0) {
54,233,800!
428
    return TSDB_CODE_SUCCESS;
×
429
  }
430

431
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
108,461,291✔
432
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
54,235,584✔
433

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

438
    SColumnInfoData* pSrcCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
54,235,584✔
439
    if (NULL == pSrcCol) {
54,228,121!
440
      return TSDB_CODE_OUT_OF_RANGE;
×
441
    }
442

443
    char* pData = colDataGetData(pSrcCol, rowIndex);
54,228,121!
444

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

448
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
54,228,121✔
449
    if (NULL == pDstCol) {
54,224,837!
450
      return TSDB_CODE_OUT_OF_RANGE;
×
451
    }
452
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
108,449,674✔
453
      colDataSetNULL(pDstCol, pos);
20!
454
    } else {
455
      int32_t code = colDataSetVal(pDstCol, pos, pData, false);
54,224,817✔
456
      if (TSDB_CODE_SUCCESS != code) {
54,227,471!
457
        return code;
×
458
      }
459
    }
460
  }
461
  return TSDB_CODE_SUCCESS;
54,225,707✔
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) {
1,467,130,331✔
470
  if (pResultInfo->initialized) {
1,467,130,331✔
471
    return TSDB_CODE_SUCCESS;  // already initialized
251,203✔
472
  }
473

474
  if (pCtx->pOutput != NULL) {
1,466,879,128!
475
    (void)memset(pCtx->pOutput, 0, (size_t)pCtx->resDataInfo.bytes);
×
476
  }
477

478
  initResultRowEntry(pResultInfo, pCtx->resDataInfo.interBufSize);
1,466,879,128✔
479
  return TSDB_CODE_SUCCESS;
1,466,879,128✔
480
}
481

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

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

495
  return code;
226,456,632✔
496
}
497

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

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

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

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

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

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

525
  return code;
194✔
526
}
527

528
EFuncDataRequired countDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
319,119✔
529
  SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0);
319,119✔
530
  if (QUERY_NODE_COLUMN == nodeType(pParam) && PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pParam)->colId) {
319,235!
531
    return FUNC_DATA_REQUIRED_NOT_LOAD;
319,242✔
532
  }
533
  return FUNC_DATA_REQUIRED_SMA_LOAD;
×
534
}
535

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

541
static int64_t getNumOfElems(SqlFunctionCtx* pCtx) {
82,622,746✔
542
  int64_t numOfElem = 0;
82,622,746✔
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;
82,622,746✔
550
  SColumnInfoData*      pInputCol = pInput->pData[0];
82,622,746✔
551
  if (1 == pInput->numOfRows && pInput->blankFill) {
82,622,746✔
552
    return 0;
567,963✔
553
  }
554
  if (pInput->colDataSMAIsSet && pInput->totalRows == pInput->numOfRows) {
82,054,783!
555
    numOfElem = pInput->numOfRows - pInput->pColumnDataAgg[0]->numOfNull;
4,134✔
556
  } else {
557
    if (pInputCol->hasNull) {
82,050,649✔
558
      for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
584,869,668✔
559
        if (colDataIsNull(pInputCol, pInput->totalRows, i, NULL)) {
1,105,678,450!
560
          continue;
10,019,983✔
561
        }
562
        numOfElem += 1;
542,819,242✔
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;
50,020,206✔
568
    }
569
  }
570
  return numOfElem;
82,054,783✔
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) {
83,178,433✔
578
  int64_t numOfElem = 0;
83,178,433✔
579

580
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
83,178,433✔
581
  SInputColumnInfoData* pInput = &pCtx->input;
83,178,433✔
582

583
  int32_t type = pInput->pData[0]->info.type;
83,178,433✔
584

585
  char*   buf = GET_ROWCELL_INTERBUF(pResInfo);
83,178,433✔
586
  int64_t val = *((int64_t*)buf);
83,178,433✔
587
  if (IS_NULL_TYPE(type)) {
83,178,433✔
588
    // select count(NULL) returns 0
589
    numOfElem = 1;
568,652✔
590
    val += 0;
568,652✔
591
  } else {
592
    numOfElem = getNumOfElems(pCtx);
82,609,781✔
593
    val += numOfElem;
82,580,953✔
594
  }
595
  taosSetInt64Aligned((int64_t*)buf, val);
596

597
  if (tsCountAlwaysReturnValue) {
83,149,605✔
598
    pResInfo->numOfRes = 1;
83,138,124✔
599
  } else {
600
    SET_VAL(pResInfo, val, 1);
11,481✔
601
  }
602

603
  return TSDB_CODE_SUCCESS;
83,149,605✔
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) {
×
620
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
621
  char*                pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
622

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

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

631
int32_t sumFunction(SqlFunctionCtx* pCtx) {
50,266,669✔
632
  int32_t numOfElem = 0;
50,266,669✔
633

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

640
  void* pSumRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
50,266,669✔
641
  SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, type);
50,266,669!
642

643
  if (IS_NULL_TYPE(type)) {
50,266,669✔
644
    numOfElem = 0;
443✔
645
    goto _sum_over;
443✔
646
  }
647

648
  if (pInput->colDataSMAIsSet) {
50,266,226✔
649
    numOfElem = pInput->numOfRows - pAgg->numOfNull;
4,560✔
650

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

669
    int32_t start = pInput->startRowIndex;
50,261,666✔
670
    int32_t numOfRows = pInput->numOfRows;
50,261,666✔
671

672
    if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
50,261,666!
673
      if (type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_BOOL) {
43,717,682!
674
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int8_t, numOfElem);
4,299,437!
675
      } else if (type == TSDB_DATA_TYPE_SMALLINT) {
42,811,925✔
676
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int16_t, numOfElem);
809,053!
677
      } else if (type == TSDB_DATA_TYPE_INT) {
42,765,842✔
678
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int32_t, numOfElem);
309,439,156✔
679
      } else if (type == TSDB_DATA_TYPE_BIGINT) {
14,699,400✔
680
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int64_t, numOfElem);
43,148,694!
681
      }
682
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
6,543,984!
683
      if (type == TSDB_DATA_TYPE_UTINYINT) {
866✔
684
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint8_t, numOfElem);
140,043!
685
      } else if (type == TSDB_DATA_TYPE_USMALLINT) {
823✔
686
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint16_t, numOfElem);
140,051!
687
      } else if (type == TSDB_DATA_TYPE_UINT) {
779✔
688
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint32_t, numOfElem);
142,285!
689
      } else if (type == TSDB_DATA_TYPE_UBIGINT) {
265!
690
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint64_t, numOfElem);
142,148!
691
      }
692
    } else if (type == TSDB_DATA_TYPE_DOUBLE) {
6,543,118✔
693
      LIST_ADD_N(SUM_RES_GET_DSUM(pSumRes), pCol, start, numOfRows, double, numOfElem);
21,681,321!
694
    } else if (type == TSDB_DATA_TYPE_FLOAT) {
572,303!
695
      LIST_ADD_N(SUM_RES_GET_DSUM(pSumRes), pCol, start, numOfRows, float, numOfElem);
2,658,662!
696
    } else if (IS_DECIMAL_TYPE(type)) {
×
697
      SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, TSDB_DATA_TYPE_DECIMAL);
×
698
      int32_t overflow = false;
×
699
      if (TSDB_DATA_TYPE_DECIMAL64 == type) {
×
700
        LIST_ADD_DECIMAL_N(&SUM_RES_GET_DECIMAL_SUM(pSumRes), pCol, start, numOfRows, Decimal64, numOfElem);
×
701
      } else if (TSDB_DATA_TYPE_DECIMAL == type) {
×
702
        LIST_ADD_DECIMAL_N(&SUM_RES_GET_DECIMAL_SUM(pSumRes), pCol, start, numOfRows, Decimal128, numOfElem);
×
703
      }
704
      if (overflow) return TSDB_CODE_DECIMAL_OVERFLOW;
×
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)))) {
50,266,226!
710
    numOfElem = 0;
×
711
  }
712

713
_sum_over:
50,612,843✔
714
  if (numOfElem == 0) {
50,266,669✔
715
    if (tsCountAlwaysReturnValue && pCtx->pExpr->pExpr->_function.pFunctNode->hasOriginalFunc &&
1,810,774!
716
        fmIsCountLikeFunc(pCtx->pExpr->pExpr->_function.pFunctNode->originalFuncId)) {
620,327✔
717
      numOfElem = 1;
×
718
    }
719
  }
720
  // data in the check operation are all null, not output
721
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
50,266,670✔
722
  return TSDB_CODE_SUCCESS;
50,266,670✔
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) {
×
786
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
787
  void*                pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
788
  int16_t              type = SUM_RES_GET_TYPE(pDBuf, pDestCtx->inputType);
×
789

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

794
  if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
×
795
    SUM_RES_INC_ISUM(pDBuf, SUM_RES_GET_ISUM(pSBuf));
×
796
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
797
    SUM_RES_INC_USUM(pDBuf, SUM_RES_GET_USUM(pSBuf));
×
798
  } else if (IS_DECIMAL_TYPE(type)) {
×
799
    bool overflow = false;
×
800
    SUM_RES_INC_DECIMAL_SUM(pDBuf, &SUM_RES_GET_DECIMAL_SUM(pSBuf), type);
×
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);
×
805
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
806
  return TSDB_CODE_SUCCESS;
×
807
}
808

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

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

839
EFuncDataRequired statisDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
341✔
840
  if (funcNotSupportStringSma(pFunc)) {
341✔
841
    return FUNC_DATA_REQUIRED_DATA_LOAD;
40✔
842
  }
843
  return FUNC_DATA_REQUIRED_SMA_LOAD;
301✔
844
}
845

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

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

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

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

870
int32_t minFunction(SqlFunctionCtx* pCtx) {
28,616,259✔
871
  int32_t numOfElems = 0;
28,616,259✔
872
  int32_t code = doMinMaxHelper(pCtx, 1, &numOfElems);
28,616,259✔
873
  if (code != TSDB_CODE_SUCCESS) {
28,656,115!
874
    return code;
×
875
  }
876
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
28,656,115✔
877
  return TSDB_CODE_SUCCESS;
28,656,115✔
878
}
879

880
int32_t maxFunction(SqlFunctionCtx* pCtx) {
46,363,365✔
881
  int32_t numOfElems = 0;
46,363,365✔
882
  int32_t code = doMinMaxHelper(pCtx, 0, &numOfElems);
46,363,365✔
883
  if (code != TSDB_CODE_SUCCESS) {
46,380,049!
884
    return code;
×
885
  }
886
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
46,380,049✔
887
  return TSDB_CODE_SUCCESS;
46,380,049✔
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) {
64,524,286✔
895
  int32_t code = TSDB_CODE_SUCCESS;
64,524,286✔
896

897
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
64,524,286✔
898
  SMinmaxResInfo*      pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
64,524,286✔
899

900
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
64,524,286✔
901
  int32_t currentRow = pBlock->info.rows;
64,524,286✔
902

903
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
64,524,286✔
904
  if (NULL == pCol) {
64,488,885!
905
    return TSDB_CODE_OUT_OF_RANGE;
×
906
  }
907
  pEntryInfo->isNullRes = (pEntryInfo->numOfRes == 0) ? 1 : 0;
64,488,885✔
908

909
  // NOTE: do nothing change it, for performance issue
910
  if (!pEntryInfo->isNullRes) {
64,488,885✔
911
    switch (pCol->info.type) {
63,134,918!
912
      case TSDB_DATA_TYPE_UBIGINT:
504,371✔
913
      case TSDB_DATA_TYPE_BIGINT:
914
        ((int64_t*)pCol->pData)[currentRow] = pRes->v;
504,371✔
915
        break;
504,371✔
916
      case TSDB_DATA_TYPE_UINT:
15,652,039✔
917
      case TSDB_DATA_TYPE_INT:
918
        colDataSetInt32(pCol, currentRow, (int32_t*)&pRes->v);
15,652,039✔
919
        break;
15,652,039✔
920
      case TSDB_DATA_TYPE_USMALLINT:
61,728✔
921
      case TSDB_DATA_TYPE_SMALLINT:
922
        colDataSetInt16(pCol, currentRow, (int16_t*)&pRes->v);
61,728✔
923
        break;
61,728✔
924
      case TSDB_DATA_TYPE_BOOL:
272,662✔
925
      case TSDB_DATA_TYPE_UTINYINT:
926
      case TSDB_DATA_TYPE_TINYINT:
927
        colDataSetInt8(pCol, currentRow, (int8_t*)&pRes->v);
272,662✔
928
        break;
272,662✔
929
      case TSDB_DATA_TYPE_DOUBLE:
6,117,421✔
930
        colDataSetDouble(pCol, currentRow, (double*)&pRes->v);
6,117,421✔
931
        break;
6,117,421✔
932
      case TSDB_DATA_TYPE_FLOAT: {
9,227,184✔
933
        float v = GET_FLOAT_VAL(&pRes->v);
9,227,184✔
934
        colDataSetFloat(pCol, currentRow, &v);
9,227,184✔
935
        break;
9,227,184✔
936
      }
937
      case TSDB_DATA_TYPE_VARBINARY:
31,340,550✔
938
      case TSDB_DATA_TYPE_VARCHAR:
939
      case TSDB_DATA_TYPE_NCHAR: {
940
        code = colDataSetVal(pCol, currentRow, pRes->str, false);
31,340,550✔
941
        if (TSDB_CODE_SUCCESS != code) {
31,318,012!
942
          return code;
×
943
        }
944
        break;
31,318,012✔
945
      }
946
      case TSDB_DATA_TYPE_DECIMAL64:
×
947
        code = colDataSetVal(pCol, currentRow, (const char*)&pRes->v, false);
×
948
        break;
×
949
      case TSDB_DATA_TYPE_DECIMAL:
×
950
        code = colDataSetVal(pCol, currentRow, (void*)pRes->dec, false);
×
951
        break;
×
952
    }
953
  } else {
954
    colDataSetNULL(pCol, currentRow);
1,353,967!
955
  }
956

957
  if (IS_VAR_DATA_TYPE(pCol->info.type)) taosMemoryFreeClear(pRes->str);
64,466,347!
958
  if (pCtx->subsidiaries.num > 0) {
64,516,032✔
959
    if (pEntryInfo->numOfRes > 0) {
45,430,629✔
960
      code = setSelectivityValue(pCtx, pBlock, &pRes->tuplePos, currentRow);
45,428,662✔
961
    } else {
962
      code = setNullSelectivityValue(pCtx, pBlock, currentRow);
1,967✔
963
    }
964
  }
965

966
  return code;
64,504,028✔
967
}
968

969
int32_t setNullSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t rowIndex) {
483,307✔
970
  if (pCtx->subsidiaries.num <= 0) {
483,307✔
971
    return TSDB_CODE_SUCCESS;
480,891✔
972
  }
973

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

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

985
  return TSDB_CODE_SUCCESS;
2,416✔
986
}
987

988
int32_t setSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, const STuplePos* pTuplePos, int32_t rowIndex) {
759,522,741✔
989
  if (pCtx->subsidiaries.num <= 0) {
759,522,741✔
990
    return TSDB_CODE_SUCCESS;
323,060,509✔
991
  }
992

993
  if ((pCtx->saveHandle.pBuf != NULL && pTuplePos->pageId != -1) ||
436,462,232!
994
      (pCtx->saveHandle.pState && pTuplePos->streamTupleKey.ts > 0)) {
×
995
    int32_t numOfCols = pCtx->subsidiaries.num;
436,523,746✔
996
    char*   p = NULL;
436,523,746✔
997
    int32_t code = loadTupleData(pCtx, pTuplePos, &p);
436,523,746✔
998
    if (p == NULL || TSDB_CODE_SUCCESS != code) {
446,204,797!
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;
446,218,499✔
1005
    char* pStart = (char*)(nullList + numOfCols * sizeof(bool));
446,218,499✔
1006

1007
    // todo set the offset value to optimize the performance.
1008
    for (int32_t j = 0; j < numOfCols; ++j) {
889,446,380✔
1009
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
446,250,754✔
1010
      int32_t         dstSlotId = pc->pExpr->base.resSchema.slotId;
446,250,754✔
1011

1012
      SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
446,250,754✔
1013
      if (NULL == pDstCol) {
444,523,639!
1014
        return terrno;
×
1015
      }
1016
      if (nullList[j]) {
444,534,993✔
1017
        colDataSetNULL(pDstCol, rowIndex);
29,870✔
1018
      } else {
1019
        code = colDataSetValOrCover(pDstCol, rowIndex, pStart, false);
444,505,123✔
1020
        if (TSDB_CODE_SUCCESS != code) {
443,198,011!
1021
          return code;
×
1022
        }
1023
      }
1024
      pStart += pDstCol->info.bytes;
443,227,881✔
1025
    }
1026
  }
1027

1028
  return TSDB_CODE_SUCCESS;
443,134,112✔
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) {
165,065,272✔
1034
  if (pCtx->subsidiaries.num <= 0) {
165,065,272!
1035
    return TSDB_CODE_SUCCESS;
×
1036
  }
1037

1038
  int32_t code = TSDB_CODE_SUCCESS;
165,065,272✔
1039
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
330,059,939✔
1040
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
165,067,776✔
1041

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

1046
    SColumnInfoData* pSrcCol = taosArrayGet(pCtx->pSrcBlock->pDataBlock, srcSlotId);
165,067,776✔
1047
    if (NULL == pSrcCol) {
164,965,899!
1048
      return TSDB_CODE_OUT_OF_RANGE;
×
1049
    }
1050

1051
    char* pData = colDataGetData(pSrcCol, rowIndex);
164,965,899!
1052

1053
    // append to dest col
1054
    int32_t dstSlotId = pc->pExpr->base.resSchema.slotId;
164,965,899✔
1055

1056
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
164,965,899✔
1057
    if (NULL == pDstCol) {
164,905,883!
1058
      return TSDB_CODE_OUT_OF_RANGE;
×
1059
    }
1060

1061
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
329,811,766✔
1062
      colDataSetNULL(pDstCol, pos);
480✔
1063
    } else {
1064
      code = colDataSetVal(pDstCol, pos, pData, false);
164,905,403✔
1065
      if (TSDB_CODE_SUCCESS != code) {
164,994,187!
1066
        return code;
×
1067
      }
1068
    }
1069
  }
1070
  return code;
164,992,163✔
1071
}
1072

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

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

1084
  switch (type) {
×
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:
×
1094
    case TSDB_DATA_TYPE_INT:
1095
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int32_t) || !pDBuf->assign)) {
×
1096
        pDBuf->v = pSBuf->v;
×
1097
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1098
        pDBuf->assign = true;
×
1099
      }
1100
      break;
×
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:
×
1119
    case TSDB_DATA_TYPE_FLOAT: {
1120
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(double) || !pDBuf->assign)) {
×
1121
        pDBuf->v = pSBuf->v;
×
1122
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1123
        pDBuf->assign = true;
×
1124
      }
1125
      break;
×
1126
    }
1127
    case TSDB_DATA_TYPE_DECIMAL64: {
×
1128
      const SDecimalOps* pOps = getDecimalOps(type);
×
1129
      if (pSBuf->assign &&
×
1130
          ((pOps->lt(&pDBuf->v, &pSBuf->v, DECIMAL_WORD_NUM(Decimal64)) ^ isMinFunc) || !pDBuf->assign)) {
×
1131
        pDBuf->v = pSBuf->v;
×
1132
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1133
        pDBuf->assign = true;
×
1134
      }
1135
    } break;
×
1136
    case TSDB_DATA_TYPE_DECIMAL: {
×
1137
      const SDecimalOps* pOps = getDecimalOps(type);
×
1138
      if (pSBuf->assign && (pOps->lt(pDBuf->dec, pSBuf->dec, DECIMAL_WORD_NUM(Decimal)) ^ isMinFunc) ||
×
1139
          !pDBuf->assign) {
×
1140
        memcpy(pDBuf->dec, pSBuf->dec, DECIMAL128_BYTES);
×
1141
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1142
        pDBuf->assign = true;
×
1143
      }
1144
    } break;
×
1145
    default:
×
1146
      if (pSBuf->assign && (strcmp(pDBuf->str, pSBuf->str) || !pDBuf->assign)) {
×
1147
        memcpy(pDBuf->str, pSBuf->str, varDataLen(pSBuf->str));
×
1148
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1149
        pDBuf->assign = true;
×
1150
      }
1151
      break;
×
1152
  }
1153
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
1154
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
1155
  return TSDB_CODE_SUCCESS;
×
1156
}
1157

1158
int32_t minCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
1159
  return minMaxCombine(pDestCtx, pSourceCtx, 1);
×
1160
}
1161
int32_t maxCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
1162
  return minMaxCombine(pDestCtx, pSourceCtx, 0);
×
1163
}
1164

1165
int32_t getStdInfoSize() { return (int32_t)sizeof(SStdRes); }
2,750,552✔
1166

1167
bool getStdFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
311,861✔
1168
  pEnv->calcMemSize = sizeof(SStdRes);
311,861✔
1169
  return true;
311,861✔
1170
}
1171

1172
int32_t stdFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
20,452,053✔
1173
  if (pResultInfo->initialized) {
20,452,053!
1174
    return TSDB_CODE_SUCCESS;
×
1175
  }
1176
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
20,452,053!
1177
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1178
  }
1179

1180
  SStdRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
20,452,192✔
1181
  (void)memset(pRes, 0, sizeof(SStdRes));
20,452,192✔
1182
  return TSDB_CODE_SUCCESS;
20,452,192✔
1183
}
1184

1185
int32_t stdFunction(SqlFunctionCtx* pCtx) {
19,413,724✔
1186
  int32_t numOfElem = 0;
19,413,724✔
1187

1188
  // Only the pre-computing information loaded and actual data does not loaded
1189
  SInputColumnInfoData* pInput = &pCtx->input;
19,413,724✔
1190
  int32_t               type = pInput->pData[0]->info.type;
19,413,724✔
1191

1192
  SStdRes* pStdRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
19,413,724✔
1193
  pStdRes->type = type;
19,413,724✔
1194

1195
  // computing based on the true data block
1196
  SColumnInfoData* pCol = pInput->pData[0];
19,413,724✔
1197

1198
  int32_t start = pInput->startRowIndex;
19,413,724✔
1199
  int32_t numOfRows = pInput->numOfRows;
19,413,724✔
1200

1201
  if (IS_NULL_TYPE(type)) {
19,413,724✔
1202
    numOfElem = 0;
207✔
1203
    goto _stddev_over;
207✔
1204
  }
1205

1206
  switch (type) {
19,413,517!
1207
    case TSDB_DATA_TYPE_TINYINT: {
2,355,230✔
1208
      int8_t* plist = (int8_t*)pCol->pData;
2,355,230✔
1209
      for (int32_t i = start; i < numOfRows + start; ++i) {
10,470,176✔
1210
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
8,114,946!
1211
          continue;
14,170✔
1212
        }
1213

1214
        numOfElem += 1;
8,100,776✔
1215
        pStdRes->count += 1;
8,100,776✔
1216
        pStdRes->isum += plist[i];
8,100,776✔
1217
        pStdRes->quadraticISum += plist[i] * plist[i];
8,100,776✔
1218
      }
1219

1220
      break;
2,355,230✔
1221
    }
1222

1223
    case TSDB_DATA_TYPE_SMALLINT: {
9,988,351✔
1224
      int16_t* plist = (int16_t*)pCol->pData;
9,988,351✔
1225
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
42,668,000✔
1226
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
32,679,649✔
1227
          continue;
85,996✔
1228
        }
1229

1230
        numOfElem += 1;
32,593,653✔
1231
        pStdRes->count += 1;
32,593,653✔
1232
        pStdRes->isum += plist[i];
32,593,653✔
1233
        pStdRes->quadraticISum += plist[i] * plist[i];
32,593,653✔
1234
      }
1235
      break;
9,988,351✔
1236
    }
1237

1238
    case TSDB_DATA_TYPE_INT: {
29,410✔
1239
      int32_t* plist = (int32_t*)pCol->pData;
29,410✔
1240
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
4,959,744✔
1241
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
4,930,334✔
1242
          continue;
93,443✔
1243
        }
1244

1245
        numOfElem += 1;
4,836,891✔
1246
        pStdRes->count += 1;
4,836,891✔
1247
        pStdRes->isum += plist[i];
4,836,891✔
1248
        pStdRes->quadraticISum += plist[i] * plist[i];
4,836,891✔
1249
      }
1250

1251
      break;
29,410✔
1252
    }
1253

1254
    case TSDB_DATA_TYPE_BIGINT: {
30,577✔
1255
      int64_t* plist = (int64_t*)pCol->pData;
30,577✔
1256
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
3,029,924✔
1257
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,999,347!
1258
          continue;
91,178✔
1259
        }
1260

1261
        numOfElem += 1;
2,908,169✔
1262
        pStdRes->count += 1;
2,908,169✔
1263
        pStdRes->isum += plist[i];
2,908,169✔
1264
        pStdRes->quadraticISum += plist[i] * plist[i];
2,908,169✔
1265
      }
1266
      break;
30,577✔
1267
    }
1268

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

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

1282
      break;
25✔
1283
    }
1284

1285
    case TSDB_DATA_TYPE_USMALLINT: {
26✔
1286
      uint16_t* plist = (uint16_t*)pCol->pData;
26✔
1287
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
80,278✔
1288
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
80,252!
1289
          continue;
×
1290
        }
1291

1292
        numOfElem += 1;
80,252✔
1293
        pStdRes->count += 1;
80,252✔
1294
        pStdRes->usum += plist[i];
80,252✔
1295
        pStdRes->quadraticUSum += plist[i] * plist[i];
80,252✔
1296
      }
1297
      break;
26✔
1298
    }
1299

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

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

1313
      break;
25✔
1314
    }
1315

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

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

1331
    case TSDB_DATA_TYPE_FLOAT: {
4,472,874✔
1332
      float* plist = (float*)pCol->pData;
4,472,874✔
1333
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
18,743,627✔
1334
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
14,270,753!
1335
          continue;
9,761✔
1336
        }
1337

1338
        numOfElem += 1;
14,260,992✔
1339
        pStdRes->count += 1;
14,260,992✔
1340
        pStdRes->dsum += plist[i];
14,260,992✔
1341
        pStdRes->quadraticDSum += plist[i] * plist[i];
14,260,992✔
1342
      }
1343
      break;
4,472,874✔
1344
    }
1345

1346
    case TSDB_DATA_TYPE_DOUBLE: {
2,539,151✔
1347
      double* plist = (double*)pCol->pData;
2,539,151✔
1348
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
8,814,275✔
1349
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
6,275,124!
1350
          continue;
663,731✔
1351
        }
1352

1353
        numOfElem += 1;
5,611,393✔
1354
        pStdRes->count += 1;
5,611,393✔
1355
        pStdRes->dsum += plist[i];
5,611,393✔
1356
        pStdRes->quadraticDSum += plist[i] * plist[i];
5,611,393✔
1357
      }
1358
      break;
2,539,151✔
1359
    }
1360

1361
    default:
×
1362
      break;
×
1363
  }
1364

1365
_stddev_over:
19,413,724✔
1366
  // data in the check operation are all null, not output
1367
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
19,413,724✔
1368
  return TSDB_CODE_SUCCESS;
19,413,724✔
1369
}
1370

1371
static void stdTransferInfo(SStdRes* pInput, SStdRes* pOutput) {
2,748,930✔
1372
  if (IS_NULL_TYPE(pInput->type)) {
2,748,930✔
1373
    return;
64✔
1374
  }
1375
  pOutput->type = pInput->type;
2,748,866✔
1376
  if (IS_SIGNED_NUMERIC_TYPE(pOutput->type)) {
2,748,866!
1377
    pOutput->quadraticISum += pInput->quadraticISum;
2,732,832✔
1378
    pOutput->isum += pInput->isum;
2,732,832✔
1379
  } else if (IS_UNSIGNED_NUMERIC_TYPE(pOutput->type)) {
16,034!
1380
    pOutput->quadraticUSum += pInput->quadraticUSum;
1✔
1381
    pOutput->usum += pInput->usum;
1✔
1382
  } else {
1383
    pOutput->quadraticDSum += pInput->quadraticDSum;
16,033✔
1384
    pOutput->dsum += pInput->dsum;
16,033✔
1385
  }
1386

1387
  pOutput->count += pInput->count;
2,748,866✔
1388
}
1389

1390
int32_t stdFunctionMerge(SqlFunctionCtx* pCtx) {
2,748,925✔
1391
  SInputColumnInfoData* pInput = &pCtx->input;
2,748,925✔
1392
  SColumnInfoData*      pCol = pInput->pData[0];
2,748,925✔
1393

1394
  if (IS_NULL_TYPE(pCol->info.type)) {
2,748,925!
1395
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
1396
    return TSDB_CODE_SUCCESS;
×
1397
  }
1398

1399
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
2,748,925!
1400
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
1401
  }
1402

1403
  SStdRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,748,925✔
1404

1405
  for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
5,497,855✔
1406
    if (colDataIsNull_s(pCol, i)) continue;
5,497,860!
1407
    char*    data = colDataGetData(pCol, i);
2,748,930!
1408
    SStdRes* pInputInfo = (SStdRes*)varDataVal(data);
2,748,930✔
1409
    stdTransferInfo(pInputInfo, pInfo);
2,748,930✔
1410
  }
1411

1412
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
2,748,925✔
1413
  return TSDB_CODE_SUCCESS;
2,748,925✔
1414
}
1415

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

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

1424
  SStdRes* pStdRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1425

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

1429
  int32_t start = pInput->startRowIndex;
1430
  int32_t numOfRows = pInput->numOfRows;
1431

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

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

1483
int32_t stddevFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
17,644,409✔
1484
  SInputColumnInfoData* pInput = &pCtx->input;
17,644,409✔
1485
  SStdRes*              pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
17,644,409✔
1486
  int32_t               type = pStddevRes->type;
17,644,409✔
1487
  double                avg;
1488

1489
  if (pStddevRes->count == 0) {
17,644,409✔
1490
    GET_RES_INFO(pCtx)->numOfRes = 0;
35,724✔
1491
    return functionFinalize(pCtx, pBlock);
35,724✔
1492
  }
1493

1494
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
17,608,685!
1495
    avg = pStddevRes->isum / ((double)pStddevRes->count);
10,666,907✔
1496
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticISum / ((double)pStddevRes->count) - avg * avg));
10,666,907✔
1497
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
6,941,778!
1498
    avg = pStddevRes->usum / ((double)pStddevRes->count);
10✔
1499
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticUSum / ((double)pStddevRes->count) - avg * avg));
10✔
1500
  } else {
1501
    avg = pStddevRes->dsum / ((double)pStddevRes->count);
6,941,768✔
1502
    pStddevRes->result = sqrt(fabs(pStddevRes->quadraticDSum / ((double)pStddevRes->count) - avg * avg));
6,941,768✔
1503
  }
1504

1505
  // check for overflow
1506
  if (isinf(pStddevRes->result) || isnan(pStddevRes->result)) {
17,608,685!
1507
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1508
  }
1509

1510
  return functionFinalize(pCtx, pBlock);
17,608,685✔
1511
}
1512

1513
int32_t stdvarFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
13,949✔
1514
  SInputColumnInfoData* pInput = &pCtx->input;
13,949✔
1515
  SStdRes*              pStdvarRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
13,949✔
1516
  int32_t               type = pStdvarRes->type;
13,949✔
1517
  double                avg;
1518

1519
  if (pStdvarRes->count == 0) {
13,949✔
1520
    GET_RES_INFO(pCtx)->numOfRes = 0;
2✔
1521
    return functionFinalize(pCtx, pBlock);
2✔
1522
  }
1523

1524
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
13,947!
1525
    avg = pStdvarRes->isum / ((double)pStdvarRes->count);
6,987✔
1526
    pStdvarRes->result = fabs(pStdvarRes->quadraticISum / ((double)pStdvarRes->count) - avg * avg);
6,987✔
1527
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
6,960!
1528
    avg = pStdvarRes->usum / ((double)pStdvarRes->count);
×
1529
    pStdvarRes->result = fabs(pStdvarRes->quadraticUSum / ((double)pStdvarRes->count) - avg * avg);
×
1530
  } else {
1531
    avg = pStdvarRes->dsum / ((double)pStdvarRes->count);
6,960✔
1532
    pStdvarRes->result = fabs(pStdvarRes->quadraticDSum / ((double)pStdvarRes->count) - avg * avg);
6,960✔
1533
  }
1534

1535
  // check for overflow
1536
  if (isinf(pStdvarRes->result) || isnan(pStdvarRes->result)) {
13,947!
1537
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1538
  }
1539

1540
  return functionFinalize(pCtx, pBlock);
13,947✔
1541
}
1542

1543
int32_t stdPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,750,480✔
1544
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,750,480✔
1545
  SStdRes*             pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,750,480✔
1546
  int32_t              resultBytes = getStdInfoSize();
2,750,480✔
1547
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
2,750,480!
1548

1549
  if (NULL == res) {
2,750,480!
1550
    return terrno;
×
1551
  }
1552
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
2,750,480✔
1553
  varDataSetLen(res, resultBytes);
2,750,480✔
1554

1555
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
2,750,480✔
1556
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,750,480✔
1557
  if (NULL == pCol) {
2,750,479!
1558
    taosMemoryFree(res);
×
1559
    return TSDB_CODE_OUT_OF_RANGE;
×
1560
  }
1561

1562
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
2,750,479✔
1563

1564
  taosMemoryFree(res);
2,750,480!
1565
  return code;
2,750,480✔
1566
}
1567

1568
int32_t stdCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
1569
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
1570
  SStdRes*             pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
1571

1572
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
1573
  SStdRes*             pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
1574
  int16_t              type = pDBuf->type == TSDB_DATA_TYPE_NULL ? pSBuf->type : pDBuf->type;
×
1575

1576
  stdTransferInfo(pSBuf, pDBuf);
×
1577

1578
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
1579
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
1580
  return TSDB_CODE_SUCCESS;
×
1581
}
1582

1583
bool getLeastSQRFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
114,652✔
1584
  pEnv->calcMemSize = sizeof(SLeastSQRInfo);
114,652✔
1585
  return true;
114,652✔
1586
}
1587

1588
int32_t leastSQRFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
14,225,294✔
1589
  if (pResultInfo->initialized) {
14,225,294!
1590
    return TSDB_CODE_SUCCESS;
×
1591
  }
1592
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
14,225,294!
1593
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1594
  }
1595

1596
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
14,225,293✔
1597

1598
  GET_TYPED_DATA(pInfo->startVal, double, pCtx->param[1].param.nType, &pCtx->param[1].param.i,
14,225,293!
1599
                 typeGetTypeModFromCol(pCtx->param[1].pCol));
1600
  GET_TYPED_DATA(pInfo->stepVal, double, pCtx->param[2].param.nType, &pCtx->param[2].param.i,
14,225,293!
1601
                 typeGetTypeModFromCol(pCtx->param[2].pCol));
1602
  return TSDB_CODE_SUCCESS;
14,225,293✔
1603
}
1604

1605
int32_t leastSQRFunction(SqlFunctionCtx* pCtx) {
15,355,186✔
1606
  int32_t numOfElem = 0;
15,355,186✔
1607

1608
  SInputColumnInfoData* pInput = &pCtx->input;
15,355,186✔
1609
  int32_t               type = pInput->pData[0]->info.type;
15,355,186✔
1610

1611
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
15,355,186✔
1612

1613
  SColumnInfoData* pCol = pInput->pData[0];
15,355,186✔
1614

1615
  double(*param)[3] = pInfo->matrix;
15,355,186✔
1616
  double x = pInfo->startVal;
15,355,186✔
1617

1618
  int32_t start = pInput->startRowIndex;
15,355,186✔
1619
  int32_t numOfRows = pInput->numOfRows;
15,355,186✔
1620

1621
  switch (type) {
15,355,186!
1622
    case TSDB_DATA_TYPE_TINYINT: {
6,565,960✔
1623
      int8_t* plist = (int8_t*)pCol->pData;
6,565,960✔
1624
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
18,505,591✔
1625
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
11,939,631!
1626
          continue;
848✔
1627
        }
1628
        numOfElem++;
11,938,783✔
1629
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
11,938,783✔
1630
      }
1631
      break;
6,565,960✔
1632
    }
1633
    case TSDB_DATA_TYPE_SMALLINT: {
14,405✔
1634
      int16_t* plist = (int16_t*)pCol->pData;
14,405✔
1635
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
1,199,665✔
1636
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
1,185,260!
1637
          continue;
138,449✔
1638
        }
1639

1640
        numOfElem++;
1,046,811✔
1641
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
1,046,811✔
1642
      }
1643
      break;
14,405✔
1644
    }
1645

1646
    case TSDB_DATA_TYPE_INT: {
11,661✔
1647
      int32_t* plist = (int32_t*)pCol->pData;
11,661✔
1648
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
684,882✔
1649
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
673,221✔
1650
          continue;
148,821✔
1651
        }
1652

1653
        numOfElem++;
524,400✔
1654
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
524,400✔
1655
      }
1656
      break;
11,661✔
1657
    }
1658

1659
    case TSDB_DATA_TYPE_BIGINT: {
10,285✔
1660
      int64_t* plist = (int64_t*)pCol->pData;
10,285✔
1661
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
871,709✔
1662
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
861,424!
1663
          continue;
148,496✔
1664
        }
1665

1666
        numOfElem++;
712,928✔
1667
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
712,928✔
1668
      }
1669
      break;
10,285✔
1670
    }
1671

1672
    case TSDB_DATA_TYPE_UTINYINT: {
128✔
1673
      uint8_t* plist = (uint8_t*)pCol->pData;
128✔
1674
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
80,464✔
1675
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
80,336!
1676
          continue;
88✔
1677
        }
1678
        numOfElem++;
80,248✔
1679
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
80,248✔
1680
      }
1681
      break;
128✔
1682
    }
1683
    case TSDB_DATA_TYPE_USMALLINT: {
128✔
1684
      uint16_t* plist = (uint16_t*)pCol->pData;
128✔
1685
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
80,464✔
1686
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
80,336!
1687
          continue;
80✔
1688
        }
1689

1690
        numOfElem++;
80,256✔
1691
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
80,256✔
1692
      }
1693
      break;
128✔
1694
    }
1695

1696
    case TSDB_DATA_TYPE_UINT: {
128✔
1697
      uint32_t* plist = (uint32_t*)pCol->pData;
128✔
1698
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
80,464✔
1699
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
80,336!
1700
          continue;
80✔
1701
        }
1702

1703
        numOfElem++;
80,256✔
1704
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
80,256✔
1705
      }
1706
      break;
128✔
1707
    }
1708

1709
    case TSDB_DATA_TYPE_UBIGINT: {
128✔
1710
      uint64_t* plist = (uint64_t*)pCol->pData;
128✔
1711
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
80,464✔
1712
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
80,336!
1713
          continue;
80✔
1714
        }
1715

1716
        numOfElem++;
80,256✔
1717
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
80,256✔
1718
      }
1719
      break;
128✔
1720
    }
1721

1722
    case TSDB_DATA_TYPE_FLOAT: {
1,871,795✔
1723
      float* plist = (float*)pCol->pData;
1,871,795✔
1724
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
5,709,076✔
1725
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
3,837,281!
1726
          continue;
1,148✔
1727
        }
1728

1729
        numOfElem++;
3,836,133✔
1730
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
3,836,133✔
1731
      }
1732
      break;
1,871,795✔
1733
    }
1734

1735
    case TSDB_DATA_TYPE_DOUBLE: {
6,880,568✔
1736
      double* plist = (double*)pCol->pData;
6,880,568✔
1737
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
22,540,166✔
1738
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
15,659,598✔
1739
          continue;
148,587✔
1740
        }
1741

1742
        numOfElem++;
15,511,011✔
1743
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
15,511,011✔
1744
      }
1745
      break;
6,880,568✔
1746
    }
1747
    case TSDB_DATA_TYPE_NULL: {
×
1748
      GET_RES_INFO(pCtx)->isNullRes = 1;
×
1749
      numOfElem = 1;
×
1750
      break;
×
1751
    }
1752

1753
    default:
×
1754
      break;
×
1755
  }
1756

1757
  pInfo->startVal = x;
15,355,186✔
1758
  pInfo->num += numOfElem;
15,355,186✔
1759

1760
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
15,355,186✔
1761

1762
  return TSDB_CODE_SUCCESS;
15,355,186✔
1763
}
1764

1765
int32_t leastSQRFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
14,219,083✔
1766
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
14,219,083✔
1767
  SLeastSQRInfo*       pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
14,219,083✔
1768
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
14,219,083✔
1769
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
14,219,083✔
1770

1771
  if (NULL == pCol) {
14,219,082!
1772
    return TSDB_CODE_OUT_OF_RANGE;
×
1773
  }
1774
  int32_t currentRow = pBlock->info.rows;
14,219,082✔
1775

1776
  if (0 == pInfo->num) {
14,219,082✔
1777
    colDataSetNULL(pCol, currentRow);
20,422!
1778
    return TSDB_CODE_SUCCESS;
20,422✔
1779
  }
1780

1781
  double(*param)[3] = pInfo->matrix;
14,198,660✔
1782

1783
  param[1][1] = (double)pInfo->num;
14,198,660✔
1784
  param[1][0] = param[0][1];
14,198,660✔
1785

1786
  double param00 = param[0][0] - param[1][0] * (param[0][1] / param[1][1]);
14,198,660✔
1787
  double param02 = param[0][2] - param[1][2] * (param[0][1] / param[1][1]);
14,198,660✔
1788

1789
  if (0 == param00) {
14,198,660✔
1790
    colDataSetNULL(pCol, currentRow);
11,833,634!
1791
    return TSDB_CODE_SUCCESS;
11,833,634✔
1792
  }
1793

1794
  // param[0][1] = 0;
1795
  double param12 = param[1][2] - param02 * (param[1][0] / param00);
2,365,026✔
1796
  // param[1][0] = 0;
1797
  param02 /= param00;
2,365,026✔
1798

1799
  param12 /= param[1][1];
2,365,026✔
1800

1801
  char buf[LEASTSQUARES_BUFF_LENGTH] = {0};
2,365,026✔
1802
  char slopBuf[64] = {0};
2,365,026✔
1803
  char interceptBuf[64] = {0};
2,365,026✔
1804
  int  n = tsnprintf(slopBuf, 64, "%.6lf", param02);
2,365,026✔
1805
  if (n > LEASTSQUARES_DOUBLE_ITEM_LENGTH) {
2,365,026✔
1806
    (void)snprintf(slopBuf, 64, "%." DOUBLE_PRECISION_DIGITS, param02);
29✔
1807
  }
1808
  n = tsnprintf(interceptBuf, 64, "%.6lf", param12);
2,365,026✔
1809
  if (n > LEASTSQUARES_DOUBLE_ITEM_LENGTH) {
2,365,027✔
1810
    (void)snprintf(interceptBuf, 64, "%." DOUBLE_PRECISION_DIGITS, param12);
874✔
1811
  }
1812
  size_t len =
2,365,027✔
1813
      snprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE, "{slop:%s, intercept:%s}", slopBuf, interceptBuf);
2,365,027✔
1814
  varDataSetLen(buf, len);
2,365,027✔
1815

1816
  int32_t code = colDataSetVal(pCol, currentRow, buf, pResInfo->isNullRes);
2,365,027✔
1817

1818
  return code;
2,365,027✔
1819
}
1820

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

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

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

1848
int32_t percentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
7,933✔
1849
  if (pResultInfo->initialized) {
7,933!
1850
    return TSDB_CODE_SUCCESS;
×
1851
  }
1852
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
7,933!
1853
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1854
  }
1855

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

1862
  return TSDB_CODE_SUCCESS;
7,933✔
1863
}
1864

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

1876
int32_t percentileFunction(SqlFunctionCtx* pCtx) {
7,206,568✔
1877
  int32_t              code = TSDB_CODE_SUCCESS;
7,206,568✔
1878
  int32_t              numOfElems = 0;
7,206,568✔
1879
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,206,568✔
1880

1881
  SInputColumnInfoData* pInput = &pCtx->input;
7,206,568✔
1882
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
7,206,568✔
1883

1884
  SColumnInfoData* pCol = pInput->pData[0];
7,206,568✔
1885
  int32_t          type = pCol->info.type;
7,206,568✔
1886

1887
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
7,206,568✔
1888
  if (pCtx->scanFlag == MAIN_SCAN && pInfo->stage == 0) {
7,206,568✔
1889
    pInfo->stage += 1;
7,933✔
1890

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

1904
  // the first stage, only acquire the min/max value
1905
  if (pInfo->stage == 0) {
7,205,423✔
1906
    if (pCtx->input.colDataSMAIsSet) {
3,603,312✔
1907
      double tmin = 0.0, tmax = 0.0;
3,587,430✔
1908
      if (IS_SIGNED_NUMERIC_TYPE(type)) {
3,587,430!
1909
        tmin = (double)GET_INT64_VAL(&pAgg->min);
×
1910
        tmax = (double)GET_INT64_VAL(&pAgg->max);
×
1911
      } else if (IS_FLOAT_TYPE(type)) {
3,587,430!
1912
        tmin = GET_DOUBLE_VAL(&pAgg->min);
3,587,430✔
1913
        tmax = GET_DOUBLE_VAL(&pAgg->max);
3,587,430✔
1914
      } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
1915
        tmin = (double)GET_UINT64_VAL(&pAgg->min);
×
1916
        tmax = (double)GET_UINT64_VAL(&pAgg->max);
×
1917
      }
1918

1919
      if (GET_DOUBLE_VAL(&pInfo->minval) > tmin) {
3,587,430✔
1920
        SET_DOUBLE_VAL(&pInfo->minval, tmin);
42✔
1921
      }
1922

1923
      if (GET_DOUBLE_VAL(&pInfo->maxval) < tmax) {
3,587,430✔
1924
        SET_DOUBLE_VAL(&pInfo->maxval, tmax);
42✔
1925
      }
1926

1927
      pInfo->numOfElems += (pInput->numOfRows - pAgg->numOfNull);
3,587,430✔
1928
    } else {
1929
      // check the valid data one by one
1930
      int32_t start = pInput->startRowIndex;
15,882✔
1931
      for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
28,395,397✔
1932
        if (colDataIsNull_f(pCol, i)) {
28,379,515!
1933
          continue;
1,432✔
1934
        }
1935

1936
        char* data = colDataGetData(pCol, i);
28,378,083!
1937

1938
        double v = 0;
28,378,083✔
1939
        GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
28,378,083!
1940
        if (v < GET_DOUBLE_VAL(&pInfo->minval)) {
28,378,083✔
1941
          SET_DOUBLE_VAL(&pInfo->minval, v);
7,345✔
1942
        }
1943

1944
        if (v > GET_DOUBLE_VAL(&pInfo->maxval)) {
28,378,083✔
1945
          SET_DOUBLE_VAL(&pInfo->maxval, v);
413,511✔
1946
        }
1947

1948
        pInfo->numOfElems += 1;
28,378,083✔
1949
      }
1950
    }
1951
  } else {
1952
    // the second stage, calculate the true percentile value
1953
    int32_t start = pInput->startRowIndex;
3,602,111✔
1954
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
2,147,483,647✔
1955
      if (colDataIsNull_f(pCol, i)) {
2,147,483,647!
1956
        continue;
×
1957
      }
1958

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

1968
    SET_VAL(pResInfo, numOfElems, 1);
3,602,109!
1969
  }
1970

1971
  pCtx->needCleanup = true;
7,205,421✔
1972
  return TSDB_CODE_SUCCESS;
7,205,421✔
1973
}
1974

1975
int32_t percentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
7,929✔
1976
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
7,929✔
1977
  SPercentileInfo*     ppInfo = (SPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
7,929✔
1978

1979
  int32_t code = 0;
7,929✔
1980
  double  v = 0;
7,929✔
1981

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

1990
      varDataVal(buf)[0] = '[';
36✔
1991
      for (int32_t i = 1; i < pCtx->numOfParams; ++i) {
300✔
1992
        SVariant* pVal = &pCtx->param[i].param;
264✔
1993

1994
        GET_TYPED_DATA(v, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[i].pCol));
264!
1995

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

2001
        if (i == pCtx->numOfParams - 1) {
264✔
2002
          len += tsnprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf]", ppInfo->result);
36✔
2003
        } else {
2004
          len += tsnprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf, ", ppInfo->result);
228✔
2005
        }
2006
      }
2007

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

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

2021
      tMemBucketDestroy(pMemBucket);
36✔
2022
      return TSDB_CODE_SUCCESS;
36✔
2023
    } else {
2024
      SVariant* pVal = &pCtx->param[1].param;
6,748✔
2025

2026
      GET_TYPED_DATA(v, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[1].pCol));
6,748!
2027

2028
      code = getPercentile((*pMemBucket), v, &ppInfo->result);
6,748✔
2029
      if (code != TSDB_CODE_SUCCESS) {
6,748!
2030
        goto _fin_error;
×
2031
      }
2032

2033
      tMemBucketDestroy(pMemBucket);
6,748✔
2034
      return functionFinalize(pCtx, pBlock);
6,748✔
2035
    }
2036
  } else {
2037
    return functionFinalize(pCtx, pBlock);
1,145✔
2038
  }
2039

2040
_fin_error:
×
2041

2042
  tMemBucketDestroy(pMemBucket);
×
2043
  return code;
×
2044
}
2045

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

2054
int32_t getApercentileMaxSize() {
3,207,174✔
2055
  int32_t bytesHist =
3,207,174✔
2056
      (int32_t)(sizeof(SAPercentileInfo) + sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
2057
  int32_t bytesDigest = (int32_t)(sizeof(SAPercentileInfo) + TDIGEST_SIZE(COMPRESSION));
3,207,174✔
2058
  return TMAX(bytesHist, bytesDigest);
3,207,174✔
2059
}
2060

2061
static int8_t getApercentileAlgo(char* algoStr) {
13,928,607✔
2062
  int8_t algoType;
2063
  if (strcasecmp(algoStr, "default") == 0) {
13,928,607✔
2064
    algoType = APERCT_ALGO_DEFAULT;
11,423✔
2065
  } else if (strcasecmp(algoStr, "t-digest") == 0) {
13,917,184✔
2066
    algoType = APERCT_ALGO_TDIGEST;
13,916,881✔
2067
  } else {
2068
    algoType = APERCT_ALGO_UNKNOWN;
303✔
2069
  }
2070

2071
  return algoType;
13,928,607✔
2072
}
2073

2074
static void buildHistogramInfo(SAPercentileInfo* pInfo) {
3,173,128✔
2075
  pInfo->pHisto = (SHistogramInfo*)((char*)pInfo + sizeof(SAPercentileInfo));
3,173,128✔
2076
  pInfo->pHisto->elems = (SHistBin*)((char*)pInfo->pHisto + sizeof(SHistogramInfo));
3,173,128✔
2077
}
3,173,128✔
2078

2079
static void buildTDigestInfo(SAPercentileInfo* pInfo) {
30,230,691✔
2080
  pInfo->pTDigest = (TDigest*)((char*)pInfo + sizeof(SAPercentileInfo));
30,230,691✔
2081
}
30,230,691✔
2082

2083
int32_t apercentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
14,870,046✔
2084
  if (pResultInfo->initialized) {
14,870,046!
2085
    return TSDB_CODE_SUCCESS;
×
2086
  }
2087
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
14,870,046!
2088
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
2089
  }
2090

2091
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
14,874,602✔
2092

2093
  SVariant* pVal = &pCtx->param[1].param;
14,874,602✔
2094
  pInfo->percent = 0;
14,874,602✔
2095
  GET_TYPED_DATA(pInfo->percent, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[1].pCol));
14,874,602!
2096

2097
  if (pCtx->numOfParams == 2) {
14,874,663✔
2098
    pInfo->algo = APERCT_ALGO_DEFAULT;
945,959✔
2099
  } else if (pCtx->numOfParams == 3) {
13,928,704!
2100
    pInfo->algo = getApercentileAlgo(varDataVal(pCtx->param[2].param.pz));
13,928,720✔
2101
    if (pInfo->algo == APERCT_ALGO_UNKNOWN) {
13,927,970!
2102
      return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
2103
    }
2104
  }
2105

2106
  char* tmp = (char*)pInfo + sizeof(SAPercentileInfo);
14,873,913✔
2107
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
14,873,913✔
2108
    pInfo->pTDigest = tdigestNewFrom(tmp, COMPRESSION);
13,916,630✔
2109
  } else {
2110
    buildHistogramInfo(pInfo);
957,283✔
2111
    pInfo->pHisto = tHistogramCreateFrom(tmp, MAX_HISTOGRAM_BIN);
957,376✔
2112
    qDebug("%s set up histogram, numOfElems:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
957,350✔
2113
           pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2114
  }
2115

2116
  return TSDB_CODE_SUCCESS;
14,875,358✔
2117
}
2118

2119
int32_t apercentileFunction(SqlFunctionCtx* pCtx) {
14,263,535✔
2120
  int32_t               numOfElems = 0;
14,263,535✔
2121
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
14,263,535✔
2122
  SInputColumnInfoData* pInput = &pCtx->input;
14,263,535✔
2123

2124
  SColumnInfoData* pCol = pInput->pData[0];
14,263,535✔
2125
  int32_t          type = pCol->info.type;
14,263,535✔
2126

2127
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
14,263,535✔
2128

2129
  int32_t start = pInput->startRowIndex;
14,263,535✔
2130
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
14,263,535✔
2131
    buildTDigestInfo(pInfo);
13,321,681✔
2132
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
13,320,456✔
2133
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
65,471,759✔
2134
      if (colDataIsNull_f(pCol, i)) {
52,150,083✔
2135
        continue;
289,479✔
2136
      }
2137
      numOfElems += 1;
51,860,604✔
2138
      char* data = colDataGetData(pCol, i);
51,860,604!
2139

2140
      double  v = 0;  // value
51,860,604✔
2141
      int64_t w = 1;  // weigth
51,860,604✔
2142
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
51,860,604!
2143
      int32_t code = tdigestAdd(pInfo->pTDigest, v, w);
51,860,604✔
2144
      if (code != TSDB_CODE_SUCCESS) {
51,861,870!
2145
        return code;
×
2146
      }
2147
    }
2148
  } else {
2149
    // might be a race condition here that pHisto can be overwritten or setup function
2150
    // has not been called, need to relink the buffer pHisto points to.
2151
    buildHistogramInfo(pInfo);
941,854✔
2152
    qDebug("%s before add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
942,032✔
2153
           __FUNCTION__, numOfElems, pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto,
2154
           pInfo->pHisto->elems);
2155
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
11,571,560✔
2156
      if (colDataIsNull_f(pCol, i)) {
10,629,221!
2157
        continue;
720,821✔
2158
      }
2159
      numOfElems += 1;
9,908,400✔
2160
      char* data = colDataGetData(pCol, i);
9,908,400!
2161

2162
      double v = 0;
9,908,400✔
2163
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
9,908,400!
2164
      int32_t code = tHistogramAdd(&pInfo->pHisto, v);
9,908,400✔
2165
      if (code != TSDB_CODE_SUCCESS) {
9,908,696!
2166
        return code;
×
2167
      }
2168
    }
2169

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

2175
  SET_VAL(pResInfo, numOfElems, 1);
14,264,609✔
2176
  return TSDB_CODE_SUCCESS;
14,264,609✔
2177
}
2178

2179
static int32_t apercentileTransferInfo(SAPercentileInfo* pInput, SAPercentileInfo* pOutput, bool* hasRes) {
3,214,556✔
2180
  pOutput->percent = pInput->percent;
3,214,556✔
2181
  pOutput->algo = pInput->algo;
3,214,556✔
2182
  if (pOutput->algo == APERCT_ALGO_TDIGEST) {
3,214,556✔
2183
    buildTDigestInfo(pInput);
2,993,246✔
2184
    tdigestAutoFill(pInput->pTDigest, COMPRESSION);
2,993,246✔
2185

2186
    if (pInput->pTDigest->num_centroids == 0 && pInput->pTDigest->num_buffered_pts == 0) {
2,993,246✔
2187
      return TSDB_CODE_SUCCESS;
1✔
2188
    }
2189

2190
    if (hasRes) {
2,993,245!
2191
      *hasRes = true;
2,993,245✔
2192
    }
2193

2194
    buildTDigestInfo(pOutput);
2,993,245✔
2195
    TDigest* pTDigest = pOutput->pTDigest;
2,993,245✔
2196
    tdigestAutoFill(pTDigest, COMPRESSION);
2,993,245✔
2197

2198
    if (pTDigest->num_centroids <= 0 && pTDigest->num_buffered_pts == 0) {
2,993,245✔
2199
      (void)memcpy(pTDigest, pInput->pTDigest, (size_t)TDIGEST_SIZE(COMPRESSION));
1,499,601✔
2200
      tdigestAutoFill(pTDigest, COMPRESSION);
1,499,601✔
2201
    } else {
2202
      int32_t code = tdigestMerge(pTDigest, pInput->pTDigest);
1,493,644✔
2203
      if (TSDB_CODE_SUCCESS != code) {
1,493,644!
2204
        return code;
×
2205
      }
2206
    }
2207
  } else {
2208
    buildHistogramInfo(pInput);
221,310✔
2209
    if (pInput->pHisto->numOfElems <= 0) {
221,310✔
2210
      return TSDB_CODE_SUCCESS;
41✔
2211
    }
2212

2213
    if (hasRes) {
221,269!
2214
      *hasRes = true;
221,269✔
2215
    }
2216

2217
    buildHistogramInfo(pOutput);
221,269✔
2218
    SHistogramInfo* pHisto = pOutput->pHisto;
221,269✔
2219

2220
    if (pHisto->numOfElems <= 0) {
221,269✔
2221
      (void)memcpy(pHisto, pInput->pHisto, sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
111,523✔
2222
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
111,523✔
2223

2224
      qDebug("%s merge histo, total:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems, pHisto->numOfEntries,
111,523✔
2225
             pHisto);
2226
    } else {
2227
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
109,746✔
2228
      qDebug("%s input histogram, elem:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems,
109,746✔
2229
             pHisto->numOfEntries, pInput->pHisto);
2230

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

2240
      qDebug("%s merge histo, total:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems, pHisto->numOfEntries,
109,746✔
2241
             pHisto);
2242
      tHistogramDestroy(&pRes);
109,746✔
2243
    }
2244
  }
2245
  return TSDB_CODE_SUCCESS;
3,214,514✔
2246
}
2247

2248
int32_t apercentileFunctionMerge(SqlFunctionCtx* pCtx) {
1,611,264✔
2249
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,611,264✔
2250

2251
  SInputColumnInfoData* pInput = &pCtx->input;
1,611,264✔
2252

2253
  SColumnInfoData* pCol = pInput->pData[0];
1,611,264✔
2254
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
1,611,264!
2255
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
2256
  }
2257

2258
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,611,264✔
2259

2260
  qDebug("%s total %" PRId64 " rows will merge, %p", __FUNCTION__, pInput->numOfRows, pInfo->pHisto);
1,611,264✔
2261

2262
  bool    hasRes = false;
1,611,264✔
2263
  int32_t start = pInput->startRowIndex;
1,611,264✔
2264
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
4,825,820✔
2265
    char* data = colDataGetData(pCol, i);
3,214,556!
2266

2267
    SAPercentileInfo* pInputInfo = (SAPercentileInfo*)varDataVal(data);
3,214,556✔
2268
    int32_t           code = apercentileTransferInfo(pInputInfo, pInfo, &hasRes);
3,214,556✔
2269
    if (TSDB_CODE_SUCCESS != code) {
3,214,556!
2270
      return code;
×
2271
    }
2272
  }
2273

2274
  if (pInfo->algo != APERCT_ALGO_TDIGEST) {
1,611,264✔
2275
    buildHistogramInfo(pInfo);
111,626✔
2276
    qDebug("%s after merge, total:%" PRId64 ", numOfEntry:%d, %p", __FUNCTION__, pInfo->pHisto->numOfElems,
111,626✔
2277
           pInfo->pHisto->numOfEntries, pInfo->pHisto);
2278
  }
2279

2280
  SET_VAL(pResInfo, hasRes ? 1 : 0, 1);
1,611,264✔
2281
  return TSDB_CODE_SUCCESS;
1,611,264✔
2282
}
2283

2284
int32_t apercentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
11,642,433✔
2285
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
11,642,433✔
2286
  SAPercentileInfo*    pInfo = (SAPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
11,642,433✔
2287

2288
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
11,642,433✔
2289
    buildTDigestInfo(pInfo);
10,922,499✔
2290
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
10,922,499✔
2291
    if (pInfo->pTDigest->size > 0) {
10,922,499!
2292
      pInfo->result = tdigestQuantile(pInfo->pTDigest, pInfo->percent / 100);
10,922,499✔
2293
    } else {  // no need to free
2294
      // setNull(pCtx->pOutput, pCtx->outputType, pCtx->outputBytes);
2295
      return TSDB_CODE_SUCCESS;
×
2296
    }
2297
  } else {
2298
    buildHistogramInfo(pInfo);
719,934✔
2299
    if (pInfo->pHisto->numOfElems > 0) {
719,933✔
2300
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
687,090✔
2301
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2302

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

2321
  return functionFinalize(pCtx, pBlock);
11,642,444✔
2322
}
2323

2324
int32_t apercentilePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
3,206,650✔
2325
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
3,206,650✔
2326
  SAPercentileInfo*    pInfo = (SAPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
3,206,650✔
2327

2328
  int32_t resultBytes = getApercentileMaxSize();
3,206,650✔
2329
  char*   res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
3,207,282!
2330
  if (NULL == res) {
3,212,026!
2331
    return terrno;
×
2332
  }
2333

2334
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
3,212,026✔
2335
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
2,990,484✔
2336
    varDataSetLen(res, resultBytes);
2,990,484✔
2337
  } else {
2338
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
221,542✔
2339
    varDataSetLen(res, resultBytes);
221,542✔
2340
  }
2341

2342
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
3,212,026✔
2343
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
3,212,026✔
2344
  if (NULL == pCol) {
3,198,629!
2345
    taosMemoryFree(res);
×
2346
    return TSDB_CODE_OUT_OF_RANGE;
×
2347
  }
2348

2349
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
3,198,629✔
2350

2351
  taosMemoryFree(res);
3,198,536!
2352
  return code;
3,211,604✔
2353
}
2354

2355
int32_t apercentileCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
2356
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
2357
  SAPercentileInfo*    pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
2358

2359
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
2360
  SAPercentileInfo*    pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
2361

2362
  qDebug("%s start to combine apercentile, %p", __FUNCTION__, pDBuf->pHisto);
×
2363

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

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

2397
EFuncDataRequired firstDynDataReq(void* pRes, SDataBlockInfo* pBlockInfo) {
13,315✔
2398
  SResultRowEntryInfo* pEntry = (SResultRowEntryInfo*)pRes;
13,315✔
2399

2400
  // not initialized yet, data is required
2401
  if (pEntry == NULL) {
13,315!
2402
    return FUNC_DATA_REQUIRED_DATA_LOAD;
×
2403
  }
2404

2405
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
13,315✔
2406
  if (pResult->hasResult) {
13,315✔
2407
    if (pResult->pkBytes > 0) {
13,282✔
2408
      pResult->pkData = pResult->buf + pResult->bytes;
2,596✔
2409
    } else {
2410
      pResult->pkData = NULL;
10,686✔
2411
    }
2412
    if (pResult->ts < pBlockInfo->window.skey) {
13,282✔
2413
      return FUNC_DATA_REQUIRED_NOT_LOAD;
9,009✔
2414
    } else if (pResult->ts == pBlockInfo->window.skey) {
4,273✔
2415
      if (NULL == pResult->pkData) {
1,367✔
2416
        return FUNC_DATA_REQUIRED_NOT_LOAD;
461✔
2417
      }
2418
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 0, TSDB_ORDER_ASC) < 0) {
906✔
2419
        return FUNC_DATA_REQUIRED_NOT_LOAD;
176✔
2420
      }
2421
    }
2422
    return FUNC_DATA_REQUIRED_DATA_LOAD;
3,636✔
2423
  } else {
2424
    return FUNC_DATA_REQUIRED_DATA_LOAD;
33✔
2425
  }
2426
}
2427

2428
EFuncDataRequired lastDynDataReq(void* pRes, SDataBlockInfo* pBlockInfo) {
44,029✔
2429
  SResultRowEntryInfo* pEntry = (SResultRowEntryInfo*)pRes;
44,029✔
2430

2431
  // not initialized yet, data is required
2432
  if (pEntry == NULL) {
44,029!
2433
    return FUNC_DATA_REQUIRED_DATA_LOAD;
×
2434
  }
2435

2436
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
44,029✔
2437
  if (pResult->hasResult) {
44,029✔
2438
    if (pResult->pkBytes > 0) {
43,979✔
2439
      pResult->pkData = pResult->buf + pResult->bytes;
3,415✔
2440
    } else {
2441
      pResult->pkData = NULL;
40,564✔
2442
    }
2443
    if (pResult->ts > pBlockInfo->window.ekey) {
43,979✔
2444
      return FUNC_DATA_REQUIRED_NOT_LOAD;
33,094✔
2445
    } else if (pResult->ts == pBlockInfo->window.ekey && pResult->pkData) {
10,885✔
2446
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 1, TSDB_ORDER_DESC) < 0) {
1,132✔
2447
        return FUNC_DATA_REQUIRED_NOT_LOAD;
329✔
2448
      }
2449
    }
2450
    return FUNC_DATA_REQUIRED_DATA_LOAD;
10,556✔
2451
  } else {
2452
    return FUNC_DATA_REQUIRED_DATA_LOAD;
50✔
2453
  }
2454
}
2455

2456
// TODO modify it to include primary key bytes
2457
int32_t getFirstLastInfoSize(int32_t resBytes, int32_t pkBytes) { return sizeof(SFirstLastRes) + resBytes + pkBytes; }
171,965,659✔
2458

2459
bool getFirstLastFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
5,107,878✔
2460
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
5,107,878✔
2461
  // TODO: change SFunctionNode to add pk info
2462
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
5,112,443✔
2463
  pEnv->calcMemSize = getFirstLastInfoSize(pNode->node.resType.bytes, pkBytes);
5,112,443✔
2464
  return true;
5,114,968✔
2465
}
2466

2467
bool getSelectivityFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
3,543,273✔
2468
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
3,543,273✔
2469
  pEnv->calcMemSize = pNode->node.resType.bytes;
3,545,432✔
2470
  return true;
3,545,432✔
2471
}
2472

2473
bool getGroupKeyFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
277,597✔
2474
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
277,597✔
2475
  pEnv->calcMemSize = sizeof(SGroupKeyInfo) + pNode->node.resType.bytes;
277,876✔
2476
  return true;
277,876✔
2477
}
2478

2479
static FORCE_INLINE TSKEY getRowPTs(SColumnInfoData* pTsColInfo, int32_t rowIndex) {
2480
  if (pTsColInfo == NULL || pTsColInfo->pData == NULL) {
969,462,337!
2481
    return 0;
×
2482
  }
2483

2484
  return *(TSKEY*)colDataGetData(pTsColInfo, rowIndex);
969,492,610!
2485
}
2486

2487
int32_t firstLastFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
69,857,822✔
2488
  if (pResInfo->initialized) {
69,857,822!
2489
    return TSDB_CODE_SUCCESS;
×
2490
  }
2491
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
69,857,822!
2492
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
2493
  }
2494

2495
  SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pResInfo);
69,860,440✔
2496
  pRes->nullTupleSaved = false;
69,860,440✔
2497
  pRes->nullTuplePos.pageId = -1;
69,860,440✔
2498
  return TSDB_CODE_SUCCESS;
69,860,440✔
2499
}
2500

2501
static int32_t prepareBuf(SqlFunctionCtx* pCtx) {
721,273,363✔
2502
  if (pCtx->subsidiaries.rowLen == 0) {
721,273,363✔
2503
    int32_t rowLen = 0;
1,896,849✔
2504
    for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
3,802,784✔
2505
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
1,905,935✔
2506
      rowLen += pc->pExpr->base.resSchema.bytes;
1,905,935✔
2507
    }
2508

2509
    pCtx->subsidiaries.rowLen = rowLen + pCtx->subsidiaries.num * sizeof(bool);
1,896,849✔
2510
    pCtx->subsidiaries.buf = taosMemoryMalloc(pCtx->subsidiaries.rowLen);
1,896,849!
2511
    if (NULL == pCtx->subsidiaries.buf) {
1,885,693!
2512
      return terrno;
×
2513
    }
2514
  }
2515
  return TSDB_CODE_SUCCESS;
721,262,207✔
2516
}
2517

2518
static int32_t firstlastSaveTupleData(const SSDataBlock* pSrcBlock, int32_t rowIndex, SqlFunctionCtx* pCtx,
580,837,045✔
2519
                                      SFirstLastRes* pInfo, bool noElements) {
2520
  int32_t code = TSDB_CODE_SUCCESS;
580,837,045✔
2521

2522
  if (pCtx->subsidiaries.num <= 0) {
580,837,045✔
2523
    return TSDB_CODE_SUCCESS;
226,078,100✔
2524
  }
2525

2526
  if (!pInfo->hasResult) {
354,758,945✔
2527
    code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
284,707,064✔
2528
  } else if (!noElements) {
70,051,881!
2529
    code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
70,246,077✔
2530
  } else {
2531
  }  // dothing
2532

2533
  return code;
354,201,129✔
2534
}
2535

2536
static int32_t doSaveCurrentVal(SqlFunctionCtx* pCtx, int32_t rowIndex, int64_t currentTs, char* pkData, int32_t type,
230,623,480✔
2537
                                char* pData) {
2538
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
230,623,480✔
2539
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
230,623,480✔
2540

2541
  if (IS_VAR_DATA_TYPE(type)) {
230,623,480!
2542
    pInfo->bytes = calcStrBytesByType(type, pData);
17,468,023✔
2543
    // if (type == TSDB_DATA_TYPE_JSON) {
2544
    //   pInfo->bytes = getJsonValueLen(pData);
2545
    // } else {
2546
    //   pInfo->bytes = varDataTLen(pData);
2547
    // }
2548
  }
2549

2550
  (void)memcpy(pInfo->buf, pData, pInfo->bytes);
230,662,186✔
2551
  if (pkData != NULL) {
230,662,186✔
2552
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
285,566!
2553
      pInfo->pkBytes = calcStrBytesByType(pInfo->pkType, pkData);
94,924✔
2554
      // if (pInfo->pkType == TSDB_DATA_TYPE_JSON) {
2555
      //   pInfo->pkBytes = getJsonValueLen(pkData);
2556
      // } else {
2557
      //   pInfo->pkBytes = varDataTLen(pkData);
2558
      // }
2559
    }
2560
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
285,566✔
2561
    pInfo->pkData = pInfo->buf + pInfo->bytes;
285,566✔
2562
  }
2563

2564
  pInfo->ts = currentTs;
230,662,186✔
2565
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
230,662,186✔
2566
  if (code != TSDB_CODE_SUCCESS) {
230,413,768!
2567
    return code;
×
2568
  }
2569

2570
  pInfo->hasResult = true;
230,413,768✔
2571
  return TSDB_CODE_SUCCESS;
230,413,768✔
2572
}
2573

2574
// This ordinary first function does not care if current scan is ascending order or descending order scan
2575
// the OPTIMIZED version of first function will only handle the ascending order scan
2576
int32_t firstFunction(SqlFunctionCtx* pCtx) {
82,305,775✔
2577
  int32_t numOfElems = 0;
82,305,775✔
2578

2579
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
82,305,775✔
2580
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
82,305,775✔
2581

2582
  SInputColumnInfoData* pInput = &pCtx->input;
82,305,775✔
2583
  SColumnInfoData*      pInputCol = pInput->pData[0];
82,305,775✔
2584

2585
  pInfo->bytes = pInputCol->info.bytes;
82,305,775✔
2586

2587
  if (IS_NULL_TYPE(pInputCol->info.type)) {
82,305,775✔
2588
    return TSDB_CODE_SUCCESS;
8,981✔
2589
  }
2590

2591
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
82,296,794✔
2592
  pInfo->pkType = -1;
82,296,794✔
2593
  __compar_fn_t pkCompareFn = NULL;
82,296,794✔
2594
  if (pCtx->hasPrimaryKey) {
82,296,794✔
2595
    pInfo->pkType = pkCol->info.type;
19,146✔
2596
    pInfo->pkBytes = pkCol->info.bytes;
19,146✔
2597
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_ASC);
19,146✔
2598
  }
2599

2600
  // All null data column, return directly.
2601
  if (pInput->colDataSMAIsSet && (pInput->pColumnDataAgg[0]->numOfNull == pInput->totalRows) &&
82,297,287!
2602
      pInputCol->hasNull == true) {
×
2603
    // save selectivity value for column consisted of all null values
2604
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
×
2605
    if (code != TSDB_CODE_SUCCESS) {
×
2606
      return code;
×
2607
    }
2608
    pInfo->nullTupleSaved = true;
×
2609
    return TSDB_CODE_SUCCESS;
×
2610
  }
2611

2612
  SColumnDataAgg* pColAgg = (pInput->colDataSMAIsSet) ? pInput->pColumnDataAgg[0] : NULL;
82,297,287!
2613

2614
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
82,297,287!
2615
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
82,297,287!
2616

2617
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
82,297,287✔
2618

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

2630
    for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
2631
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2632
        continue;
2633
      }
2634

2635
      numOfElems++;
2636

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

2653
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
2654
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2655
        continue;
2656
      }
2657

2658
      numOfElems++;
2659

2660
      char* data = colDataGetData(pInputCol, i);
2661
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2662

2663
      if (pResInfo->numOfRes == 0 || pInfo->ts > cts) {
2664
        doSaveCurrentVal(pCtx, i, cts, pInputCol->info.type, data);
2665
        break;
2666
      }
2667
    }
2668
  }
2669
#else
2670
  int64_t* pts = (int64_t*)pInput->pPTS->pData;
82,297,287✔
2671

2672
  int     from = -1;
82,297,287✔
2673
  int32_t i = -1;
82,297,287✔
2674
  while (funcInputGetNextRowIndex(pInput, from, true, &i, &from)) {
335,568,687✔
2675
    if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
336,687,326!
2676
      continue;
4,857,334✔
2677
    }
2678

2679
    numOfElems++;
248,412,235✔
2680
    char* data = colDataGetData(pInputCol, i);
248,412,235!
2681
    char* pkData = NULL;
248,412,235✔
2682
    if (pCtx->hasPrimaryKey) {
248,412,235✔
2683
      pkData = colDataGetData(pkCol, i);
277,631!
2684
    }
2685
    TSKEY cts = pts[i];
248,412,235✔
2686
    if (pResInfo->numOfRes == 0 || pInfo->ts > cts ||
248,412,235✔
2687
        (pInfo->ts == cts && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
158,849,796!
2688
      int32_t code = doSaveCurrentVal(pCtx, i, cts, pkData, pInputCol->info.type, data);
89,562,439✔
2689
      if (code != TSDB_CODE_SUCCESS) {
89,564,271!
2690
        return code;
×
2691
      }
2692
      pResInfo->numOfRes = 1;
89,564,271✔
2693
    }
2694
  }
2695
#endif
2696

2697
  if (numOfElems == 0) {
82,270,455✔
2698
    // save selectivity value for column consisted of all null values
2699
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
543,756✔
2700
    if (code != TSDB_CODE_SUCCESS) {
543,756!
2701
      return code;
×
2702
    }
2703
    pInfo->nullTupleSaved = true;
543,756✔
2704
  }
2705
  SET_VAL(pResInfo, numOfElems, 1);
82,270,455✔
2706
  return TSDB_CODE_SUCCESS;
82,270,455✔
2707
}
2708

2709
int32_t lastFunction(SqlFunctionCtx* pCtx) {
94,271,662✔
2710
  int32_t numOfElems = 0;
94,271,662✔
2711

2712
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
94,271,662✔
2713
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
94,271,662✔
2714

2715
  SInputColumnInfoData* pInput = &pCtx->input;
94,271,662✔
2716
  SColumnInfoData*      pInputCol = pInput->pData[0];
94,271,662✔
2717

2718
  int32_t type = pInputCol->info.type;
94,271,662✔
2719
  int32_t bytes = pInputCol->info.bytes;
94,271,662✔
2720

2721
  if (IS_NULL_TYPE(type)) {
94,271,662✔
2722
    return TSDB_CODE_SUCCESS;
8,973✔
2723
  }
2724
  pInfo->bytes = bytes;
94,262,689✔
2725

2726
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
94,262,689✔
2727
  pInfo->pkType = -1;
94,262,689✔
2728
  __compar_fn_t pkCompareFn = NULL;
94,262,689✔
2729
  if (pCtx->hasPrimaryKey) {
94,262,689✔
2730
    pInfo->pkType = pkCol->info.type;
24,507✔
2731
    pInfo->pkBytes = pkCol->info.bytes;
24,507✔
2732
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
24,507✔
2733
  }
2734

2735
  // All null data column, return directly.
2736
  if (pInput->colDataSMAIsSet && (pInput->pColumnDataAgg[0]->numOfNull == pInput->totalRows) &&
94,272,682!
2737
      pInputCol->hasNull == true) {
×
2738
    // save selectivity value for column consisted of all null values
2739
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
×
2740
    if (code != TSDB_CODE_SUCCESS) {
×
2741
      return code;
×
2742
    }
2743
    pInfo->nullTupleSaved = true;
×
2744
    return TSDB_CODE_SUCCESS;
×
2745
  }
2746

2747
  SColumnDataAgg* pColAgg = (pInput->colDataSMAIsSet) ? pInput->pColumnDataAgg[0] : NULL;
94,272,682!
2748

2749
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
94,272,682✔
2750
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
94,272,682!
2751

2752
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
94,272,682✔
2753

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

2762
      numOfElems++;
2763

2764
      char* data = colDataGetData(pInputCol, i);
2765
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2766
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2767
        doSaveCurrentVal(pCtx, i, cts, type, data);
2768
      }
2769

2770
      break;
2771
    }
2772
  } else {  // descending order
2773
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
2774
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2775
        continue;
2776
      }
2777

2778
      numOfElems++;
2779

2780
      char* data = colDataGetData(pInputCol, i);
2781
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2782
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2783
        doSaveCurrentVal(pCtx, i, cts, type, data);
2784
      }
2785
      break;
2786
    }
2787
  }
2788
#else
2789
  int64_t* pts = (int64_t*)pInput->pPTS->pData;
94,272,682✔
2790

2791
#if 0
2792
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
2793
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2794
        continue;
2795
      }
2796

2797
      numOfElems++;
2798
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i]) {
2799
        char* data = colDataGetData(pInputCol, i);
2800
        doSaveCurrentVal(pCtx, i, pts[i], type, data);
2801
        pResInfo->numOfRes = 1;
2802
      }
2803
    }
2804
#else
2805

2806
  // todo refactor
2807
  if (!pInputCol->hasNull && !pCtx->hasPrimaryKey) {
150,714,435✔
2808
    numOfElems = 1;
56,580,496✔
2809

2810
    int32_t round = pInput->numOfRows >> 2;
56,580,496✔
2811
    int32_t reminder = pInput->numOfRows & 0x03;
56,580,496✔
2812

2813
    for (int32_t i = pInput->startRowIndex, tick = 0; tick < round; i += 4, tick += 1) {
96,815,041✔
2814
      int64_t cts = pts[i];
40,253,743✔
2815
      int32_t chosen = i;
40,253,743✔
2816

2817
      if (cts < pts[i + 1]) {
40,253,743✔
2818
        cts = pts[i + 1];
174,839✔
2819
        chosen = i + 1;
174,839✔
2820
      }
2821

2822
      if (cts < pts[i + 2]) {
40,253,743✔
2823
        cts = pts[i + 2];
174,840✔
2824
        chosen = i + 2;
174,840✔
2825
      }
2826

2827
      if (cts < pts[i + 3]) {
40,253,743✔
2828
        cts = pts[i + 3];
174,836✔
2829
        chosen = i + 3;
174,836✔
2830
      }
2831

2832
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
40,253,743✔
2833
        char*   data = colDataGetData(pInputCol, chosen);
4,447,585!
2834
        int32_t code = doSaveCurrentVal(pCtx, chosen, cts, NULL, type, data);
4,447,585✔
2835
        if (code != TSDB_CODE_SUCCESS) {
4,428,387!
2836
          return code;
×
2837
        }
2838
        pResInfo->numOfRes = 1;
4,428,387✔
2839
      }
2840
    }
2841

2842
    for (int32_t i = pInput->startRowIndex + round * 4; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
130,716,482✔
2843
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i]) {
74,274,729✔
2844
        char*   data = colDataGetData(pInputCol, i);
51,020,777!
2845
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], NULL, type, data);
51,020,777✔
2846
        if (code != TSDB_CODE_SUCCESS) {
50,901,232!
2847
          return code;
×
2848
        }
2849
        pResInfo->numOfRes = 1;
50,901,232✔
2850
      }
2851
    }
2852
  } else {
2853
    int     from = -1;
37,692,186✔
2854
    int32_t i = -1;
37,692,186✔
2855
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
173,103,827✔
2856
      if (colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
270,849,886✔
2857
        continue;
8,445,372✔
2858
      }
2859

2860
      numOfElems++;
126,979,571✔
2861
      char* pkData = NULL;
126,979,571✔
2862
      if (pCtx->hasPrimaryKey && !colDataIsNull_s(pkCol, i)) {
127,266,382✔
2863
        // pkCol[i] might be null when using cachemodel
2864
        // however, if using cachemodel, we don't need pk to determine the order
2865
        // because ts is enough
2866
        pkData = colDataGetData(pkCol, i);
286,805!
2867
      }
2868
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i] ||
126,979,571✔
2869
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
41,380,135!
2870
        char*   data = colDataGetData(pInputCol, i);
85,643,504!
2871
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], pkData, type, data);
85,643,504✔
2872
        if (code != TSDB_CODE_SUCCESS) {
85,630,202!
2873
          return code;
×
2874
        }
2875
        pResInfo->numOfRes = 1;
85,630,202✔
2876
      }
2877
    }
2878
  }
2879
#endif
2880

2881
#endif
2882

2883
  // save selectivity value for column consisted of all null values
2884
  if (numOfElems == 0) {
94,230,862✔
2885
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
1,320,019✔
2886
    if (code != TSDB_CODE_SUCCESS) {
1,320,019!
2887
      return code;
×
2888
    }
2889
    pInfo->nullTupleSaved = true;
1,320,019✔
2890
  }
2891

2892
  return TSDB_CODE_SUCCESS;
94,230,862✔
2893
}
2894

2895
static bool firstLastTransferInfoImpl(SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst) {
167,113,193✔
2896
  if (!pInput->hasResult) {
167,113,193!
2897
    return false;
×
2898
  }
2899
  __compar_fn_t pkCompareFn = NULL;
167,113,193✔
2900
  if (pInput->pkData) {
167,113,193✔
2901
    pkCompareFn = getKeyComparFunc(pInput->pkType, (isFirst) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC);
6,968✔
2902
  }
2903
  if (pOutput->hasResult) {
167,133,985✔
2904
    if (isFirst) {
47,560,640✔
2905
      if (pInput->ts > pOutput->ts ||
567,551✔
2906
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
327,716✔
2907
        return false;
239,926✔
2908
      }
2909
    } else {
2910
      if (pInput->ts < pOutput->ts ||
46,993,089✔
2911
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
23,226,647!
2912
        return false;
23,769,959✔
2913
      }
2914
    }
2915
  }
2916

2917
  pOutput->isNull = pInput->isNull;
143,124,100✔
2918
  pOutput->ts = pInput->ts;
143,124,100✔
2919
  pOutput->bytes = pInput->bytes;
143,124,100✔
2920
  pOutput->pkType = pInput->pkType;
143,124,100✔
2921

2922
  (void)memcpy(pOutput->buf, pInput->buf, pOutput->bytes);
143,124,100✔
2923
  if (pInput->pkData) {
143,124,100✔
2924
    pOutput->pkBytes = pInput->pkBytes;
6,531✔
2925
    (void)memcpy(pOutput->buf + pOutput->bytes, pInput->pkData, pOutput->pkBytes);
6,531✔
2926
    pOutput->pkData = pOutput->buf + pOutput->bytes;
6,531✔
2927
  }
2928
  return true;
143,124,100✔
2929
}
2930

2931
static int32_t firstLastTransferInfo(SqlFunctionCtx* pCtx, SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst,
167,106,482✔
2932
                                     int32_t rowIndex) {
2933
  if (firstLastTransferInfoImpl(pInput, pOutput, isFirst)) {
167,106,482✔
2934
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pOutput, false);
143,123,511✔
2935
    if (TSDB_CODE_SUCCESS != code) {
143,092,941!
2936
      return code;
×
2937
    }
2938
    pOutput->hasResult = true;
143,092,941✔
2939
  }
2940
  return TSDB_CODE_SUCCESS;
167,087,758✔
2941
}
2942

2943
static int32_t firstLastFunctionMergeImpl(SqlFunctionCtx* pCtx, bool isFirstQuery) {
120,128,226✔
2944
  SInputColumnInfoData* pInput = &pCtx->input;
120,128,226✔
2945
  SColumnInfoData*      pCol = pInput->pData[0];
120,128,226✔
2946

2947
  if (IS_NULL_TYPE(pCol->info.type)) {
120,128,226!
2948
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
2949
    return TSDB_CODE_SUCCESS;
×
2950
  }
2951

2952
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
120,128,226!
2953
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
2954
  }
2955

2956
  SFirstLastRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
120,128,226✔
2957

2958
  int32_t start = pInput->startRowIndex;
120,128,226✔
2959
  int32_t numOfElems = 0;
120,128,226✔
2960

2961
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
287,214,333✔
2962
    if (colDataIsNull_s(pCol, i)) {
334,254,674✔
2963
      continue;
1,175✔
2964
    }
2965
    char*          data = colDataGetData(pCol, i);
167,126,162!
2966
    SFirstLastRes* pInputInfo = (SFirstLastRes*)varDataVal(data);
167,126,162✔
2967
    if (pCtx->hasPrimaryKey) {
167,126,162✔
2968
      pInputInfo->pkData = pInputInfo->buf + pInputInfo->bytes;
6,968✔
2969
    } else {
2970
      pInputInfo->pkData = NULL;
167,119,194✔
2971
    }
2972

2973
    int32_t code = firstLastTransferInfo(pCtx, pInputInfo, pInfo, isFirstQuery, i);
167,126,162✔
2974
    if (code != TSDB_CODE_SUCCESS) {
167,084,932!
2975
      return code;
×
2976
    }
2977
    if (!numOfElems) {
167,084,932✔
2978
      numOfElems = pInputInfo->hasResult ? 1 : 0;
120,123,498✔
2979
    }
2980
  }
2981

2982
  if (numOfElems == 0) {
120,086,996✔
2983
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
1,175✔
2984
    if (code != TSDB_CODE_SUCCESS) {
1,175!
2985
      return code;
×
2986
    }
2987
    pInfo->nullTupleSaved = true;
1,175✔
2988
  }
2989

2990
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
120,086,996✔
2991
  return TSDB_CODE_SUCCESS;
120,086,996✔
2992
}
2993

2994
int32_t firstFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, true); }
28,519,334✔
2995

2996
int32_t lastFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, false); }
91,631,891✔
2997

2998
int32_t firstLastFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
291,880,790✔
2999
  int32_t          code = TSDB_CODE_SUCCESS;
291,880,790✔
3000
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
291,880,790✔
3001
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
291,880,790✔
3002
  if (NULL == pCol) {
291,309,694!
3003
    return TSDB_CODE_OUT_OF_RANGE;
×
3004
  }
3005

3006
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
291,309,694✔
3007
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
291,309,694✔
3008

3009
  SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pResInfo);
291,309,694✔
3010

3011
  if (pResInfo->isNullRes) {
291,309,694✔
3012
    colDataSetNULL(pCol, pBlock->info.rows);
479,939✔
3013
    return setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
479,939✔
3014
  }
3015
  code = colDataSetVal(pCol, pBlock->info.rows, pRes->buf, pRes->isNull || pResInfo->isNullRes);
290,829,755!
3016
  if (TSDB_CODE_SUCCESS != code) {
290,058,231!
3017
    return code;
×
3018
  }
3019

3020
  // handle selectivity
3021
  code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
290,058,231✔
3022
  if (TSDB_CODE_SUCCESS != code) {
290,165,872!
3023
    qError("%s failed at %d, msg:%s", __func__, __LINE__, tstrerror(code));
×
3024
  }
3025

3026
  return code;
290,170,134✔
3027
}
3028

3029
int32_t firstLastPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
166,742,092✔
3030
  int32_t code = TSDB_CODE_SUCCESS;
166,742,092✔
3031

3032
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
166,742,092✔
3033
  SFirstLastRes*       pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
166,742,092✔
3034

3035
  int32_t resultBytes = getFirstLastInfoSize(pRes->bytes, pRes->pkBytes);
166,742,092✔
3036

3037
  // todo check for failure
3038
  char* res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
166,817,403!
3039
  if (NULL == res) {
167,415,193!
3040
    return terrno;
×
3041
  }
3042
  (void)memcpy(varDataVal(res), pRes, resultBytes);
167,415,193✔
3043

3044
  varDataSetLen(res, resultBytes);
167,415,193✔
3045

3046
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
167,415,193✔
3047
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
167,415,193✔
3048
  if (NULL == pCol) {
166,354,911!
3049
    taosMemoryFree(res);
×
3050
    return TSDB_CODE_OUT_OF_RANGE;
×
3051
  }
3052

3053
  if (pEntryInfo->numOfRes == 0) {
166,361,436✔
3054
    colDataSetNULL(pCol, pBlock->info.rows);
1,314!
3055
    code = setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
1,314✔
3056
  } else {
3057
    code = colDataSetVal(pCol, pBlock->info.rows, res, false);
166,360,122✔
3058
    if (TSDB_CODE_SUCCESS != code) {
165,072,425!
3059
      taosMemoryFree(res);
×
3060
      return code;
×
3061
    }
3062
    code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
165,072,425✔
3063
  }
3064
  taosMemoryFree(res);
165,406,924!
3065
  return code;
167,269,873✔
3066
}
3067

3068
int32_t lastCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
3069
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
3070
  SFirstLastRes*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
3071
  int32_t              bytes = pDBuf->bytes;
×
3072

3073
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
3074
  SFirstLastRes*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
3075

3076
  pDBuf->hasResult = firstLastTransferInfoImpl(pSBuf, pDBuf, false);
×
3077
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
3078
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
3079
  return TSDB_CODE_SUCCESS;
×
3080
}
3081

3082
static int32_t doSaveLastrow(SqlFunctionCtx* pCtx, char* pData, int32_t rowIndex, int64_t cts, SFirstLastRes* pInfo) {
205,360,644✔
3083
  SInputColumnInfoData* pInput = &pCtx->input;
205,360,644✔
3084
  SColumnInfoData*      pInputCol = pInput->pData[0];
205,360,644✔
3085
  SColumnInfoData*      pkCol = pInput->pPrimaryKey;
205,360,644✔
3086

3087
  if (colDataIsNull_s(pInputCol, rowIndex)) {
410,721,288✔
3088
    pInfo->isNull = true;
488,254✔
3089
  } else {
3090
    pInfo->isNull = false;
204,872,390✔
3091

3092
    if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
204,872,390!
3093
      pInfo->bytes = calcStrBytesByType(pInputCol->info.type, pData);
329,636✔
3094
      // if (pInputCol->info.type == TSDB_DATA_TYPE_JSON) {
3095
      //   pInfo->bytes = getJsonValueLen(pData);
3096
      // } else {
3097
      //   pInfo->bytes = varDataTLen(pData);
3098
      // }
3099
    }
3100

3101
    (void)memcpy(pInfo->buf, pData, pInfo->bytes);
204,893,640✔
3102
  }
3103

3104
  if (pCtx->hasPrimaryKey && !colDataIsNull_s(pkCol, rowIndex)) {
205,398,252✔
3105
    char* pkData = colDataGetData(pkCol, rowIndex);
16,354!
3106
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
16,354!
3107
      pInfo->pkBytes = calcStrBytesByType(pInfo->pkType, pkData);
5,313✔
3108
    }
3109
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
16,357✔
3110
    pInfo->pkData = pInfo->buf + pInfo->bytes;
16,357✔
3111
  }
3112
  pInfo->ts = cts;
205,381,897✔
3113
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
205,381,897✔
3114
  if (code != TSDB_CODE_SUCCESS) {
205,259,023!
3115
    return code;
×
3116
  }
3117

3118
  pInfo->hasResult = true;
205,259,023✔
3119

3120
  return TSDB_CODE_SUCCESS;
205,259,023✔
3121
}
3122

3123
int32_t lastRowFunction(SqlFunctionCtx* pCtx) {
205,326,824✔
3124
  int32_t numOfElems = 0;
205,326,824✔
3125

3126
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
205,326,824✔
3127
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
205,326,824✔
3128

3129
  SInputColumnInfoData* pInput = &pCtx->input;
205,326,824✔
3130
  SColumnInfoData*      pInputCol = pInput->pData[0];
205,326,824✔
3131

3132
  int32_t type = pInputCol->info.type;
205,326,824✔
3133
  int32_t bytes = pInputCol->info.bytes;
205,326,824✔
3134
  pInfo->bytes = bytes;
205,326,824✔
3135

3136
  if (IS_NULL_TYPE(type)) {
205,326,824✔
3137
    return TSDB_CODE_SUCCESS;
125✔
3138
  }
3139
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
205,326,699✔
3140
  pInfo->pkType = -1;
205,326,699✔
3141
  __compar_fn_t pkCompareFn = NULL;
205,326,699✔
3142
  if (pCtx->hasPrimaryKey) {
205,326,699✔
3143
    pInfo->pkType = pkCol->info.type;
20,846✔
3144
    pInfo->pkBytes = pkCol->info.bytes;
20,846✔
3145
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
20,846✔
3146
  }
3147
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
205,362,108!
3148
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
205,362,108!
3149

3150
  if (pCtx->order == TSDB_ORDER_ASC && !pCtx->hasPrimaryKey) {
205,362,108!
3151
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
229,130,135!
3152
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
114,575,652✔
3153
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
114,575,652!
3154
      TSKEY cts = getRowPTs(pInput->pPTS, i);
114,575,652!
3155
      numOfElems++;
114,575,652✔
3156

3157
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
114,575,652✔
3158
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
112,803,066✔
3159
        if (code != TSDB_CODE_SUCCESS) return code;
112,786,948!
3160
      }
3161

3162
      break;
114,559,534✔
3163
    }
3164
  } else if (pCtx->order == TSDB_ORDER_DESC && !pCtx->hasPrimaryKey) {
90,791,507!
3165
    // the optimized version only valid if all tuples in one block are monotonious increasing or descreasing.
3166
    // this assumption is NOT always works if project operator exists in downstream.
3167
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
181,705,963!
3168
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
90,913,044✔
3169
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
90,913,044!
3170
      TSKEY cts = getRowPTs(pInput->pPTS, i);
90,913,044!
3171
      numOfElems++;
90,913,044✔
3172

3173
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
90,913,044✔
3174
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
89,808,023✔
3175
        if (code != TSDB_CODE_SUCCESS) return code;
89,718,920!
3176
      }
3177
      break;
90,823,941✔
3178
    }
3179
  } else {
3180
    int64_t* pts = (int64_t*)pInput->pPTS->pData;
×
3181
    int      from = -1;
×
3182
    int32_t  i = -1;
×
3183
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
4,177,024✔
3184
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
4,267,509✔
3185
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
4,267,509!
3186
      TSKEY cts = pts[i];
4,267,509✔
3187

3188
      numOfElems++;
4,267,509✔
3189
      char* pkData = NULL;
4,267,509✔
3190
      if (pCtx->hasPrimaryKey) {
4,267,509✔
3191
        pkData = colDataGetData(pkCol, i);
281,891!
3192
      }
3193
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts ||
4,267,509✔
3194
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
1,509,430✔
3195
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
2,758,085✔
3196
        if (code != TSDB_CODE_SUCCESS) {
2,758,116!
3197
          return code;
×
3198
        }
3199
        pResInfo->numOfRes = 1;
2,758,116✔
3200
      }
3201
    }
3202
  }
3203

3204
  SET_VAL(pResInfo, numOfElems, 1);
205,380,697!
3205
  return TSDB_CODE_SUCCESS;
205,380,697✔
3206
}
3207

3208
bool getDiffFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
107,253✔
3209
  pEnv->calcMemSize = sizeof(SDiffInfo);
107,253✔
3210
  return true;
107,253✔
3211
}
3212

3213
int32_t diffFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
4,245,678✔
3214
  if (pResInfo->initialized) {
4,245,678✔
3215
    return TSDB_CODE_SUCCESS;
4,096,488✔
3216
  }
3217
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
149,190!
3218
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3219
  }
3220
  SDiffInfo* pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
149,192✔
3221
  pDiffInfo->hasPrev = false;
149,192✔
3222
  pDiffInfo->isFirstRow = true;
149,192✔
3223
  pDiffInfo->prev.i64 = 0;
149,192✔
3224
  pDiffInfo->prevTs = -1;
149,192✔
3225
  if (pCtx->numOfParams > 1) {
149,192!
3226
    pDiffInfo->ignoreOption = pCtx->param[1].param.i;  // TODO set correct param
149,192✔
3227
  } else {
3228
    pDiffInfo->ignoreOption = 0;
×
3229
  }
3230
  return TSDB_CODE_SUCCESS;
149,192✔
3231
}
3232

3233
static int32_t doSetPrevVal(SDiffInfo* pDiffInfo, int32_t type, const char* pv, int64_t ts) {
5,272,501✔
3234
  switch (type) {
5,272,501!
3235
    case TSDB_DATA_TYPE_BOOL:
37✔
3236
      pDiffInfo->prev.i64 = *(bool*)pv ? 1 : 0;
37✔
3237
      break;
37✔
3238
    case TSDB_DATA_TYPE_UTINYINT:
1,748,919✔
3239
    case TSDB_DATA_TYPE_TINYINT:
3240
      pDiffInfo->prev.i64 = *(int8_t*)pv;
1,748,919✔
3241
      break;
1,748,919✔
3242
    case TSDB_DATA_TYPE_UINT:
770,099✔
3243
    case TSDB_DATA_TYPE_INT:
3244
      pDiffInfo->prev.i64 = *(int32_t*)pv;
770,099✔
3245
      break;
770,099✔
3246
    case TSDB_DATA_TYPE_USMALLINT:
1,871,853✔
3247
    case TSDB_DATA_TYPE_SMALLINT:
3248
      pDiffInfo->prev.i64 = *(int16_t*)pv;
1,871,853✔
3249
      break;
1,871,853✔
3250
    case TSDB_DATA_TYPE_TIMESTAMP:
626✔
3251
    case TSDB_DATA_TYPE_UBIGINT:
3252
    case TSDB_DATA_TYPE_BIGINT:
3253
      pDiffInfo->prev.i64 = *(int64_t*)pv;
626✔
3254
      break;
626✔
3255
    case TSDB_DATA_TYPE_FLOAT:
880,632✔
3256
      pDiffInfo->prev.d64 = *(float*)pv;
880,632✔
3257
      break;
880,632✔
3258
    case TSDB_DATA_TYPE_DOUBLE:
335✔
3259
      pDiffInfo->prev.d64 = *(double*)pv;
335✔
3260
      break;
335✔
3261
    default:
×
3262
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3263
  }
3264
  pDiffInfo->prevTs = ts;
5,272,501✔
3265
  pDiffInfo->hasPrev = true;
5,272,501✔
3266
  return TSDB_CODE_SUCCESS;
5,272,501✔
3267
}
3268

3269
static bool diffIsNegtive(SDiffInfo* pDiffInfo, int32_t type, const char* pv) {
21,281,979✔
3270
  switch (type) {
21,281,979!
3271
    case TSDB_DATA_TYPE_UINT: {
×
3272
      int64_t v = *(uint32_t*)pv;
×
3273
      return v < pDiffInfo->prev.i64;
×
3274
    }
3275
    case TSDB_DATA_TYPE_INT: {
3,189,906✔
3276
      int64_t v = *(int32_t*)pv;
3,189,906✔
3277
      return v < pDiffInfo->prev.i64;
3,189,906✔
3278
    }
3279
    case TSDB_DATA_TYPE_BOOL: {
×
3280
      int64_t v = *(bool*)pv;
×
3281
      return v < pDiffInfo->prev.i64;
×
3282
    }
3283
    case TSDB_DATA_TYPE_UTINYINT: {
×
3284
      int64_t v = *(uint8_t*)pv;
×
3285
      return v < pDiffInfo->prev.i64;
×
3286
    }
3287
    case TSDB_DATA_TYPE_TINYINT: {
6,776,588✔
3288
      int64_t v = *(int8_t*)pv;
6,776,588✔
3289
      return v < pDiffInfo->prev.i64;
6,776,588✔
3290
    }
3291
    case TSDB_DATA_TYPE_USMALLINT: {
×
3292
      int64_t v = *(uint16_t*)pv;
×
3293
      return v < pDiffInfo->prev.i64;
×
3294
    }
3295
    case TSDB_DATA_TYPE_SMALLINT: {
8,005,518✔
3296
      int64_t v = *(int16_t*)pv;
8,005,518✔
3297
      return v < pDiffInfo->prev.i64;
8,005,518✔
3298
    }
3299
    case TSDB_DATA_TYPE_UBIGINT: {
40✔
3300
      uint64_t v = *(uint64_t*)pv;
40✔
3301
      return v < (uint64_t)pDiffInfo->prev.i64;
40✔
3302
    }
3303
    case TSDB_DATA_TYPE_TIMESTAMP:
2,329✔
3304
    case TSDB_DATA_TYPE_BIGINT: {
3305
      int64_t v = *(int64_t*)pv;
2,329✔
3306
      return v < pDiffInfo->prev.i64;
2,329✔
3307
    }
3308
    case TSDB_DATA_TYPE_FLOAT: {
3,305,364✔
3309
      float v = *(float*)pv;
3,305,364✔
3310
      return v < pDiffInfo->prev.d64;
3,305,364✔
3311
    }
3312
    case TSDB_DATA_TYPE_DOUBLE: {
2,234✔
3313
      double v = *(double*)pv;
2,234✔
3314
      return v < pDiffInfo->prev.d64;
2,234✔
3315
    }
3316
    default:
×
3317
      return false;
×
3318
  }
3319

3320
  return false;
3321
}
3322

3323
static void tryToSetInt64(SDiffInfo* pDiffInfo, int32_t type, SColumnInfoData* pOutput, int64_t v, int32_t pos) {
2,147,483,647✔
3324
  bool isNegative = v < pDiffInfo->prev.i64;
2,147,483,647✔
3325
  if (type == TSDB_DATA_TYPE_UBIGINT) {
2,147,483,647✔
3326
    isNegative = (uint64_t)v < (uint64_t)pDiffInfo->prev.i64;
1,491✔
3327
  }
3328
  int64_t delta = v - pDiffInfo->prev.i64;
2,147,483,647✔
3329
  if (isNegative && ignoreNegative(pDiffInfo->ignoreOption)) {
2,147,483,647✔
3330
    colDataSetNull_f_s(pOutput, pos);
4,780,302✔
3331
    pOutput->hasNull = true;
4,780,302✔
3332
  } else {
3333
    colDataSetInt64(pOutput, pos, &delta);
2,147,483,647✔
3334
  }
3335
  pDiffInfo->prev.i64 = v;
2,147,483,647✔
3336
}
2,147,483,647✔
3337

3338
static void tryToSetDouble(SDiffInfo* pDiffInfo, SColumnInfoData* pOutput, double v, int32_t pos) {
4,092,778✔
3339
  double delta = v - pDiffInfo->prev.d64;
4,092,778✔
3340
  if (delta < 0 && ignoreNegative(pDiffInfo->ignoreOption)) {
4,092,778✔
3341
    colDataSetNull_f_s(pOutput, pos);
867,252✔
3342
  } else {
3343
    colDataSetDouble(pOutput, pos, &delta);
3,225,526✔
3344
  }
3345
  pDiffInfo->prev.d64 = v;
4,092,778✔
3346
}
4,092,778✔
3347

3348
static int32_t doHandleDiff(SDiffInfo* pDiffInfo, int32_t type, const char* pv, SColumnInfoData* pOutput, int32_t pos,
2,147,483,647✔
3349
                            int64_t ts) {
3350
  if (!pDiffInfo->hasPrev) {
2,147,483,647✔
3351
    colDataSetNull_f_s(pOutput, pos);
500✔
3352
    return doSetPrevVal(pDiffInfo, type, pv, ts);
500✔
3353
  }
3354
  pDiffInfo->prevTs = ts;
2,147,483,647✔
3355
  switch (type) {
2,147,483,647!
3356
    case TSDB_DATA_TYPE_UINT: {
1,421✔
3357
      int64_t v = *(uint32_t*)pv;
1,421✔
3358
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
1,421✔
3359
      break;
1,421✔
3360
    }
3361
    case TSDB_DATA_TYPE_INT: {
24,007,823✔
3362
      int64_t v = *(int32_t*)pv;
24,007,823✔
3363
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
24,007,823✔
3364
      break;
24,007,823✔
3365
    }
3366
    case TSDB_DATA_TYPE_BOOL: {
878✔
3367
      int64_t v = *(bool*)pv;
878✔
3368
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
878✔
3369
      break;
878✔
3370
    }
3371
    case TSDB_DATA_TYPE_UTINYINT: {
675✔
3372
      int64_t v = *(uint8_t*)pv;
675✔
3373
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
675✔
3374
      break;
675✔
3375
    }
3376
    case TSDB_DATA_TYPE_TINYINT: {
6,170,473✔
3377
      int64_t v = *(int8_t*)pv;
6,170,473✔
3378
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
6,170,473✔
3379
      break;
6,170,473✔
3380
    }
3381
    case TSDB_DATA_TYPE_USMALLINT: {
675✔
3382
      int64_t v = *(uint16_t*)pv;
675✔
3383
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
675✔
3384
      break;
675✔
3385
    }
3386
    case TSDB_DATA_TYPE_SMALLINT: {
7,709,456✔
3387
      int64_t v = *(int16_t*)pv;
7,709,456✔
3388
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
7,709,456✔
3389
      break;
7,709,456✔
3390
    }
3391
    case TSDB_DATA_TYPE_TIMESTAMP:
2,147,483,647✔
3392
    case TSDB_DATA_TYPE_UBIGINT:
3393
    case TSDB_DATA_TYPE_BIGINT: {
3394
      int64_t v = *(int64_t*)pv;
2,147,483,647✔
3395
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
2,147,483,647✔
3396
      break;
2,147,483,647✔
3397
    }
3398
    case TSDB_DATA_TYPE_FLOAT: {
4,081,125✔
3399
      double v = *(float*)pv;
4,081,125✔
3400
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
4,081,125✔
3401
      break;
4,081,125✔
3402
    }
3403
    case TSDB_DATA_TYPE_DOUBLE: {
11,653✔
3404
      double v = *(double*)pv;
11,653✔
3405
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
11,653✔
3406
      break;
11,653✔
3407
    }
3408
    default:
×
3409
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3410
  }
3411
  pDiffInfo->hasPrev = true;
2,147,483,647✔
3412
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3413
}
3414

3415
// TODO: the primary key compare can be skipped for ordered pk if knonwn before
3416
// TODO: for desc ordered, pk shall select the smallest one for one ts. if across block boundaries.
3417
bool funcInputGetNextRowIndex(SInputColumnInfoData* pInput, int32_t from, bool firstOccur, int32_t* pRowIndex,
512,924,673✔
3418
                              int32_t* nextFrom) {
3419
  if (pInput->pPrimaryKey == NULL) {
512,924,673✔
3420
    if (from == -1) {
512,022,878✔
3421
      from = pInput->startRowIndex;
120,097,567✔
3422
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
391,925,311✔
3423
      return false;
120,066,602✔
3424
    }
3425
    *pRowIndex = from;
391,956,276✔
3426
    *nextFrom = from + 1;
391,956,276✔
3427
    return true;
391,956,276✔
3428
  } else {
3429
    if (from == -1) {
901,795✔
3430
      from = pInput->startRowIndex;
64,499✔
3431
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
837,296✔
3432
      return false;
64,485✔
3433
    }
3434
    TSKEY*           tsList = (int64_t*)pInput->pPTS->pData;
837,310✔
3435
    SColumnInfoData* pkCol = pInput->pPrimaryKey;
837,310✔
3436
    int8_t           pkType = pkCol->info.type;
837,310✔
3437
    int32_t          order = (firstOccur) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
837,310✔
3438
    __compar_fn_t    compareFunc = getKeyComparFunc(pkType, order);
837,310✔
3439
    int32_t          select = from;
847,388✔
3440
    char*            val = colDataGetData(pkCol, select);
847,388!
3441
    while (from < pInput->numOfRows + pInput->startRowIndex - 1 && tsList[from + 1] == tsList[from]) {
2,131,073✔
3442
      char* val1 = colDataGetData(pkCol, from + 1);
1,283,692!
3443
      if (compareFunc(val1, val) < 0) {
1,283,692✔
3444
        select = from + 1;
395,712✔
3445
        val = val1;
395,712✔
3446
      }
3447
      from = from + 1;
1,283,685✔
3448
    }
3449
    *pRowIndex = select;
847,381✔
3450
    *nextFrom = from + 1;
847,381✔
3451
    return true;
847,381✔
3452
  }
3453
}
3454

3455
bool getForecastConfEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
×
3456
  pEnv->calcMemSize = sizeof(double);
×
3457
  return true;
×
3458
}
3459

3460
int32_t diffResultIsNull(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
2,147,483,647✔
3461
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3462
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3463

3464
  if (pRow->isDataNull || !pDiffInfo->hasPrev) {
2,147,483,647✔
3465
    return true;
196,581✔
3466
  } else if (ignoreNegative(pDiffInfo->ignoreOption)) {
2,147,483,647✔
3467
    return diffIsNegtive(pDiffInfo, pCtx->input.pData[0]->info.type, pRow->pData);
21,077,975✔
3468
  }
3469
  return false;
2,147,483,647✔
3470
}
3471

3472
bool isFirstRow(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
2,147,483,647✔
3473
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3474
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3475
  return pDiffInfo->isFirstRow;
2,147,483,647✔
3476
}
3477

3478
int32_t trySetPreVal(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
5,273,333✔
3479
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5,273,333✔
3480
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
5,273,333✔
3481
  pDiffInfo->isFirstRow = false;
5,273,333✔
3482
  if (pRow->isDataNull) {
5,273,333✔
3483
    return TSDB_CODE_SUCCESS;
1,332✔
3484
  }
3485

3486
  SInputColumnInfoData* pInput = &pCtx->input;
5,272,001✔
3487
  SColumnInfoData*      pInputCol = pInput->pData[0];
5,272,001✔
3488
  int8_t                inputType = pInputCol->info.type;
5,272,001✔
3489

3490
  char* pv = pRow->pData;
5,272,001✔
3491
  return doSetPrevVal(pDiffInfo, inputType, pv, pRow->ts);
5,272,001✔
3492
}
3493

3494
int32_t setDoDiffResult(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, int32_t pos) {
2,147,483,647✔
3495
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3496
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3497

3498
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
3499
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
3500
  int8_t                inputType = pInputCol->info.type;
2,147,483,647✔
3501
  SColumnInfoData*      pOutput = (SColumnInfoData*)pCtx->pOutput;
2,147,483,647✔
3502
  int32_t               code = TSDB_CODE_SUCCESS;
2,147,483,647✔
3503
  if (pRow->isDataNull) {
2,147,483,647✔
3504
    colDataSetNull_f_s(pOutput, pos);
49,769✔
3505
    pOutput->hasNull = true;
49,769✔
3506

3507
    // handle selectivity
3508
    if (pCtx->subsidiaries.num > 0) {
49,769✔
3509
      code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
203✔
3510
      if (code != TSDB_CODE_SUCCESS) {
203!
3511
        return code;
×
3512
      }
3513
    }
3514
    return TSDB_CODE_SUCCESS;
49,769✔
3515
  }
3516

3517
  char* pv = pRow->pData;
2,147,483,647✔
3518

3519
  if (pRow->ts == pDiffInfo->prevTs) {
2,147,483,647✔
3520
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
22✔
3521
  }
3522
  code = doHandleDiff(pDiffInfo, inputType, pv, pOutput, pos, pRow->ts);
2,147,483,647✔
3523
  if (code != TSDB_CODE_SUCCESS) {
2,147,483,647!
3524
    return code;
×
3525
  }
3526
  // handle selectivity
3527
  if (pCtx->subsidiaries.num > 0) {
2,147,483,647✔
3528
    code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
49,995,421✔
3529
    if (code != TSDB_CODE_SUCCESS) {
49,995,421!
3530
      return code;
×
3531
    }
3532
  }
3533

3534
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3535
}
3536

3537
int32_t diffFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; }
4,138,422✔
3538

3539
int32_t diffFunctionByRow(SArray* pCtxArray) {
4,138,182✔
3540
  int32_t code = TSDB_CODE_SUCCESS;
4,138,182✔
3541
  int     diffColNum = pCtxArray->size;
4,138,182✔
3542
  if (diffColNum == 0) {
4,138,182!
3543
    return TSDB_CODE_SUCCESS;
×
3544
  }
3545
  int32_t numOfElems = 0;
4,138,182✔
3546

3547
  SArray* pRows = taosArrayInit_s(sizeof(SFuncInputRow), diffColNum);
4,138,182✔
3548
  if (NULL == pRows) {
4,138,190!
3549
    return terrno;
×
3550
  }
3551

3552
  bool keepNull = false;
4,138,191✔
3553
  for (int i = 0; i < diffColNum; ++i) {
8,276,615✔
3554
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
4,138,430✔
3555
    if (NULL == pCtx) {
4,138,422!
3556
      code = terrno;
×
3557
      goto _exit;
×
3558
    }
3559
    funcInputUpdate(pCtx);
4,138,422✔
3560
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
4,138,421✔
3561
    SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
4,138,421✔
3562
    if (!ignoreNull(pDiffInfo->ignoreOption)) {
4,138,421✔
3563
      keepNull = true;
4,081,758✔
3564
    }
3565
  }
3566

3567
  SqlFunctionCtx* pCtx0 = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, 0);
4,138,185✔
3568
  SFuncInputRow*  pRow0 = (SFuncInputRow*)taosArrayGet(pRows, 0);
4,138,181✔
3569
  if (NULL == pCtx0 || NULL == pRow0) {
4,138,180!
3570
    code = terrno;
×
3571
    goto _exit;
×
3572
  }
3573
  int32_t startOffset = pCtx0->offset;
4,138,181✔
3574
  bool    result = false;
4,138,181✔
3575
  while (1) {
2,147,483,647✔
3576
    code = funcInputGetNextRow(pCtx0, pRow0, &result);
2,147,483,647✔
3577
    if (TSDB_CODE_SUCCESS != code) {
2,147,483,647!
3578
      goto _exit;
×
3579
    }
3580
    if (!result) {
2,147,483,647✔
3581
      break;
4,138,167✔
3582
    }
3583
    bool hasNotNullValue = !diffResultIsNull(pCtx0, pRow0);
2,147,483,647✔
3584
    for (int i = 1; i < diffColNum; ++i) {
2,147,483,647✔
3585
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
7,381✔
3586
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
7,381✔
3587
      if (NULL == pCtx || NULL == pRow) {
7,381!
3588
        code = terrno;
×
3589
        goto _exit;
×
3590
      }
3591
      code = funcInputGetNextRow(pCtx, pRow, &result);
7,381✔
3592
      if (TSDB_CODE_SUCCESS != code) {
7,381!
3593
        goto _exit;
×
3594
      }
3595
      if (!result) {
7,381!
3596
        // rows are not equal
3597
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
3598
        goto _exit;
×
3599
      }
3600
      if (!diffResultIsNull(pCtx, pRow)) {
7,381✔
3601
        hasNotNullValue = true;
6,717✔
3602
      }
3603
    }
3604
    int32_t pos = startOffset + numOfElems;
2,147,483,647✔
3605

3606
    bool newRow = false;
2,147,483,647✔
3607
    for (int i = 0; i < diffColNum; ++i) {
2,147,483,647✔
3608
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
2,147,483,647✔
3609
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
2,147,483,647✔
3610
      if (NULL == pCtx || NULL == pRow) {
2,147,483,647!
3611
        code = terrno;
×
3612
        goto _exit;
×
3613
      }
3614
      if ((keepNull || hasNotNullValue) && !isFirstRow(pCtx, pRow)) {
2,147,483,647✔
3615
        code = setDoDiffResult(pCtx, pRow, pos);
2,147,483,647✔
3616
        if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
3617
          goto _exit;
22✔
3618
        }
3619
        newRow = true;
2,147,483,647✔
3620
      } else {
3621
        code = trySetPreVal(pCtx, pRow);
5,270,788✔
3622
        if (code != TSDB_CODE_SUCCESS) {
5,273,333!
3623
          goto _exit;
×
3624
        }
3625
      }
3626
    }
3627
    if (newRow) ++numOfElems;
2,147,483,647✔
3628
  }
3629

3630
  for (int i = 0; i < diffColNum; ++i) {
8,276,568✔
3631
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
4,138,402✔
3632
    if (NULL == pCtx) {
4,138,401!
3633
      code = terrno;
×
3634
      goto _exit;
×
3635
    }
3636
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
4,138,401✔
3637
    pResInfo->numOfRes = numOfElems;
4,138,401✔
3638
  }
3639

3640
_exit:
4,138,166✔
3641
  if (pRows) {
4,138,188!
3642
    taosArrayDestroy(pRows);
4,138,188✔
3643
    pRows = NULL;
4,138,192✔
3644
  }
3645
  return code;
4,138,192✔
3646
}
3647

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

3650
bool getTopBotFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
208,731✔
3651
  SValueNode* pkNode = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
208,731✔
3652
  pEnv->calcMemSize = sizeof(STopBotRes) + pkNode->datum.i * sizeof(STopBotResItem);
208,831✔
3653
  return true;
208,831✔
3654
}
3655

3656
int32_t topBotFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
124,328,348✔
3657
  if (pResInfo->initialized) {
124,328,348!
3658
    return TSDB_CODE_SUCCESS;
×
3659
  }
3660
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
124,328,348!
3661
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3662
  }
3663

3664
  STopBotRes*           pRes = GET_ROWCELL_INTERBUF(pResInfo);
124,405,647✔
3665
  SInputColumnInfoData* pInput = &pCtx->input;
124,405,647✔
3666

3667
  pRes->maxSize = pCtx->param[1].param.i;
124,405,647✔
3668

3669
  pRes->nullTupleSaved = false;
124,405,647✔
3670
  pRes->nullTuplePos.pageId = -1;
124,405,647✔
3671
  return TSDB_CODE_SUCCESS;
124,405,647✔
3672
}
3673

3674
static STopBotRes* getTopBotOutputInfo(SqlFunctionCtx* pCtx) {
585,092,514✔
3675
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
585,092,514✔
3676
  STopBotRes*          pRes = GET_ROWCELL_INTERBUF(pResInfo);
585,092,514✔
3677
  pRes->pItems = (STopBotResItem*)((char*)pRes + sizeof(STopBotRes));
585,092,514✔
3678

3679
  return pRes;
585,092,514✔
3680
}
3681

3682
static int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock,
3683
                               uint16_t type, uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery);
3684

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

3687
int32_t topFunction(SqlFunctionCtx* pCtx) {
76,701,240✔
3688
  int32_t              numOfElems = 0;
76,701,240✔
3689
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
76,701,240✔
3690

3691
  SInputColumnInfoData* pInput = &pCtx->input;
76,701,240✔
3692
  SColumnInfoData*      pCol = pInput->pData[0];
76,701,240✔
3693

3694
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
76,701,240✔
3695
  pRes->type = pInput->pData[0]->info.type;
76,694,173✔
3696

3697
  int32_t start = pInput->startRowIndex;
76,694,173✔
3698
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
284,490,335✔
3699
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
207,730,414✔
3700
      continue;
17,125✔
3701
    }
3702

3703
    numOfElems++;
207,713,289✔
3704
    char*   data = colDataGetData(pCol, i);
207,713,289!
3705
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, true);
207,713,289✔
3706
    if (code != TSDB_CODE_SUCCESS) {
207,779,037!
3707
      return code;
×
3708
    }
3709
  }
3710

3711
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
76,759,921✔
3712
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
5,651✔
3713
    if (code != TSDB_CODE_SUCCESS) {
5,651!
3714
      return code;
×
3715
    }
3716
    pRes->nullTupleSaved = true;
5,651✔
3717
  }
3718
  return TSDB_CODE_SUCCESS;
76,759,921✔
3719
}
3720

3721
int32_t bottomFunction(SqlFunctionCtx* pCtx) {
50,561,897✔
3722
  int32_t              numOfElems = 0;
50,561,897✔
3723
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
50,561,897✔
3724

3725
  SInputColumnInfoData* pInput = &pCtx->input;
50,561,897✔
3726
  SColumnInfoData*      pCol = pInput->pData[0];
50,561,897✔
3727

3728
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
50,561,897✔
3729
  pRes->type = pInput->pData[0]->info.type;
50,559,196✔
3730

3731
  int32_t start = pInput->startRowIndex;
50,559,196✔
3732
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
177,708,319✔
3733
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
127,119,491!
3734
      continue;
17,168✔
3735
    }
3736

3737
    numOfElems++;
127,102,323✔
3738
    char*   data = colDataGetData(pCol, i);
127,102,323!
3739
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, false);
127,102,323✔
3740
    if (code != TSDB_CODE_SUCCESS) {
127,131,955!
3741
      return code;
×
3742
    }
3743
  }
3744

3745
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
50,588,828✔
3746
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
3,832✔
3747
    if (code != TSDB_CODE_SUCCESS) {
3,832!
3748
      return code;
×
3749
    }
3750
    pRes->nullTupleSaved = true;
3,832✔
3751
  }
3752

3753
  return TSDB_CODE_SUCCESS;
50,588,828✔
3754
}
3755

3756
static int32_t topBotResComparFn(const void* p1, const void* p2, const void* param) {
1,163,407,639✔
3757
  uint16_t type = *(uint16_t*)param;
1,163,407,639✔
3758

3759
  STopBotResItem* val1 = (STopBotResItem*)p1;
1,163,407,639✔
3760
  STopBotResItem* val2 = (STopBotResItem*)p2;
1,163,407,639✔
3761

3762
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
1,163,407,639!
3763
    if (val1->v.i == val2->v.i) {
788,569,562✔
3764
      return 0;
268,561✔
3765
    }
3766

3767
    return (val1->v.i > val2->v.i) ? 1 : -1;
788,301,001✔
3768
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
374,838,077!
3769
    if (val1->v.u == val2->v.u) {
745,905✔
3770
      return 0;
157,369✔
3771
    }
3772

3773
    return (val1->v.u > val2->v.u) ? 1 : -1;
588,536✔
3774
  } else if (TSDB_DATA_TYPE_FLOAT == type) {
374,092,172✔
3775
    if (val1->v.f == val2->v.f) {
212,512,189✔
3776
      return 0;
63✔
3777
    }
3778

3779
    return (val1->v.f > val2->v.f) ? 1 : -1;
212,512,126✔
3780
  }
3781

3782
  if (val1->v.d == val2->v.d) {
161,579,983✔
3783
    return 0;
11✔
3784
  }
3785

3786
  return (val1->v.d > val2->v.d) ? 1 : -1;
161,579,972✔
3787
}
3788

3789
int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock, uint16_t type,
334,818,844✔
3790
                        uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery) {
3791
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
334,818,844✔
3792
  int32_t     code = TSDB_CODE_SUCCESS;
334,735,731✔
3793

3794
  SVariant val = {0};
334,735,731✔
3795
  TAOS_CHECK_RETURN(taosVariantCreateFromBinary(&val, pData, tDataTypes[type].bytes, type));
334,735,731!
3796

3797
  STopBotResItem* pItems = pRes->pItems;
334,931,382✔
3798

3799
  // not full yet
3800
  if (pEntryInfo->numOfRes < pRes->maxSize) {
334,931,382✔
3801
    STopBotResItem* pItem = &pItems[pEntryInfo->numOfRes];
214,121,169✔
3802
    pItem->v = val;
214,121,169✔
3803
    pItem->uid = uid;
214,121,169✔
3804

3805
    // save the data of this tuple
3806
    if (pCtx->subsidiaries.num > 0) {
214,121,169✔
3807
      code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
114,167,708✔
3808
      if (code != TSDB_CODE_SUCCESS) {
114,023,681!
3809
        return code;
×
3810
      }
3811
    }
3812
#ifdef BUF_PAGE_DEBUG
3813
    qDebug("page_saveTuple i:%d, item:%p,pageId:%d, offset:%d\n", pEntryInfo->numOfRes, pItem, pItem->tuplePos.pageId,
3814
           pItem->tuplePos.offset);
3815
#endif
3816
    // allocate the buffer and keep the data of this row into the new allocated buffer
3817
    pEntryInfo->numOfRes++;
213,977,142✔
3818
    code = taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type,
213,977,142✔
3819
                        topBotResComparFn, !isTopQuery);
213,977,142✔
3820
    if (code != TSDB_CODE_SUCCESS) {
214,189,151!
3821
      return code;
×
3822
    }
3823
  } else {  // replace the minimum value in the result
3824
    if ((isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i > pItems[0].v.i) ||
120,810,213!
3825
                        (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u > pItems[0].v.u) ||
67,100,175!
3826
                        (TSDB_DATA_TYPE_FLOAT == type && val.f > pItems[0].v.f) ||
67,008,310✔
3827
                        (TSDB_DATA_TYPE_DOUBLE == type && val.d > pItems[0].v.d))) ||
63,637,446✔
3828
        (!isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i < pItems[0].v.i) ||
104,741,112!
3829
                         (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u < pItems[0].v.u) ||
35,518,100!
3830
                         (TSDB_DATA_TYPE_FLOAT == type && val.f < pItems[0].v.f) ||
35,515,641✔
3831
                         (TSDB_DATA_TYPE_DOUBLE == type && val.d < pItems[0].v.d)))) {
35,389,536✔
3832
      // replace the old data and the coresponding tuple data
3833
      STopBotResItem* pItem = &pItems[0];
26,246,000✔
3834
      pItem->v = val;
26,246,000✔
3835
      pItem->uid = uid;
26,246,000✔
3836

3837
      // save the data of this tuple by over writing the old data
3838
      if (pCtx->subsidiaries.num > 0) {
26,246,000✔
3839
        code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
17,117,933✔
3840
        if (code != TSDB_CODE_SUCCESS) {
17,109,593!
3841
          return code;
×
3842
        }
3843
      }
3844
#ifdef BUF_PAGE_DEBUG
3845
      qDebug("page_copyTuple pageId:%d, offset:%d", pItem->tuplePos.pageId, pItem->tuplePos.offset);
3846
#endif
3847
      code = taosheapadjust((void*)pItems, sizeof(STopBotResItem), 0, pEntryInfo->numOfRes - 1, (const void*)&type,
26,237,660✔
3848
                            topBotResComparFn, NULL, !isTopQuery);
26,237,660✔
3849
      if (code != TSDB_CODE_SUCCESS) {
26,092,999!
3850
        return code;
×
3851
      }
3852
    }
3853
  }
3854

3855
  return TSDB_CODE_SUCCESS;
334,846,363✔
3856
}
3857

3858
/*
3859
 * +------------------------------------+--------------+--------------+
3860
 * |            null bitmap             |              |              |
3861
 * |(n columns, one bit for each column)| src column #1| src column #2|
3862
 * +------------------------------------+--------------+--------------+
3863
 */
3864
int32_t serializeTupleData(const SSDataBlock* pSrcBlock, int32_t rowIndex, SSubsidiaryResInfo* pSubsidiaryies,
721,175,104✔
3865
                           char* buf, char** res) {
3866
  char* nullList = buf;
721,175,104✔
3867
  char* pStart = (char*)(nullList + sizeof(bool) * pSubsidiaryies->num);
721,175,104✔
3868

3869
  int32_t offset = 0;
721,175,104✔
3870
  for (int32_t i = 0; i < pSubsidiaryies->num; ++i) {
1,439,819,234✔
3871
    SqlFunctionCtx* pc = pSubsidiaryies->pCtx[i];
721,249,781✔
3872

3873
    // group_key function has its own process function
3874
    // do not process there
3875
    if (fmIsGroupKeyFunc(pc->functionId)) {
721,249,781!
3876
      continue;
×
3877
    }
3878

3879
    SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
721,155,941✔
3880
    int32_t      srcSlotId = pFuncParam->pCol->slotId;
721,155,941✔
3881

3882
    SColumnInfoData* pCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
721,155,941✔
3883
    if (NULL == pCol) {
718,102,798!
3884
      return TSDB_CODE_OUT_OF_RANGE;
×
3885
    }
3886
    if ((nullList[i] = colDataIsNull_s(pCol, rowIndex)) == true) {
1,436,205,596✔
3887
      offset += pCol->info.bytes;
31,009✔
3888
      continue;
31,009✔
3889
    }
3890

3891
    char* p = colDataGetData(pCol, rowIndex);
718,071,789!
3892
    if (IS_VAR_DATA_TYPE(pCol->info.type)) {
718,071,789!
3893
      int32_t bytes = calcStrBytesByType(pCol->info.type, p);
×
3894
      (void)memcpy(pStart + offset, p, bytes);
50,461✔
3895
    } else {
3896
      (void)memcpy(pStart + offset, p, pCol->info.bytes);
718,562,660✔
3897
    }
3898

3899
    offset += pCol->info.bytes;
718,613,121✔
3900
  }
3901

3902
  *res = buf;
718,569,453✔
3903
  return TSDB_CODE_SUCCESS;
718,569,453✔
3904
}
3905

3906
static int32_t doSaveTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, SWinKey* key,
815,493,954✔
3907
                               STuplePos* pPos, SFunctionStateStore* pStore) {
3908
  STuplePos p = {0};
815,493,954✔
3909
  if (pHandle->pBuf != NULL) {
815,493,954!
3910
    SFilePage* pPage = NULL;
816,139,901✔
3911

3912
    if (pHandle->currentPage == -1) {
816,139,901✔
3913
      pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
1,919,865✔
3914
      if (pPage == NULL) {
1,919,873!
3915
        return terrno;
×
3916
      }
3917
      pPage->num = sizeof(SFilePage);
1,919,873✔
3918
    } else {
3919
      pPage = getBufPage(pHandle->pBuf, pHandle->currentPage);
814,220,036✔
3920
      if (pPage == NULL) {
813,966,857!
3921
        return terrno;
×
3922
      }
3923
      if (pPage->num + length > getBufPageSize(pHandle->pBuf)) {
813,966,857✔
3924
        // current page is all used, let's prepare a new buffer page
3925
        releaseBufPage(pHandle->pBuf, pPage);
7,584,039✔
3926
        pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
7,584,038✔
3927
        if (pPage == NULL) {
7,584,031!
3928
          return terrno;
×
3929
        }
3930
        pPage->num = sizeof(SFilePage);
7,584,031✔
3931
      }
3932
    }
3933

3934
    p = (STuplePos){.pageId = pHandle->currentPage, .offset = pPage->num};
815,837,213✔
3935
    (void)memcpy(pPage->data + pPage->num, pBuf, length);
815,837,213✔
3936

3937
    pPage->num += length;
815,837,213✔
3938
    setBufPageDirty(pPage, true);
815,837,213✔
3939
    releaseBufPage(pHandle->pBuf, pPage);
815,614,974✔
3940
  } else {  // other tuple save policy
3941
    if (pStore->streamStateFuncPut(pHandle->pState, key, pBuf, length) >= 0) {
×
3942
      p.streamTupleKey = *key;
×
3943
    }
3944
  }
3945

3946
  *pPos = p;
815,168,106✔
3947
  return TSDB_CODE_SUCCESS;
815,168,106✔
3948
}
3949

3950
int32_t saveTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
582,218,178✔
3951
  int32_t code = prepareBuf(pCtx);
582,218,178✔
3952
  if (TSDB_CODE_SUCCESS != code) {
582,143,207!
3953
    return code;
×
3954
  }
3955

3956
  SWinKey key = {0};
582,143,207✔
3957
  if (pCtx->saveHandle.pBuf == NULL) {
582,143,207!
3958
    SColumnInfoData* pColInfo = taosArrayGet(pSrcBlock->pDataBlock, pCtx->saveHandle.pState->tsIndex);
×
3959
    if (NULL == pColInfo) {
×
3960
      return TSDB_CODE_OUT_OF_RANGE;
×
3961
    }
3962
    if (pColInfo->info.type != TSDB_DATA_TYPE_TIMESTAMP) {
×
3963
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3964
    }
3965
    key.groupId = pSrcBlock->info.id.groupId;
×
3966
    key.ts = *(int64_t*)colDataGetData(pColInfo, rowIndex);
×
3967
    key.numInGroup = pCtx->pExpr->pExpr->_function.bindExprID;
×
3968
  }
3969

3970
  char* buf = NULL;
582,143,207✔
3971
  code = serializeTupleData(pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
582,143,207✔
3972
  if (TSDB_CODE_SUCCESS != code) {
580,755,246!
3973
    return code;
×
3974
  }
3975
  return doSaveTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, &key, pPos, pCtx->pStore);
580,755,246✔
3976
}
3977

3978
static int32_t doUpdateTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, STuplePos* pPos,
139,207,085✔
3979
                                 SFunctionStateStore* pStore) {
3980
  if (pHandle->pBuf != NULL) {
139,207,085!
3981
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
139,207,640✔
3982
    if (pPage == NULL) {
139,210,370!
3983
      return terrno;
×
3984
    }
3985
    (void)memcpy(pPage->data + pPos->offset, pBuf, length);
139,210,370✔
3986
    setBufPageDirty(pPage, true);
139,210,370✔
3987
    releaseBufPage(pHandle->pBuf, pPage);
139,199,564✔
3988
  } else {
3989
    int32_t code = pStore->streamStateFuncPut(pHandle->pState, &pPos->streamTupleKey, pBuf, length);
×
3990
    if (TSDB_CODE_SUCCESS != code) {
×
3991
      return code;
×
3992
    }
3993
  }
3994

3995
  return TSDB_CODE_SUCCESS;
139,185,799✔
3996
}
3997

3998
int32_t updateTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
139,240,049✔
3999
  int32_t code = prepareBuf(pCtx);
139,240,049✔
4000
  if (TSDB_CODE_SUCCESS != code) {
139,236,082!
4001
    return code;
×
4002
  }
4003

4004
  char* buf = NULL;
139,236,082✔
4005
  code = serializeTupleData(pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
139,236,082✔
4006
  if (TSDB_CODE_SUCCESS != code) {
139,180,208!
4007
    return code;
×
4008
  }
4009
  return doUpdateTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, pPos, pCtx->pStore);
139,180,208✔
4010
}
4011

4012
static int32_t doLoadTupleData(SSerializeDataHandle* pHandle, const STuplePos* pPos, SFunctionStateStore* pStore,
444,505,936✔
4013
                               char** value) {
4014
  if (pHandle->pBuf != NULL) {
444,505,936!
4015
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
444,704,302✔
4016
    if (pPage == NULL) {
446,483,330!
4017
      *value = NULL;
×
4018
      return terrno;
×
4019
    }
4020
    *value = pPage->data + pPos->offset;
446,483,330✔
4021
    releaseBufPage(pHandle->pBuf, pPage);
446,483,330✔
4022
    return TSDB_CODE_SUCCESS;
446,295,017✔
4023
  } else {
4024
    *value = NULL;
×
4025
    int32_t vLen;
4026
    int32_t code = pStore->streamStateFuncGet(pHandle->pState, &pPos->streamTupleKey, (void**)(value), &vLen);
×
4027
    if (TSDB_CODE_SUCCESS != code) {
×
4028
      return code;
×
4029
    }
4030
    return TSDB_CODE_SUCCESS;
×
4031
  }
4032
}
4033

4034
int32_t loadTupleData(SqlFunctionCtx* pCtx, const STuplePos* pPos, char** value) {
443,319,579✔
4035
  return doLoadTupleData(&pCtx->saveHandle, pPos, pCtx->pStore, value);
443,319,579✔
4036
}
4037

4038
int32_t topBotFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
123,959,228✔
4039
  int32_t code = TSDB_CODE_SUCCESS;
123,959,228✔
4040

4041
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
123,959,228✔
4042
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
123,959,228✔
4043

4044
  int16_t type = pCtx->pExpr->base.resSchema.type;
123,958,344✔
4045
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
123,958,344✔
4046

4047
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
123,958,344✔
4048
  if (NULL == pCol) {
123,608,967!
4049
    return TSDB_CODE_OUT_OF_RANGE;
×
4050
  }
4051

4052
  // todo assign the tag value and the corresponding row data
4053
  int32_t currentRow = pBlock->info.rows;
123,608,967✔
4054
  if (pEntryInfo->numOfRes <= 0) {
123,608,967✔
4055
    colDataSetNULL(pCol, currentRow);
302!
4056
    code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, currentRow);
302✔
4057
    return code;
302✔
4058
  }
4059
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
334,818,376✔
4060
    STopBotResItem* pItem = &pRes->pItems[i];
211,878,082✔
4061
    code = colDataSetVal(pCol, currentRow, (const char*)&pItem->v.i, false);
211,878,082✔
4062
    if (TSDB_CODE_SUCCESS != code) {
211,079,912!
4063
      return code;
×
4064
    }
4065
#ifdef BUF_PAGE_DEBUG
4066
    qDebug("page_finalize i:%d,item:%p,pageId:%d, offset:%d\n", i, pItem, pItem->tuplePos.pageId,
4067
           pItem->tuplePos.offset);
4068
#endif
4069
    code = setSelectivityValue(pCtx, pBlock, &pRes->pItems[i].tuplePos, currentRow);
211,079,912✔
4070
    if (TSDB_CODE_SUCCESS != code) {
211,209,711!
4071
      return code;
×
4072
    }
4073
    currentRow += 1;
211,209,711✔
4074
  }
4075

4076
  return code;
122,940,294✔
4077
}
4078

4079
int32_t addResult(SqlFunctionCtx* pCtx, STopBotResItem* pSourceItem, int16_t type, bool isTopQuery) {
×
4080
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
×
4081
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
×
4082
  STopBotResItem*      pItems = pRes->pItems;
×
4083
  int32_t              code = TSDB_CODE_SUCCESS;
×
4084

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

4112
      // save the data of this tuple by over writing the old data
4113
      replaceTupleData(&pItem->tuplePos, &pSourceItem->tuplePos);
×
4114
      code = taosheapadjust((void*)pItems, sizeof(STopBotResItem), 0, pEntryInfo->numOfRes - 1, (const void*)&type,
×
4115
                            topBotResComparFn, NULL, !isTopQuery);
×
4116
      if (TSDB_CODE_SUCCESS != code) {
×
4117
        return code;
×
4118
      }
4119
    }
4120
  }
4121
  return code;
×
4122
}
4123

4124
int32_t topCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4125
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4126
  STopBotRes*          pSBuf = getTopBotOutputInfo(pSourceCtx);
×
4127
  int16_t              type = pSBuf->type;
×
4128
  int32_t              code = TSDB_CODE_SUCCESS;
×
4129
  for (int32_t i = 0; i < pSResInfo->numOfRes; i++) {
×
4130
    code = addResult(pDestCtx, pSBuf->pItems + i, type, true);
×
4131
    if (TSDB_CODE_SUCCESS != code) {
×
4132
      return code;
×
4133
    }
4134
  }
4135
  return TSDB_CODE_SUCCESS;
×
4136
}
4137

4138
int32_t bottomCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4139
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4140
  STopBotRes*          pSBuf = getTopBotOutputInfo(pSourceCtx);
×
4141
  int16_t              type = pSBuf->type;
×
4142
  int32_t              code = TSDB_CODE_SUCCESS;
×
4143
  for (int32_t i = 0; i < pSResInfo->numOfRes; i++) {
×
4144
    code = addResult(pDestCtx, pSBuf->pItems + i, type, false);
×
4145
    if (TSDB_CODE_SUCCESS != code) {
×
4146
      return code;
×
4147
    }
4148
  }
4149
  return TSDB_CODE_SUCCESS;
×
4150
}
4151

4152
int32_t getSpreadInfoSize() { return (int32_t)sizeof(SSpreadInfo); }
3,096,445✔
4153

4154
bool getSpreadFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
159,795✔
4155
  pEnv->calcMemSize = sizeof(SSpreadInfo);
159,795✔
4156
  return true;
159,795✔
4157
}
4158

4159
int32_t spreadFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
13,694,131✔
4160
  if (pResultInfo->initialized) {
13,694,131!
4161
    return TSDB_CODE_SUCCESS;
×
4162
  }
4163
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
13,694,131!
4164
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4165
  }
4166

4167
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
13,694,136✔
4168
  SET_DOUBLE_VAL(&pInfo->min, DBL_MAX);
13,694,136✔
4169
  SET_DOUBLE_VAL(&pInfo->max, -DBL_MAX);
13,694,136✔
4170
  pInfo->hasResult = false;
13,694,136✔
4171
  return TSDB_CODE_SUCCESS;
13,694,136✔
4172
}
4173

4174
int32_t spreadFunction(SqlFunctionCtx* pCtx) {
13,672,549✔
4175
  int32_t numOfElems = 0;
13,672,549✔
4176

4177
  // Only the pre-computing information loaded and actual data does not loaded
4178
  SInputColumnInfoData* pInput = &pCtx->input;
13,672,549✔
4179
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
13,672,549✔
4180
  int32_t               type = pInput->pData[0]->info.type;
13,672,549✔
4181

4182
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
13,672,549✔
4183

4184
  if (pInput->colDataSMAIsSet) {
13,672,549!
4185
    numOfElems = pInput->numOfRows - pAgg->numOfNull;
×
4186
    if (numOfElems == 0) {
×
4187
      goto _spread_over;
×
4188
    }
4189
    double tmin = 0.0, tmax = 0.0;
×
4190
    if (IS_SIGNED_NUMERIC_TYPE(type) || IS_TIMESTAMP_TYPE(type)) {
×
4191
      tmin = (double)GET_INT64_VAL(&pAgg->min);
×
4192
      tmax = (double)GET_INT64_VAL(&pAgg->max);
×
4193
    } else if (IS_FLOAT_TYPE(type)) {
×
4194
      tmin = GET_DOUBLE_VAL(&pAgg->min);
×
4195
      tmax = GET_DOUBLE_VAL(&pAgg->max);
×
4196
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
4197
      tmin = (double)GET_UINT64_VAL(&pAgg->min);
×
4198
      tmax = (double)GET_UINT64_VAL(&pAgg->max);
×
4199
    }
4200

4201
    if (GET_DOUBLE_VAL(&pInfo->min) > tmin) {
×
4202
      SET_DOUBLE_VAL(&pInfo->min, tmin);
×
4203
    }
4204

4205
    if (GET_DOUBLE_VAL(&pInfo->max) < tmax) {
×
4206
      SET_DOUBLE_VAL(&pInfo->max, tmax);
×
4207
    }
4208

4209
  } else {  // computing based on the true data block
4210
    SColumnInfoData* pCol = pInput->pData[0];
13,672,549✔
4211

4212
    int32_t start = pInput->startRowIndex;
13,672,549✔
4213
    // check the valid data one by one
4214
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
58,264,661✔
4215
      if (colDataIsNull_f(pCol, i)) {
44,592,204✔
4216
        continue;
1,017,421✔
4217
      }
4218

4219
      char* data = colDataGetData(pCol, i);
43,574,783!
4220

4221
      double v = 0;
43,574,783✔
4222
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
43,574,783!
4223
      if (v < GET_DOUBLE_VAL(&pInfo->min)) {
43,574,691✔
4224
        SET_DOUBLE_VAL(&pInfo->min, v);
15,922,736✔
4225
      }
4226

4227
      if (v > GET_DOUBLE_VAL(&pInfo->max)) {
43,574,691✔
4228
        SET_DOUBLE_VAL(&pInfo->max, v);
19,487,131✔
4229
      }
4230

4231
      numOfElems += 1;
43,574,691✔
4232
    }
4233
  }
4234

4235
_spread_over:
13,672,457✔
4236
  // data in the check operation are all null, not output
4237
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
13,672,457✔
4238
  if (numOfElems > 0) {
13,672,457✔
4239
    pInfo->hasResult = true;
13,648,223✔
4240
  }
4241

4242
  return TSDB_CODE_SUCCESS;
13,672,457✔
4243
}
4244

4245
static void spreadTransferInfo(SSpreadInfo* pInput, SSpreadInfo* pOutput) {
3,094,479✔
4246
  pOutput->hasResult = pInput->hasResult;
3,094,479✔
4247
  if (pInput->max > pOutput->max) {
3,094,479✔
4248
    pOutput->max = pInput->max;
3,090,330✔
4249
  }
4250

4251
  if (pInput->min < pOutput->min) {
3,094,479✔
4252
    pOutput->min = pInput->min;
3,090,325✔
4253
  }
4254
}
3,094,479✔
4255

4256
int32_t spreadFunctionMerge(SqlFunctionCtx* pCtx) {
3,090,471✔
4257
  SInputColumnInfoData* pInput = &pCtx->input;
3,090,471✔
4258
  SColumnInfoData*      pCol = pInput->pData[0];
3,090,471✔
4259

4260
  if (IS_NULL_TYPE(pCol->info.type)) {
3,090,471!
4261
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
4262
    return TSDB_CODE_SUCCESS;
×
4263
  }
4264

4265
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
3,090,471!
4266
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4267
  }
4268

4269
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
3,090,471✔
4270

4271
  int32_t start = pInput->startRowIndex;
3,090,471✔
4272
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
6,184,983✔
4273
    if (colDataIsNull_s(pCol, i)) continue;
6,189,024!
4274
    char*        data = colDataGetData(pCol, i);
3,094,512!
4275
    SSpreadInfo* pInputInfo = (SSpreadInfo*)varDataVal(data);
3,094,512✔
4276
    if (pInputInfo->hasResult) {
3,094,512✔
4277
      spreadTransferInfo(pInputInfo, pInfo);
3,094,479✔
4278
    }
4279
  }
4280

4281
  if (pInfo->hasResult) {
3,090,471✔
4282
    GET_RES_INFO(pCtx)->numOfRes = 1;
3,090,438✔
4283
  }
4284

4285
  return TSDB_CODE_SUCCESS;
3,090,471✔
4286
}
4287

4288
int32_t spreadFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
10,576,509✔
4289
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
10,576,509✔
4290
  if (pInfo->hasResult == true) {
10,576,509✔
4291
    SET_DOUBLE_VAL(&pInfo->result, pInfo->max - pInfo->min);
10,552,281✔
4292
  } else {
4293
    GET_RES_INFO(pCtx)->isNullRes = 1;
24,228✔
4294
  }
4295
  return functionFinalize(pCtx, pBlock);
10,576,509✔
4296
}
4297

4298
int32_t spreadPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
3,096,447✔
4299
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
3,096,447✔
4300
  SSpreadInfo*         pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
3,096,447✔
4301
  int32_t              resultBytes = getSpreadInfoSize();
3,096,447✔
4302
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
3,096,446!
4303

4304
  if (NULL == res) {
3,096,447!
4305
    return terrno;
×
4306
  }
4307
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
3,096,447✔
4308
  varDataSetLen(res, resultBytes);
3,096,447✔
4309

4310
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
3,096,447✔
4311
  int32_t          code = TSDB_CODE_SUCCESS;
3,096,447✔
4312
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
3,096,447✔
4313
  if (NULL == pCol) {
3,096,446!
4314
    code = terrno;
×
4315
    goto _exit;
×
4316
  }
4317

4318
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
3,096,446✔
4319
  if (TSDB_CODE_SUCCESS != code) {
3,096,446!
4320
    goto _exit;
×
4321
  }
4322

4323
_exit:
3,096,446✔
4324
  taosMemoryFree(res);
3,096,446!
4325
  return code;
3,096,446✔
4326
}
4327

4328
int32_t spreadCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4329
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
4330
  SSpreadInfo*         pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
4331

4332
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4333
  SSpreadInfo*         pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
4334
  spreadTransferInfo(pSBuf, pDBuf);
×
4335
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
4336
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
4337
  return TSDB_CODE_SUCCESS;
×
4338
}
4339

4340
int32_t getElapsedInfoSize() { return (int32_t)sizeof(SElapsedInfo); }
×
4341

4342
bool getElapsedFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
256,791✔
4343
  pEnv->calcMemSize = sizeof(SElapsedInfo);
256,791✔
4344
  return true;
256,791✔
4345
}
4346

4347
int32_t elapsedFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
33,997,701✔
4348
  if (pResultInfo->initialized) {
33,997,701!
4349
    return TSDB_CODE_SUCCESS;
×
4350
  }
4351
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
33,997,701!
4352
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4353
  }
4354

4355
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
33,997,701✔
4356
  pInfo->result = 0;
33,997,701✔
4357
  pInfo->min = TSKEY_MAX;
33,997,701✔
4358
  pInfo->max = 0;
33,997,701✔
4359

4360
  if (pCtx->numOfParams > 1) {
33,997,701✔
4361
    pInfo->timeUnit = pCtx->param[1].param.i;
26,671,386✔
4362
  } else {
4363
    pInfo->timeUnit = 1;
7,326,315✔
4364
  }
4365

4366
  return TSDB_CODE_SUCCESS;
33,997,701✔
4367
}
4368

4369
int32_t elapsedFunction(SqlFunctionCtx* pCtx) {
34,040,862✔
4370
  int32_t numOfElems = 0;
34,040,862✔
4371

4372
  // Only the pre-computing information loaded and actual data does not loaded
4373
  SInputColumnInfoData* pInput = &pCtx->input;
34,040,862✔
4374
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
34,040,862✔
4375

4376
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
34,040,862✔
4377

4378
  numOfElems = pInput->numOfRows;  // since this is the primary timestamp, no need to exclude NULL values
34,040,862✔
4379
  if (numOfElems == 0) {
34,040,862✔
4380
    // for stream
4381
    if (pCtx->end.key != INT64_MIN) {
3,588!
4382
      pInfo->max = pCtx->end.key + 1;
×
4383
    }
4384
    goto _elapsed_over;
3,588✔
4385
  }
4386

4387
  if (pInput->colDataSMAIsSet) {
34,037,274!
4388
    if (pInfo->min == TSKEY_MAX) {
×
4389
      pInfo->min = GET_INT64_VAL(&pAgg->min);
×
4390
      pInfo->max = GET_INT64_VAL(&pAgg->max);
×
4391
    } else {
4392
      if (pCtx->order == TSDB_ORDER_ASC) {
×
4393
        pInfo->max = GET_INT64_VAL(&pAgg->max);
×
4394
      } else {
4395
        pInfo->min = GET_INT64_VAL(&pAgg->min);
×
4396
      }
4397
    }
4398
  } else {  // computing based on the true data block
4399
    if (0 == pInput->numOfRows) {
34,037,274!
4400
      if (pCtx->order == TSDB_ORDER_DESC) {
×
4401
        if (pCtx->end.key != INT64_MIN) {
×
4402
          pInfo->min = pCtx->end.key;
×
4403
        }
4404
      } else {
4405
        if (pCtx->end.key != INT64_MIN) {
×
4406
          pInfo->max = pCtx->end.key + 1;
×
4407
        }
4408
      }
4409
      goto _elapsed_over;
×
4410
    }
4411

4412
    SColumnInfoData* pCol = pInput->pData[0];
34,037,274✔
4413

4414
    int32_t start = pInput->startRowIndex;
34,037,274✔
4415
    TSKEY*  ptsList = (int64_t*)colDataGetData(pCol, 0);
34,037,274!
4416
    if (pCtx->order == TSDB_ORDER_DESC) {
34,037,274✔
4417
      if (pCtx->start.key == INT64_MIN) {
1,738!
4418
        pInfo->max = (pInfo->max < ptsList[start]) ? ptsList[start] : pInfo->max;
1,738✔
4419
      } else {
4420
        pInfo->max = pCtx->start.key + 1;
×
4421
      }
4422

4423
      if (pCtx->end.key == INT64_MIN) {
1,738!
4424
        pInfo->min =
1,738✔
4425
            (pInfo->min > ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->min;
1,738✔
4426
      } else {
4427
        pInfo->min = pCtx->end.key;
×
4428
      }
4429
    } else {
4430
      if (pCtx->start.key == INT64_MIN) {
34,035,536✔
4431
        pInfo->min = (pInfo->min > ptsList[start]) ? ptsList[start] : pInfo->min;
19,812,126✔
4432
      } else {
4433
        pInfo->min = pCtx->start.key;
14,223,410✔
4434
      }
4435

4436
      if (pCtx->end.key == INT64_MIN) {
34,035,536✔
4437
        pInfo->max =
19,262,254✔
4438
            (pInfo->max < ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->max;
19,262,254✔
4439
      } else {
4440
        pInfo->max = pCtx->end.key + 1;
14,773,282✔
4441
      }
4442
    }
4443
  }
4444

4445
_elapsed_over:
34,040,862✔
4446
  // data in the check operation are all null, not output
4447
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
34,040,862✔
4448

4449
  return TSDB_CODE_SUCCESS;
34,040,862✔
4450
}
4451

4452
static void elapsedTransferInfo(SElapsedInfo* pInput, SElapsedInfo* pOutput) {
×
4453
  pOutput->timeUnit = pInput->timeUnit;
×
4454
  if (pOutput->min > pInput->min) {
×
4455
    pOutput->min = pInput->min;
×
4456
  }
4457

4458
  if (pOutput->max < pInput->max) {
×
4459
    pOutput->max = pInput->max;
×
4460
  }
4461
}
×
4462

4463
int32_t elapsedFunctionMerge(SqlFunctionCtx* pCtx) {
×
4464
  SInputColumnInfoData* pInput = &pCtx->input;
×
4465
  SColumnInfoData*      pCol = pInput->pData[0];
×
4466
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
×
4467
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4468
  }
4469

4470
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
4471

4472
  int32_t start = pInput->startRowIndex;
×
4473

4474
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
×
4475
    char*         data = colDataGetData(pCol, i);
×
4476
    SElapsedInfo* pInputInfo = (SElapsedInfo*)varDataVal(data);
×
4477
    elapsedTransferInfo(pInputInfo, pInfo);
×
4478
  }
4479

4480
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
×
4481
  return TSDB_CODE_SUCCESS;
×
4482
}
4483

4484
int32_t elapsedFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
33,945,298✔
4485
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
33,945,298✔
4486
  double        result = (double)pInfo->max - (double)pInfo->min;
33,945,298✔
4487
  result = (result >= 0) ? result : -result;
33,945,298✔
4488
  pInfo->result = result / pInfo->timeUnit;
33,945,298✔
4489
  return functionFinalize(pCtx, pBlock);
33,945,298✔
4490
}
4491

4492
int32_t elapsedPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
4493
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
×
4494
  SElapsedInfo*        pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
4495
  int32_t              resultBytes = getElapsedInfoSize();
×
4496
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
×
4497

4498
  if (NULL == res) {
×
4499
    return terrno;
×
4500
  }
4501
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
×
4502
  varDataSetLen(res, resultBytes);
×
4503

4504
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
×
4505
  int32_t          code = TSDB_CODE_SUCCESS;
×
4506
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
×
4507
  if (NULL == pCol) {
×
4508
    code = terrno;
×
4509
    goto _exit;
×
4510
  }
4511

4512
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
×
4513
  if (TSDB_CODE_SUCCESS != code) {
×
4514
    goto _exit;
×
4515
  }
4516
_exit:
×
4517
  taosMemoryFree(res);
×
4518
  return code;
×
4519
}
4520

4521
int32_t elapsedCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4522
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
4523
  SElapsedInfo*        pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
4524

4525
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4526
  SElapsedInfo*        pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
4527

4528
  elapsedTransferInfo(pSBuf, pDBuf);
×
4529
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
4530
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
4531
  return TSDB_CODE_SUCCESS;
×
4532
}
4533

4534
int32_t getHistogramInfoSize() {
5,060,964✔
4535
  return (int32_t)sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
5,060,964✔
4536
}
4537

4538
bool getHistogramFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
215,950✔
4539
  pEnv->calcMemSize = sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
215,950✔
4540
  return true;
215,950✔
4541
}
4542

4543
static int8_t getHistogramBinType(char* binTypeStr) {
18,639,109✔
4544
  int8_t binType;
4545
  if (strcasecmp(binTypeStr, "user_input") == 0) {
18,639,109✔
4546
    binType = USER_INPUT_BIN;
2,985✔
4547
  } else if (strcasecmp(binTypeStr, "linear_bin") == 0) {
18,636,124✔
4548
    binType = LINEAR_BIN;
2,025✔
4549
  } else if (strcasecmp(binTypeStr, "log_bin") == 0) {
18,634,099!
4550
    binType = LOG_BIN;
18,634,566✔
4551
  } else {
4552
    binType = UNKNOWN_BIN;
×
4553
  }
4554

4555
  return binType;
18,639,109✔
4556
}
4557

4558
static int32_t getHistogramBinDesc(SHistoFuncInfo* pInfo, char* binDescStr, int8_t binType, bool normalized) {
18,639,107✔
4559
  cJSON*  binDesc = cJSON_Parse(binDescStr);
18,639,107✔
4560
  int32_t numOfBins;
4561
  double* intervals;
4562
  if (cJSON_IsObject(binDesc)) { /* linaer/log bins */
18,640,781✔
4563
    int32_t numOfParams = cJSON_GetArraySize(binDesc);
18,637,844✔
4564
    int32_t startIndex;
4565
    if (numOfParams != 4) {
18,637,709!
4566
      cJSON_Delete(binDesc);
×
4567
      return TSDB_CODE_FAILED;
×
4568
    }
4569

4570
    cJSON* start = cJSON_GetObjectItem(binDesc, "start");
18,637,709✔
4571
    cJSON* factor = cJSON_GetObjectItem(binDesc, "factor");
18,637,436✔
4572
    cJSON* width = cJSON_GetObjectItem(binDesc, "width");
18,637,389✔
4573
    cJSON* count = cJSON_GetObjectItem(binDesc, "count");
18,637,566✔
4574
    cJSON* infinity = cJSON_GetObjectItem(binDesc, "infinity");
18,637,720✔
4575

4576
    if (!cJSON_IsNumber(start) || !cJSON_IsNumber(count) || !cJSON_IsBool(infinity)) {
18,637,660!
4577
      cJSON_Delete(binDesc);
×
4578
      return TSDB_CODE_FAILED;
×
4579
    }
4580

4581
    if (count->valueint <= 0 || count->valueint > 1000) {  // limit count to 1000
18,637,696!
4582
      cJSON_Delete(binDesc);
×
4583
      return TSDB_CODE_FAILED;
×
4584
    }
4585

4586
    if (isinf(start->valuedouble) || (width != NULL && isinf(width->valuedouble)) ||
18,637,737!
4587
        (factor != NULL && isinf(factor->valuedouble)) || (count != NULL && isinf(count->valuedouble))) {
18,637,737!
4588
      cJSON_Delete(binDesc);
×
4589
      return TSDB_CODE_FAILED;
×
4590
    }
4591

4592
    int32_t counter = (int32_t)count->valueint;
18,637,737✔
4593
    if (infinity->valueint == false) {
18,637,737✔
4594
      startIndex = 0;
9,388,678✔
4595
      numOfBins = counter + 1;
9,388,678✔
4596
    } else {
4597
      startIndex = 1;
9,249,059✔
4598
      numOfBins = counter + 3;
9,249,059✔
4599
    }
4600

4601
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
18,637,737!
4602
    if (NULL == intervals) {
18,636,662!
4603
      cJSON_Delete(binDesc);
×
4604
      qError("histogram function out of memory");
×
4605
      return terrno;
×
4606
    }
4607
    if (cJSON_IsNumber(width) && factor == NULL && binType == LINEAR_BIN) {
18,636,662!
4608
      // linear bin process
4609
      if (width->valuedouble == 0) {
2,025!
4610
        taosMemoryFree(intervals);
×
4611
        cJSON_Delete(binDesc);
×
4612
        return TSDB_CODE_FAILED;
×
4613
      }
4614
      for (int i = 0; i < counter + 1; ++i) {
22,927✔
4615
        intervals[startIndex] = start->valuedouble + i * width->valuedouble;
20,902✔
4616
        if (isinf(intervals[startIndex])) {
20,902!
4617
          taosMemoryFree(intervals);
×
4618
          cJSON_Delete(binDesc);
×
4619
          return TSDB_CODE_FAILED;
×
4620
        }
4621
        startIndex++;
20,902✔
4622
      }
4623
    } else if (cJSON_IsNumber(factor) && width == NULL && binType == LOG_BIN) {
18,634,564!
4624
      // log bin process
4625
      if (start->valuedouble == 0) {
18,634,591!
4626
        taosMemoryFree(intervals);
×
4627
        cJSON_Delete(binDesc);
×
4628
        return TSDB_CODE_FAILED;
×
4629
      }
4630
      if (factor->valuedouble < 0 || factor->valuedouble == 0 || factor->valuedouble == 1) {
18,634,591!
4631
        taosMemoryFree(intervals);
×
4632
        cJSON_Delete(binDesc);
×
4633
        return TSDB_CODE_FAILED;
×
4634
      }
4635
      for (int i = 0; i < counter + 1; ++i) {
130,431,693✔
4636
        intervals[startIndex] = start->valuedouble * pow(factor->valuedouble, i * 1.0);
111,797,015✔
4637
        if (isinf(intervals[startIndex])) {
111,797,015!
4638
          taosMemoryFree(intervals);
×
4639
          cJSON_Delete(binDesc);
×
4640
          return TSDB_CODE_FAILED;
×
4641
        }
4642
        startIndex++;
111,797,015✔
4643
      }
4644
    } else {
4645
      taosMemoryFree(intervals);
×
4646
      cJSON_Delete(binDesc);
×
4647
      return TSDB_CODE_FAILED;
×
4648
    }
4649

4650
    if (infinity->valueint == true) {
18,636,703✔
4651
      intervals[0] = -INFINITY;
9,248,467✔
4652
      intervals[numOfBins - 1] = INFINITY;
9,248,467✔
4653
      // in case of desc bin orders, -inf/inf should be swapped
4654
      if (numOfBins < 4) {
9,248,467!
4655
        return TSDB_CODE_FAILED;
×
4656
      }
4657
      if (intervals[1] > intervals[numOfBins - 2]) {
9,248,467✔
4658
        TSWAP(intervals[0], intervals[numOfBins - 1]);
9,247,801✔
4659
      }
4660
    }
4661
  } else if (cJSON_IsArray(binDesc)) { /* user input bins */
2,986!
4662
    if (binType != USER_INPUT_BIN) {
2,986!
4663
      cJSON_Delete(binDesc);
×
4664
      return TSDB_CODE_FAILED;
×
4665
    }
4666
    numOfBins = cJSON_GetArraySize(binDesc);
2,986✔
4667
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
2,986!
4668
    if (NULL == intervals) {
2,986!
4669
      cJSON_Delete(binDesc);
×
4670
      qError("histogram function out of memory");
×
4671
      return terrno;
×
4672
    }
4673
    cJSON* bin = binDesc->child;
2,986✔
4674
    if (bin == NULL) {
2,986!
4675
      taosMemoryFree(intervals);
×
4676
      cJSON_Delete(binDesc);
×
4677
      return TSDB_CODE_FAILED;
×
4678
    }
4679
    int i = 0;
2,986✔
4680
    while (bin) {
12,971✔
4681
      intervals[i] = bin->valuedouble;
9,984✔
4682
      if (!cJSON_IsNumber(bin)) {
9,984!
4683
        taosMemoryFree(intervals);
×
4684
        cJSON_Delete(binDesc);
×
4685
        return TSDB_CODE_FAILED;
×
4686
      }
4687
      if (i != 0 && intervals[i] <= intervals[i - 1]) {
9,985!
4688
        taosMemoryFree(intervals);
×
4689
        cJSON_Delete(binDesc);
×
4690
        return TSDB_CODE_FAILED;
×
4691
      }
4692
      bin = bin->next;
9,985✔
4693
      i++;
9,985✔
4694
    }
4695
  } else {
4696
    cJSON_Delete(binDesc);
×
4697
    return TSDB_CODE_FAILED;
×
4698
  }
4699

4700
  pInfo->numOfBins = numOfBins - 1;
18,639,690✔
4701
  pInfo->normalized = normalized;
18,639,690✔
4702
  for (int32_t i = 0; i < pInfo->numOfBins; ++i) {
130,330,725✔
4703
    pInfo->bins[i].lower = intervals[i] < intervals[i + 1] ? intervals[i] : intervals[i + 1];
111,691,035✔
4704
    pInfo->bins[i].upper = intervals[i + 1] > intervals[i] ? intervals[i + 1] : intervals[i];
111,691,035✔
4705
    pInfo->bins[i].count = 0;
111,691,035✔
4706
  }
4707

4708
  taosMemoryFree(intervals);
18,639,690!
4709
  cJSON_Delete(binDesc);
18,639,216✔
4710

4711
  return TSDB_CODE_SUCCESS;
18,640,255✔
4712
}
4713

4714
int32_t histogramFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
18,639,477✔
4715
  if (pResultInfo->initialized) {
18,639,477!
4716
    return TSDB_CODE_SUCCESS;
×
4717
  }
4718
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
18,639,477!
4719
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4720
  }
4721

4722
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
18,639,812✔
4723
  pInfo->numOfBins = 0;
18,639,812✔
4724
  pInfo->totalCount = 0;
18,639,812✔
4725
  pInfo->normalized = 0;
18,639,812✔
4726

4727
  char* binTypeStr = taosStrndup(varDataVal(pCtx->param[1].param.pz), varDataLen(pCtx->param[1].param.pz));
18,639,812!
4728
  if (binTypeStr == NULL) {
18,639,187!
4729
    return terrno;
×
4730
  }
4731
  int8_t binType = getHistogramBinType(binTypeStr);
18,639,187✔
4732
  taosMemoryFree(binTypeStr);
18,639,487!
4733

4734
  if (binType == UNKNOWN_BIN) {
18,638,398!
4735
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
4736
  }
4737
  char* binDesc = taosStrndup(varDataVal(pCtx->param[2].param.pz), varDataLen(pCtx->param[2].param.pz));
18,638,398!
4738
  if (binDesc == NULL) {
18,638,869!
4739
    return terrno;
×
4740
  }
4741
  int64_t normalized = pCtx->param[3].param.i;
18,638,869✔
4742
  if (normalized != 0 && normalized != 1) {
18,638,869!
4743
    taosMemoryFree(binDesc);
×
4744
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
4745
  }
4746
  int32_t code = getHistogramBinDesc(pInfo, binDesc, binType, (bool)normalized);
18,638,869✔
4747
  if (TSDB_CODE_SUCCESS != code) {
18,640,113!
4748
    taosMemoryFree(binDesc);
×
4749
    return code;
×
4750
  }
4751
  taosMemoryFree(binDesc);
18,640,113!
4752

4753
  return TSDB_CODE_SUCCESS;
18,639,808✔
4754
}
4755

4756
static int32_t histogramFunctionImpl(SqlFunctionCtx* pCtx, bool isPartial) {
18,660,079✔
4757
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
18,660,079✔
4758

4759
  SInputColumnInfoData* pInput = &pCtx->input;
18,660,079✔
4760
  SColumnInfoData*      pCol = pInput->pData[0];
18,660,079✔
4761

4762
  int32_t type = pInput->pData[0]->info.type;
18,660,079✔
4763

4764
  int32_t start = pInput->startRowIndex;
18,660,079✔
4765
  int32_t numOfRows = pInput->numOfRows;
18,660,079✔
4766

4767
  int32_t numOfElems = 0;
18,660,079✔
4768
  for (int32_t i = start; i < numOfRows + start; ++i) {
60,721,970✔
4769
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
42,062,197!
4770
      continue;
495,913✔
4771
    }
4772

4773
    numOfElems++;
41,566,284✔
4774

4775
    char*  data = colDataGetData(pCol, i);
41,566,284!
4776
    double v;
4777
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
41,566,284!
4778

4779
    for (int32_t k = 0; k < pInfo->numOfBins; ++k) {
137,340,040✔
4780
      if (v > pInfo->bins[k].lower && v <= pInfo->bins[k].upper) {
120,376,574✔
4781
        pInfo->bins[k].count++;
24,602,512✔
4782
        pInfo->totalCount++;
24,602,512✔
4783
        break;
24,602,512✔
4784
      }
4785
    }
4786
  }
4787

4788
  if (!isPartial) {
18,659,773✔
4789
    GET_RES_INFO(pCtx)->numOfRes = pInfo->numOfBins;
13,580,443✔
4790
  } else {
4791
    GET_RES_INFO(pCtx)->numOfRes = 1;
5,079,330✔
4792
  }
4793
  return TSDB_CODE_SUCCESS;
18,659,773✔
4794
}
4795

4796
int32_t histogramFunction(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, false); }
13,579,939✔
4797

4798
int32_t histogramFunctionPartial(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, true); }
5,080,735✔
4799

4800
static void histogramTransferInfo(SHistoFuncInfo* pInput, SHistoFuncInfo* pOutput) {
5,006,037✔
4801
  pOutput->normalized = pInput->normalized;
5,006,037✔
4802
  pOutput->numOfBins = pInput->numOfBins;
5,006,037✔
4803
  pOutput->totalCount += pInput->totalCount;
5,006,037✔
4804
  for (int32_t k = 0; k < pOutput->numOfBins; ++k) {
34,895,061✔
4805
    pOutput->bins[k].lower = pInput->bins[k].lower;
29,889,024✔
4806
    pOutput->bins[k].upper = pInput->bins[k].upper;
29,889,024✔
4807
    pOutput->bins[k].count += pInput->bins[k].count;
29,889,024✔
4808
  }
4809
}
5,006,037✔
4810

4811
int32_t histogramFunctionMerge(SqlFunctionCtx* pCtx) {
5,006,037✔
4812
  SInputColumnInfoData* pInput = &pCtx->input;
5,006,037✔
4813
  SColumnInfoData*      pCol = pInput->pData[0];
5,006,037✔
4814
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
5,006,037!
4815
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4816
  }
4817

4818
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
5,006,037✔
4819

4820
  int32_t start = pInput->startRowIndex;
5,006,037✔
4821

4822
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
10,012,074✔
4823
    char*           data = colDataGetData(pCol, i);
5,006,037!
4824
    SHistoFuncInfo* pInputInfo = (SHistoFuncInfo*)varDataVal(data);
5,006,037✔
4825
    histogramTransferInfo(pInputInfo, pInfo);
5,006,037✔
4826
  }
4827

4828
  SET_VAL(GET_RES_INFO(pCtx), pInfo->numOfBins, pInfo->numOfBins);
5,006,037!
4829
  return TSDB_CODE_SUCCESS;
5,006,037✔
4830
}
4831

4832
int32_t histogramFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
18,472,467✔
4833
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
18,472,467✔
4834
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
18,472,467✔
4835
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
18,472,467✔
4836
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
18,472,467✔
4837
  int32_t              code = TSDB_CODE_SUCCESS;
18,465,572✔
4838

4839
  int32_t currentRow = pBlock->info.rows;
18,465,572✔
4840
  if (NULL == pCol) {
18,465,572!
4841
    return TSDB_CODE_OUT_OF_RANGE;
×
4842
  }
4843

4844
  if (pInfo->normalized) {
18,465,572✔
4845
    for (int32_t k = 0; k < pResInfo->numOfRes; ++k) {
108,722,368✔
4846
      if (pInfo->totalCount != 0) {
93,642,134✔
4847
        pInfo->bins[k].percentage = pInfo->bins[k].count / (double)pInfo->totalCount;
63,878,876✔
4848
      } else {
4849
        pInfo->bins[k].percentage = 0;
29,763,258✔
4850
      }
4851
    }
4852
  }
4853

4854
  for (int32_t i = 0; i < pResInfo->numOfRes; ++i) {
128,526,460✔
4855
    int32_t len;
4856
    char    buf[512] = {0};
110,606,450✔
4857
    if (!pInfo->normalized) {
110,606,450✔
4858
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
16,940,413✔
4859
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%" PRId64 "}", pInfo->bins[i].lower,
4860
                      pInfo->bins[i].upper, pInfo->bins[i].count);
4861
    } else {
4862
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
93,666,037✔
4863
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%lf}", pInfo->bins[i].lower, pInfo->bins[i].upper,
4864
                      pInfo->bins[i].percentage);
4865
    }
4866
    varDataSetLen(buf, len);
110,628,312✔
4867
    code = colDataSetVal(pCol, currentRow, buf, false);
110,628,312✔
4868
    if (TSDB_CODE_SUCCESS != code) {
110,060,888!
4869
      return code;
×
4870
    }
4871
    currentRow++;
110,060,888✔
4872
  }
4873

4874
  return code;
17,920,010✔
4875
}
4876

4877
int32_t histogramPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
5,060,964✔
4878
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5,060,964✔
4879
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
5,060,964✔
4880
  int32_t              resultBytes = getHistogramInfoSize();
5,060,964✔
4881
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
5,060,964!
4882

4883
  if (NULL == res) {
5,060,965!
4884
    return terrno;
×
4885
  }
4886
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
5,060,965✔
4887
  varDataSetLen(res, resultBytes);
5,060,965✔
4888

4889
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
5,060,965✔
4890
  int32_t          code = TSDB_CODE_SUCCESS;
5,060,965✔
4891
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
5,060,965✔
4892
  if (NULL == pCol) {
5,060,967!
4893
    code = terrno;
×
4894
    goto _exit;
×
4895
  }
4896
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
5,060,967✔
4897

4898
_exit:
5,060,965✔
4899
  taosMemoryFree(res);
5,060,965!
4900
  return code;
5,060,967✔
4901
}
4902

4903
int32_t histogramCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4904
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
4905
  SHistoFuncInfo*      pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
4906

4907
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4908
  SHistoFuncInfo*      pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
4909

4910
  histogramTransferInfo(pSBuf, pDBuf);
×
4911
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
4912
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
4913
  return TSDB_CODE_SUCCESS;
×
4914
}
4915

4916
int32_t getHLLInfoSize() { return (int32_t)sizeof(SHLLInfo); }
3,166✔
4917

4918
bool getHLLFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
42,710✔
4919
  pEnv->calcMemSize = sizeof(SHLLInfo);
42,710✔
4920
  return true;
42,710✔
4921
}
4922

4923
static uint8_t hllCountNum(void* data, int32_t bytes, int32_t* buk) {
3,101,398✔
4924
  uint64_t hash = MurmurHash3_64(data, bytes);
3,101,398✔
4925
  int32_t  index = hash & HLL_BUCKET_MASK;
3,100,615✔
4926
  hash >>= HLL_BUCKET_BITS;
3,100,615✔
4927
  hash |= ((uint64_t)1 << HLL_DATA_BITS);
3,100,615✔
4928
  uint64_t bit = 1;
3,100,615✔
4929
  uint8_t  count = 1;
3,100,615✔
4930
  while ((hash & bit) == 0) {
5,476,900✔
4931
    count++;
2,376,285✔
4932
    bit <<= 1;
2,376,285✔
4933
  }
4934
  *buk = index;
3,100,615✔
4935
  return count;
3,100,615✔
4936
}
4937

4938
static void hllBucketHisto(uint8_t* buckets, int32_t* bucketHisto) {
110,784✔
4939
  uint64_t* word = (uint64_t*)buckets;
110,784✔
4940
  uint8_t*  bytes;
4941

4942
  for (int32_t j = 0; j < HLL_BUCKETS >> 3; j++) {
221,453,947✔
4943
    if (*word == 0) {
221,343,163✔
4944
      bucketHisto[0] += 8;
220,869,240✔
4945
    } else {
4946
      bytes = (uint8_t*)word;
473,923✔
4947
      bucketHisto[bytes[0]]++;
473,923✔
4948
      bucketHisto[bytes[1]]++;
473,923✔
4949
      bucketHisto[bytes[2]]++;
473,923✔
4950
      bucketHisto[bytes[3]]++;
473,923✔
4951
      bucketHisto[bytes[4]]++;
473,923✔
4952
      bucketHisto[bytes[5]]++;
473,923✔
4953
      bucketHisto[bytes[6]]++;
473,923✔
4954
      bucketHisto[bytes[7]]++;
473,923✔
4955
    }
4956
    word++;
221,343,163✔
4957
  }
4958
}
110,784✔
4959
static double hllTau(double x) {
110,779✔
4960
  if (x == 0. || x == 1.) return 0.;
110,779!
4961
  double zPrime;
4962
  double y = 1.0;
×
4963
  double z = 1 - x;
×
4964
  do {
4965
    x = sqrt(x);
×
4966
    zPrime = z;
×
4967
    y *= 0.5;
×
4968
    z -= pow(1 - x, 2) * y;
×
4969
  } while (zPrime != z);
×
4970
  return z / 3;
×
4971
}
4972

4973
static double hllSigma(double x) {
110,790✔
4974
  if (x == 1.0) return INFINITY;
110,790✔
4975
  double zPrime;
4976
  double y = 1;
90,591✔
4977
  double z = x;
90,591✔
4978
  do {
4979
    x *= x;
1,766,037✔
4980
    zPrime = z;
1,766,037✔
4981
    z += x * y;
1,766,037✔
4982
    y += y;
1,766,037✔
4983
  } while (zPrime != z);
1,766,037✔
4984
  return z;
90,591✔
4985
}
4986

4987
// estimate the cardinality, the algorithm refer this paper: "New cardinality estimation algorithms for HyperLogLog
4988
// sketches"
4989
static uint64_t hllCountCnt(uint8_t* buckets) {
110,761✔
4990
  double  m = HLL_BUCKETS;
110,761✔
4991
  int32_t buckethisto[64] = {0};
110,761✔
4992
  hllBucketHisto(buckets, buckethisto);
110,761✔
4993

4994
  double z = m * hllTau((m - buckethisto[HLL_DATA_BITS + 1]) / (double)m);
110,779✔
4995
  for (int j = HLL_DATA_BITS; j >= 1; --j) {
5,647,607✔
4996
    z += buckethisto[j];
5,536,818✔
4997
    z *= 0.5;
5,536,818✔
4998
  }
4999

5000
  z += m * hllSigma(buckethisto[0] / (double)m);
110,789✔
5001
  double E = (double)llroundl(HLL_ALPHA_INF * m * m / z);
110,793✔
5002

5003
  return (uint64_t)E;
110,793✔
5004
}
5005

5006
int32_t hllFunction(SqlFunctionCtx* pCtx) {
117,862✔
5007
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
117,862✔
5008

5009
  SInputColumnInfoData* pInput = &pCtx->input;
117,862✔
5010
  SColumnInfoData*      pCol = pInput->pData[0];
117,862✔
5011

5012
  int32_t type = pCol->info.type;
117,862✔
5013
  int32_t bytes = pCol->info.bytes;
117,862✔
5014

5015
  int32_t start = pInput->startRowIndex;
117,862✔
5016
  int32_t numOfRows = pInput->numOfRows;
117,862✔
5017

5018
  int32_t numOfElems = 0;
117,862✔
5019
  if (IS_NULL_TYPE(type)) {
117,862✔
5020
    goto _hll_over;
1,238✔
5021
  }
5022

5023
  for (int32_t i = start; i < numOfRows + start; ++i) {
4,233,309✔
5024
    if (pCol->hasNull && colDataIsNull_s(pCol, i)) {
5,830,250!
5025
      continue;
1,015,520✔
5026
    }
5027

5028
    numOfElems++;
3,101,293✔
5029

5030
    char* data = colDataGetData(pCol, i);
3,101,293!
5031
    if (IS_VAR_DATA_TYPE(type)) {
3,101,293!
5032
      if (IS_STR_DATA_BLOB(type)) {
676,794!
5033
        bytes = blobDataLen(data);
×
5034
        data = blobDataVal(data);
×
5035
      } else {
5036
        bytes = varDataLen(data);
676,794✔
5037
        data = varDataVal(data);
676,794✔
5038
      }
5039
    }
5040

5041
    int32_t index = 0;
3,101,293✔
5042
    uint8_t count = hllCountNum(data, bytes, &index);
3,101,293✔
5043
    uint8_t oldcount = pInfo->buckets[index];
3,101,165✔
5044
    if (count > oldcount) {
3,101,165✔
5045
      pInfo->buckets[index] = count;
524,249✔
5046
    }
5047
  }
5048

5049
_hll_over:
116,496✔
5050
  pInfo->totalCount += numOfElems;
117,734✔
5051

5052
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
117,734✔
5053
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
948✔
5054
  } else {
5055
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
116,786✔
5056
  }
5057

5058
  return TSDB_CODE_SUCCESS;
117,734✔
5059
}
5060

5061
static void hllTransferInfo(SHLLInfo* pInput, SHLLInfo* pOutput) {
2,462✔
5062
  for (int32_t k = 0; k < HLL_BUCKETS; ++k) {
39,583,206✔
5063
    if (pOutput->buckets[k] < pInput->buckets[k]) {
39,580,744✔
5064
      pOutput->buckets[k] = pInput->buckets[k];
36,831✔
5065
    }
5066
  }
5067
  pOutput->totalCount += pInput->totalCount;
2,462✔
5068
}
2,462✔
5069

5070
int32_t hllFunctionMerge(SqlFunctionCtx* pCtx) {
2,462✔
5071
  SInputColumnInfoData* pInput = &pCtx->input;
2,462✔
5072
  SColumnInfoData*      pCol = pInput->pData[0];
2,462✔
5073

5074
  if (IS_NULL_TYPE(pCol->info.type)) {
2,462!
5075
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
5076
    return TSDB_CODE_SUCCESS;
×
5077
  }
5078

5079
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
2,462!
5080
    return TSDB_CODE_SUCCESS;
×
5081
  }
5082

5083
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,462✔
5084

5085
  int32_t start = pInput->startRowIndex;
2,462✔
5086

5087
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
4,924✔
5088
    if (colDataIsNull_s(pCol, i)) continue;
4,924!
5089
    char*     data = colDataGetData(pCol, i);
2,462!
5090
    SHLLInfo* pInputInfo = (SHLLInfo*)varDataVal(data);
2,462✔
5091
    hllTransferInfo(pInputInfo, pInfo);
2,462✔
5092
  }
5093

5094
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
2,462✔
5095
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
3✔
5096
  } else {
5097
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
2,459✔
5098
  }
5099

5100
  return TSDB_CODE_SUCCESS;
2,462✔
5101
}
5102

5103
int32_t hllFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
110,762✔
5104
  SResultRowEntryInfo* pInfo = GET_RES_INFO(pCtx);
110,762✔
5105

5106
  SHLLInfo* pHllInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
110,762✔
5107
  pHllInfo->result = hllCountCnt(pHllInfo->buckets);
110,762✔
5108
  if (tsCountAlwaysReturnValue && pHllInfo->result == 0) {
110,797✔
5109
    pInfo->numOfRes = 1;
19,283✔
5110
  }
5111

5112
  return functionFinalize(pCtx, pBlock);
110,797✔
5113
}
5114

5115
int32_t hllPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
3,166✔
5116
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
3,166✔
5117
  SHLLInfo*            pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
3,166✔
5118
  int32_t              resultBytes = getHLLInfoSize();
3,166✔
5119
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
3,166!
5120

5121
  if (NULL == res) {
3,167!
5122
    return terrno;
×
5123
  }
5124
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
3,167✔
5125
  varDataSetLen(res, resultBytes);
3,167✔
5126

5127
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
3,167✔
5128
  int32_t          code = TSDB_CODE_SUCCESS;
3,167✔
5129
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
3,167✔
5130
  if (NULL == pCol) {
3,167!
5131
    code = terrno;
×
5132
    goto _exit;
×
5133
  }
5134

5135
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
3,167✔
5136

5137
_exit:
3,166✔
5138
  taosMemoryFree(res);
3,166!
5139
  return code;
3,166✔
5140
}
5141

5142
int32_t hllCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
5143
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
5144
  SHLLInfo*            pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
5145

5146
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
5147
  SHLLInfo*            pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
5148

5149
  hllTransferInfo(pSBuf, pDBuf);
×
5150
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
5151
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
5152
  return TSDB_CODE_SUCCESS;
×
5153
}
5154

5155
bool getStateFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
43,921✔
5156
  pEnv->calcMemSize = sizeof(SStateInfo);
43,921✔
5157
  return true;
43,921✔
5158
}
5159

5160
static int8_t getStateOpType(char* opStr) {
198,977✔
5161
  int8_t opType;
5162
  if (strncasecmp(opStr, "LT", 2) == 0) {
198,977✔
5163
    opType = STATE_OPER_LT;
45,039✔
5164
  } else if (strncasecmp(opStr, "GT", 2) == 0) {
153,938✔
5165
    opType = STATE_OPER_GT;
7,584✔
5166
  } else if (strncasecmp(opStr, "LE", 2) == 0) {
146,354✔
5167
    opType = STATE_OPER_LE;
992✔
5168
  } else if (strncasecmp(opStr, "GE", 2) == 0) {
145,362✔
5169
    opType = STATE_OPER_GE;
6,179✔
5170
  } else if (strncasecmp(opStr, "NE", 2) == 0) {
139,183✔
5171
    opType = STATE_OPER_NE;
54,593✔
5172
  } else if (strncasecmp(opStr, "EQ", 2) == 0) {
84,590!
5173
    opType = STATE_OPER_EQ;
84,590✔
5174
  } else {
5175
    opType = STATE_OPER_INVALID;
×
5176
  }
5177

5178
  return opType;
198,977✔
5179
}
5180

5181
static bool checkStateOp(int8_t op, SColumnInfoData* pCol, int32_t index, SVariant param) {
102,109,711✔
5182
  char* data = colDataGetData(pCol, index);
102,109,711!
5183
  switch (pCol->info.type) {
102,109,711!
5184
    case TSDB_DATA_TYPE_TINYINT: {
6,921,072✔
5185
      int8_t v = *(int8_t*)data;
6,921,072✔
5186
      STATE_COMP(op, v, param);
6,921,072!
5187
      break;
×
5188
    }
5189
    case TSDB_DATA_TYPE_UTINYINT: {
18,048✔
5190
      uint8_t v = *(uint8_t*)data;
18,048✔
5191
      STATE_COMP(op, v, param);
18,048!
5192
      break;
×
5193
    }
5194
    case TSDB_DATA_TYPE_SMALLINT: {
61,762,032✔
5195
      int16_t v = *(int16_t*)data;
61,762,032✔
5196
      STATE_COMP(op, v, param);
61,762,032!
5197
      break;
×
5198
    }
5199
    case TSDB_DATA_TYPE_USMALLINT: {
5,760✔
5200
      uint16_t v = *(uint16_t*)data;
5,760✔
5201
      STATE_COMP(op, v, param);
5,760!
5202
      break;
×
5203
    }
5204
    case TSDB_DATA_TYPE_INT: {
49,666✔
5205
      int32_t v = *(int32_t*)data;
49,666✔
5206
      STATE_COMP(op, v, param);
49,666!
5207
      break;
×
5208
    }
5209
    case TSDB_DATA_TYPE_UINT: {
5,760✔
5210
      uint32_t v = *(uint32_t*)data;
5,760✔
5211
      STATE_COMP(op, v, param);
5,760!
5212
      break;
×
5213
    }
5214
    case TSDB_DATA_TYPE_BIGINT: {
135,168✔
5215
      int64_t v = *(int64_t*)data;
135,168✔
5216
      STATE_COMP(op, v, param);
135,168!
5217
      break;
×
5218
    }
5219
    case TSDB_DATA_TYPE_UBIGINT: {
5,760✔
5220
      uint64_t v = *(uint64_t*)data;
5,760✔
5221
      STATE_COMP(op, v, param);
5,760!
5222
      break;
×
5223
    }
5224
    case TSDB_DATA_TYPE_FLOAT: {
33,197,168✔
5225
      float v = *(float*)data;
33,197,168✔
5226
      STATE_COMP(op, v, param);
33,197,168!
5227
      break;
×
5228
    }
5229
    case TSDB_DATA_TYPE_DOUBLE: {
9,456✔
5230
      double v = *(double*)data;
9,456✔
5231
      STATE_COMP(op, v, param);
9,456!
5232
      break;
×
5233
    }
5234
    default: {
×
5235
      return false;
×
5236
    }
5237
  }
5238
  return false;
×
5239
}
5240

5241
int32_t stateCountFunction(SqlFunctionCtx* pCtx) {
91,344✔
5242
  int32_t              code = TSDB_CODE_SUCCESS;
91,344✔
5243
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
91,344✔
5244
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
91,344✔
5245

5246
  SInputColumnInfoData* pInput = &pCtx->input;
91,344✔
5247
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
91,344✔
5248

5249
  SColumnInfoData* pInputCol = pInput->pData[0];
91,344✔
5250

5251
  int32_t          numOfElems = 0;
91,344✔
5252
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
91,344✔
5253

5254
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
91,344✔
5255
  if (STATE_OPER_INVALID == op) {
91,344!
5256
    return 0;
×
5257
  }
5258

5259
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
53,270,748✔
5260
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
53,179,415!
5261
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5262
    } else {
5263
      pInfo->prevTs = tsList[i];
53,179,415✔
5264
    }
5265

5266
    pInfo->isPrevTsSet = true;
53,179,415✔
5267
    numOfElems++;
53,179,415✔
5268

5269
    if (colDataIsNull_f(pInputCol, i)) {
53,179,415✔
5270
      colDataSetNULL(pOutput, i);
70,724!
5271
      // handle selectivity
5272
      if (pCtx->subsidiaries.num > 0) {
70,724✔
5273
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
36✔
5274
        if (TSDB_CODE_SUCCESS != code) {
36!
5275
          return code;
×
5276
        }
5277
      }
5278
      continue;
70,724✔
5279
    }
5280

5281
    bool ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
53,108,691✔
5282

5283
    int64_t output = -1;
53,108,693✔
5284
    if (ret) {
53,108,693✔
5285
      output = ++pInfo->count;
41,375,984✔
5286
    } else {
5287
      pInfo->count = 0;
11,732,709✔
5288
    }
5289
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
53,108,693✔
5290
    if (TSDB_CODE_SUCCESS != code) {
53,108,680!
5291
      return code;
×
5292
    }
5293

5294
    // handle selectivity
5295
    if (pCtx->subsidiaries.num > 0) {
53,108,680✔
5296
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
27,112,216✔
5297
      if (TSDB_CODE_SUCCESS != code) {
27,112,216!
5298
        return code;
×
5299
      }
5300
    }
5301
  }
5302

5303
  pResInfo->numOfRes = numOfElems;
91,333✔
5304
  return TSDB_CODE_SUCCESS;
91,333✔
5305
}
5306

5307
int32_t stateDurationFunction(SqlFunctionCtx* pCtx) {
107,633✔
5308
  int32_t              code = TSDB_CODE_SUCCESS;
107,633✔
5309
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
107,633✔
5310
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
107,633✔
5311

5312
  SInputColumnInfoData* pInput = &pCtx->input;
107,633✔
5313
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
107,633✔
5314

5315
  SColumnInfoData* pInputCol = pInput->pData[0];
107,633✔
5316

5317
  int32_t          numOfElems = 0;
107,633✔
5318
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
107,633✔
5319

5320
  // TODO: process timeUnit for different db precisions
5321
  int32_t timeUnit = 1;
107,633✔
5322
  if (pCtx->numOfParams == 5) {  // TODO: param number incorrect
107,633✔
5323
    timeUnit = pCtx->param[3].param.i;
105,673✔
5324
  }
5325

5326
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
107,633✔
5327
  if (STATE_OPER_INVALID == op) {
107,633!
5328
    return TSDB_CODE_INVALID_PARA;
×
5329
  }
5330

5331
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
49,279,213✔
5332
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
49,171,580!
5333
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5334
    } else {
5335
      pInfo->prevTs = tsList[i];
49,171,580✔
5336
    }
5337

5338
    pInfo->isPrevTsSet = true;
49,171,580✔
5339
    numOfElems++;
49,171,580✔
5340

5341
    if (colDataIsNull_f(pInputCol, i)) {
49,171,580✔
5342
      colDataSetNULL(pOutput, i);
170,484!
5343
      // handle selectivity
5344
      if (pCtx->subsidiaries.num > 0) {
170,484✔
5345
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
52✔
5346
        if (TSDB_CODE_SUCCESS != code) {
52!
5347
          return code;
×
5348
        }
5349
      }
5350
      continue;
170,484✔
5351
    }
5352

5353
    bool    ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
49,001,096✔
5354
    int64_t output = -1;
49,001,096✔
5355
    if (ret) {
49,001,096✔
5356
      if (pInfo->durationStart == 0) {
13,645,675✔
5357
        output = 0;
7,036,224✔
5358
        pInfo->durationStart = tsList[i];
7,036,224✔
5359
      } else {
5360
        output = (tsList[i] - pInfo->durationStart) / timeUnit;
6,609,451✔
5361
      }
5362
    } else {
5363
      pInfo->durationStart = 0;
35,355,421✔
5364
    }
5365
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
49,001,096✔
5366
    if (TSDB_CODE_SUCCESS != code) {
49,001,096!
5367
      return code;
×
5368
    }
5369

5370
    // handle selectivity
5371
    if (pCtx->subsidiaries.num > 0) {
49,001,096✔
5372
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
32,022,368✔
5373
      if (TSDB_CODE_SUCCESS != code) {
32,022,368!
5374
        return code;
×
5375
      }
5376
    }
5377
  }
5378

5379
  pResInfo->numOfRes = numOfElems;
107,633✔
5380
  return TSDB_CODE_SUCCESS;
107,633✔
5381
}
5382

5383
bool getCsumFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
34,706✔
5384
  pEnv->calcMemSize = sizeof(SSumRes);
34,706✔
5385
  return true;
34,706✔
5386
}
5387

5388
int32_t csumFunction(SqlFunctionCtx* pCtx) {
53,035✔
5389
  int32_t              code = TSDB_CODE_SUCCESS;
53,035✔
5390
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
53,035✔
5391
  SSumRes*             pSumRes = GET_ROWCELL_INTERBUF(pResInfo);
53,035✔
5392

5393
  SInputColumnInfoData* pInput = &pCtx->input;
53,035✔
5394
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
53,035✔
5395

5396
  SColumnInfoData* pInputCol = pInput->pData[0];
53,035✔
5397
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
53,035✔
5398

5399
  int32_t numOfElems = 0;
53,035✔
5400
  int32_t type = pInputCol->info.type;
53,035✔
5401
  int32_t startOffset = pCtx->offset;
53,035✔
5402
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
9,872,250✔
5403
    if (pSumRes->isPrevTsSet == true && tsList[i] == pSumRes->prevTs) {
9,822,049✔
5404
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
18✔
5405
    } else {
5406
      pSumRes->prevTs = tsList[i];
9,822,031✔
5407
    }
5408
    pSumRes->isPrevTsSet = true;
9,822,031✔
5409

5410
    int32_t pos = startOffset + numOfElems;
9,822,031✔
5411
    if (colDataIsNull_f(pInputCol, i)) {
9,822,031✔
5412
      // colDataSetNULL(pOutput, i);
5413
      continue;
271,728✔
5414
    }
5415

5416
    char* data = colDataGetData(pInputCol, i);
9,550,303!
5417
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
12,830,121!
5418
      int64_t v;
5419
      GET_TYPED_DATA(v, int64_t, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
3,279,778!
5420
      pSumRes->isum += v;
3,279,778✔
5421
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->isum, false);
3,279,778✔
5422
      if (TSDB_CODE_SUCCESS != code) {
3,279,818!
5423
        return code;
×
5424
      }
5425
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
6,277,229!
5426
      uint64_t v;
5427
      GET_TYPED_DATA(v, uint64_t, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
6,704!
5428
      pSumRes->usum += v;
6,704✔
5429
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->usum, false);
6,704✔
5430
      if (TSDB_CODE_SUCCESS != code) {
6,704!
5431
        return code;
×
5432
      }
5433
    } else if (IS_FLOAT_TYPE(type)) {
6,263,821!
5434
      double v;
5435
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
6,276,080!
5436
      pSumRes->dsum += v;
6,276,282✔
5437
      // check for overflow
5438
      if (isinf(pSumRes->dsum) || isnan(pSumRes->dsum)) {
6,276,282!
5439
        colDataSetNULL(pOutput, pos);
×
5440
      } else {
5441
        code = colDataSetVal(pOutput, pos, (char*)&pSumRes->dsum, false);
6,276,285✔
5442
        if (TSDB_CODE_SUCCESS != code) {
6,274,538!
5443
          return code;
×
5444
        }
5445
      }
5446
    }
5447

5448
    // handle selectivity
5449
    if (pCtx->subsidiaries.num > 0) {
9,548,798✔
5450
      code = appendSelectivityValue(pCtx, i, pos);
6,013,121✔
5451
      if (TSDB_CODE_SUCCESS != code) {
6,011,810!
5452
        return code;
×
5453
      }
5454
    }
5455

5456
    numOfElems++;
9,547,487✔
5457
  }
5458

5459
  pResInfo->numOfRes = numOfElems;
50,201✔
5460
  return TSDB_CODE_SUCCESS;
50,201✔
5461
}
5462

5463
bool getMavgFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
31,830✔
5464
  pEnv->calcMemSize = sizeof(SMavgInfo) + MAVG_MAX_POINTS_NUM * sizeof(double);
31,830✔
5465
  return true;
31,830✔
5466
}
5467

5468
int32_t mavgFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
739,917✔
5469
  if (pResultInfo->initialized) {
739,917✔
5470
    return TSDB_CODE_SUCCESS;
707,337✔
5471
  }
5472
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
32,580!
5473
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5474
  }
5475

5476
  SMavgInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
32,581✔
5477
  pInfo->pos = 0;
32,581✔
5478
  pInfo->sum = 0;
32,581✔
5479
  pInfo->prevTs = -1;
32,581✔
5480
  pInfo->isPrevTsSet = false;
32,581✔
5481
  pInfo->numOfPoints = pCtx->param[1].param.i;
32,581✔
5482
  if (pInfo->numOfPoints < 1 || pInfo->numOfPoints > MAVG_MAX_POINTS_NUM) {
32,581!
5483
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
5484
  }
5485
  pInfo->pointsMeet = false;
32,581✔
5486

5487
  return TSDB_CODE_SUCCESS;
32,581✔
5488
}
5489

5490
int32_t mavgFunction(SqlFunctionCtx* pCtx) {
708,088✔
5491
  int32_t              code = TSDB_CODE_SUCCESS;
708,088✔
5492
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
708,088✔
5493
  SMavgInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
708,088✔
5494

5495
  SInputColumnInfoData* pInput = &pCtx->input;
708,088✔
5496
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
708,088✔
5497

5498
  SColumnInfoData* pInputCol = pInput->pData[0];
708,088✔
5499
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
708,088✔
5500
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
708,088✔
5501

5502
  int32_t numOfElems = 0;
708,088✔
5503
  int32_t type = pInputCol->info.type;
708,088✔
5504
  int32_t startOffset = pCtx->offset;
708,088✔
5505
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
175,531,978✔
5506
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
174,823,890!
5507
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5508
    } else {
5509
      pInfo->prevTs = tsList[i];
174,823,890✔
5510
    }
5511
    pInfo->isPrevTsSet = true;
174,823,890✔
5512

5513
    int32_t pos = startOffset + numOfElems;
174,823,890✔
5514
    if (colDataIsNull_f(pInputCol, i)) {
174,823,890✔
5515
      // colDataSetNULL(pOutput, i);
5516
      continue;
235,363✔
5517
    }
5518

5519
    char*  data = colDataGetData(pInputCol, i);
174,588,527!
5520
    double v;
5521
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
174,588,527!
5522

5523
    if (!pInfo->pointsMeet && (pInfo->pos < pInfo->numOfPoints - 1)) {
174,588,527✔
5524
      pInfo->points[pInfo->pos] = v;
15,392,424✔
5525
      pInfo->sum += v;
15,392,424✔
5526
    } else {
5527
      if (!pInfo->pointsMeet && (pInfo->pos == pInfo->numOfPoints - 1)) {
159,196,103!
5528
        pInfo->sum += v;
30,079✔
5529
        pInfo->pointsMeet = true;
30,079✔
5530
      } else {
5531
        pInfo->sum = pInfo->sum + v - pInfo->points[pInfo->pos];
159,166,024✔
5532
      }
5533

5534
      pInfo->points[pInfo->pos] = v;
159,196,103✔
5535
      double result = pInfo->sum / pInfo->numOfPoints;
159,196,103✔
5536
      // check for overflow
5537
      if (isinf(result) || isnan(result)) {
159,196,103!
5538
        colDataSetNULL(pOutput, pos);
×
5539
      } else {
5540
        code = colDataSetVal(pOutput, pos, (char*)&result, false);
159,196,103✔
5541
        if (TSDB_CODE_SUCCESS != code) {
159,196,103!
5542
          return code;
×
5543
        }
5544
      }
5545

5546
      // handle selectivity
5547
      if (pCtx->subsidiaries.num > 0) {
159,196,103✔
5548
        code = appendSelectivityValue(pCtx, i, pos);
100,233,981✔
5549
        if (TSDB_CODE_SUCCESS != code) {
100,233,981!
5550
          return code;
×
5551
        }
5552
      }
5553

5554
      numOfElems++;
159,196,103✔
5555
    }
5556

5557
    pInfo->pos++;
174,588,527✔
5558
    if (pInfo->pos == pInfo->numOfPoints) {
174,588,527✔
5559
      pInfo->pos = 0;
477,098✔
5560
    }
5561
  }
5562

5563
  pResInfo->numOfRes = numOfElems;
708,088✔
5564
  return TSDB_CODE_SUCCESS;
708,088✔
5565
}
5566

5567
static SSampleInfo* getSampleOutputInfo(SqlFunctionCtx* pCtx) {
53,873,238✔
5568
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
53,873,238✔
5569
  SSampleInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
53,873,238✔
5570

5571
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
53,873,238✔
5572
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
53,873,238✔
5573

5574
  return pInfo;
53,873,238✔
5575
}
5576

5577
bool getSampleFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
77,044✔
5578
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
77,044✔
5579
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
77,050✔
5580
  int32_t      numOfSamples = pVal->datum.i;
77,053✔
5581
  pEnv->calcMemSize = sizeof(SSampleInfo) + numOfSamples * (pCol->node.resType.bytes + sizeof(STuplePos));
77,053✔
5582
  return true;
77,053✔
5583
}
5584

5585
int32_t sampleFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
25,431,930✔
5586
  if (pResultInfo->initialized) {
25,431,930!
5587
    return TSDB_CODE_SUCCESS;
×
5588
  }
5589
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
25,431,930!
5590
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5591
  }
5592

5593
  taosSeedRand(taosSafeRand());
25,431,936✔
5594

5595
  SSampleInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
25,431,942✔
5596
  pInfo->samples = pCtx->param[1].param.i;
25,431,942✔
5597
  pInfo->totalPoints = 0;
25,431,942✔
5598
  pInfo->numSampled = 0;
25,431,942✔
5599
  pInfo->colType = pCtx->resDataInfo.type;
25,431,942✔
5600
  pInfo->colBytes = pCtx->resDataInfo.bytes;
25,431,942✔
5601
  pInfo->nullTuplePos.pageId = -1;
25,431,942✔
5602
  pInfo->nullTupleSaved = false;
25,431,942✔
5603
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
25,431,942✔
5604
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
25,431,942✔
5605

5606
  return TSDB_CODE_SUCCESS;
25,431,942✔
5607
}
5608

5609
static void sampleAssignResult(SSampleInfo* pInfo, char* data, int32_t index) {
63,204,881✔
5610
  assignVal(pInfo->data + index * pInfo->colBytes, data, pInfo->colBytes, pInfo->colType);
63,204,881✔
5611
}
63,204,854✔
5612

5613
static int32_t doReservoirSample(SqlFunctionCtx* pCtx, SSampleInfo* pInfo, char* data, int32_t index) {
69,136,261✔
5614
  pInfo->totalPoints++;
69,136,261✔
5615
  if (pInfo->numSampled < pInfo->samples) {
69,136,261✔
5616
    sampleAssignResult(pInfo, data, pInfo->numSampled);
57,718,625✔
5617
    if (pCtx->subsidiaries.num > 0) {
57,718,344✔
5618
      int32_t code = saveTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[pInfo->numSampled]);
3,221,338✔
5619
      if (code != TSDB_CODE_SUCCESS) {
3,221,712!
5620
        return code;
×
5621
      }
5622
    }
5623
    pInfo->numSampled++;
57,718,718✔
5624
  } else {
5625
    int32_t j = taosRand() % (pInfo->totalPoints);
11,417,636✔
5626
    if (j < pInfo->samples) {
11,423,459✔
5627
      sampleAssignResult(pInfo, data, j);
5,487,795✔
5628
      if (pCtx->subsidiaries.num > 0) {
5,487,662✔
5629
        int32_t code = updateTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[j]);
1,886,335✔
5630
        if (code != TSDB_CODE_SUCCESS) {
1,881,688!
5631
          return code;
×
5632
        }
5633
      }
5634
    }
5635
  }
5636

5637
  return TSDB_CODE_SUCCESS;
69,137,397✔
5638
}
5639

5640
int32_t sampleFunction(SqlFunctionCtx* pCtx) {
28,794,380✔
5641
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
28,794,380✔
5642
  SSampleInfo*         pInfo = getSampleOutputInfo(pCtx);
28,794,380✔
5643

5644
  SInputColumnInfoData* pInput = &pCtx->input;
28,794,379✔
5645

5646
  SColumnInfoData* pInputCol = pInput->pData[0];
28,794,379✔
5647
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
98,170,387✔
5648
    if (colDataIsNull_s(pInputCol, i)) {
138,758,076✔
5649
      continue;
239,176✔
5650
    }
5651

5652
    char*   data = colDataGetData(pInputCol, i);
69,139,862!
5653
    int32_t code = doReservoirSample(pCtx, pInfo, data, i);
69,139,862✔
5654
    if (code != TSDB_CODE_SUCCESS) {
69,136,832!
5655
      return code;
×
5656
    }
5657
  }
5658

5659
  if (pInfo->numSampled == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
28,791,349✔
5660
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
18✔
5661
    if (code != TSDB_CODE_SUCCESS) {
18!
5662
      return code;
×
5663
    }
5664
    pInfo->nullTupleSaved = true;
18✔
5665
  }
5666

5667
  SET_VAL(pResInfo, pInfo->numSampled, pInfo->numSampled);
28,791,349✔
5668
  return TSDB_CODE_SUCCESS;
28,791,349✔
5669
}
5670

5671
int32_t sampleFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
25,078,864✔
5672
  int32_t              code = TSDB_CODE_SUCCESS;
25,078,864✔
5673
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
25,078,864✔
5674

5675
  SSampleInfo* pInfo = getSampleOutputInfo(pCtx);
25,078,864✔
5676
  pEntryInfo->complete = true;
25,078,866✔
5677

5678
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
25,078,866✔
5679
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
25,078,866✔
5680
  if (NULL == pCol) {
25,078,862!
5681
    return TSDB_CODE_OUT_OF_RANGE;
×
5682
  }
5683

5684
  int32_t currentRow = pBlock->info.rows;
25,078,862✔
5685
  if (pInfo->numSampled == 0) {
25,078,862✔
5686
    colDataSetNULL(pCol, currentRow);
1,697✔
5687
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
1,697✔
5688
    return code;
1,696✔
5689
  }
5690
  for (int32_t i = 0; i < pInfo->numSampled; ++i) {
80,842,428✔
5691
    code = colDataSetVal(pCol, currentRow + i, pInfo->data + i * pInfo->colBytes, false);
55,769,896✔
5692
    if (TSDB_CODE_SUCCESS != code) {
55,762,207!
5693
      return code;
×
5694
    }
5695
    code = setSelectivityValue(pCtx, pBlock, &pInfo->tuplePos[i], currentRow + i);
55,762,207✔
5696
    if (TSDB_CODE_SUCCESS != code) {
55,765,263!
5697
      return code;
×
5698
    }
5699
  }
5700

5701
  return code;
25,072,532✔
5702
}
5703

5704
bool getTailFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
5705
#if 0
5706
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
5707
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
5708
  int32_t      numOfPoints = pVal->datum.i;
5709
  pEnv->calcMemSize = sizeof(STailInfo) + numOfPoints * (POINTER_BYTES + sizeof(STailItem) + pCol->node.resType.bytes);
5710
#endif
5711
  return true;
×
5712
}
5713

5714
int32_t tailFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
×
5715
#if 0
5716
  if (!functionSetup(pCtx, pResultInfo)) {
5717
    return false;
5718
  }
5719

5720
  STailInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
5721
  pInfo->numAdded = 0;
5722
  pInfo->numOfPoints = pCtx->param[1].param.i;
5723
  if (pCtx->numOfParams == 4) {
5724
    pInfo->offset = pCtx->param[2].param.i;
5725
  } else {
5726
    pInfo->offset = 0;
5727
  }
5728
  pInfo->colType = pCtx->resDataInfo.type;
5729
  pInfo->colBytes = pCtx->resDataInfo.bytes;
5730
  if ((pInfo->numOfPoints < 1 || pInfo->numOfPoints > TAIL_MAX_POINTS_NUM) ||
5731
      (pInfo->numOfPoints < 0 || pInfo->numOfPoints > TAIL_MAX_OFFSET)) {
5732
    return false;
5733
  }
5734

5735
  pInfo->pItems = (STailItem**)((char*)pInfo + sizeof(STailInfo));
5736
  char* pItem = (char*)pInfo->pItems + pInfo->numOfPoints * POINTER_BYTES;
5737

5738
  size_t unitSize = sizeof(STailItem) + pInfo->colBytes;
5739
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5740
    pInfo->pItems[i] = (STailItem*)(pItem + i * unitSize);
5741
    pInfo->pItems[i]->isNull = false;
5742
  }
5743
#endif
5744

5745
  return TSDB_CODE_SUCCESS;
×
5746
}
5747

5748
static void tailAssignResult(STailItem* pItem, char* data, int32_t colBytes, TSKEY ts, bool isNull) {
×
5749
#if 0
5750
  pItem->timestamp = ts;
5751
  if (isNull) {
5752
    pItem->isNull = true;
5753
  } else {
5754
    pItem->isNull = false;
5755
    memcpy(pItem->data, data, colBytes);
5756
  }
5757
#endif
5758
}
×
5759

5760
#if 0
5761
static int32_t tailCompFn(const void* p1, const void* p2, const void* param) {
5762
  STailItem* d1 = *(STailItem**)p1;
5763
  STailItem* d2 = *(STailItem**)p2;
5764
  return compareInt64Val(&d1->timestamp, &d2->timestamp);
5765
}
5766

5767
static void doTailAdd(STailInfo* pInfo, char* data, TSKEY ts, bool isNull) {
5768
  STailItem** pList = pInfo->pItems;
5769
  if (pInfo->numAdded < pInfo->numOfPoints) {
5770
    tailAssignResult(pList[pInfo->numAdded], data, pInfo->colBytes, ts, isNull);
5771
    taosheapsort((void*)pList, sizeof(STailItem**), pInfo->numAdded + 1, NULL, tailCompFn, 0);
5772
    pInfo->numAdded++;
5773
  } else if (pList[0]->timestamp < ts) {
5774
    tailAssignResult(pList[0], data, pInfo->colBytes, ts, isNull);
5775
    taosheapadjust((void*)pList, sizeof(STailItem**), 0, pInfo->numOfPoints - 1, NULL, tailCompFn, NULL, 0);
5776
  }
5777
}
5778
#endif
5779

5780
int32_t tailFunction(SqlFunctionCtx* pCtx) {
×
5781
#if 0
5782
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5783
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5784

5785
  SInputColumnInfoData* pInput = &pCtx->input;
5786
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
5787

5788
  SColumnInfoData* pInputCol = pInput->pData[0];
5789
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
5790

5791
  int32_t startOffset = pCtx->offset;
5792
  if (pInfo->offset >= pInput->numOfRows) {
5793
    return 0;
5794
  } else {
5795
    pInfo->numOfPoints = TMIN(pInfo->numOfPoints, pInput->numOfRows - pInfo->offset);
5796
  }
5797
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex - pInfo->offset; i += 1) {
5798
    char* data = colDataGetData(pInputCol, i);
5799
    doTailAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
5800
  }
5801

5802
  taosqsort(pInfo->pItems, pInfo->numOfPoints, POINTER_BYTES, NULL, tailCompFn);
5803

5804
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5805
    int32_t    pos = startOffset + i;
5806
    STailItem* pItem = pInfo->pItems[i];
5807
    if (pItem->isNull) {
5808
      colDataSetNULL(pOutput, pos);
5809
    } else {
5810
      colDataSetVal(pOutput, pos, pItem->data, false);
5811
    }
5812
  }
5813

5814
  return pInfo->numOfPoints;
5815
#endif
5816
  return 0;
×
5817
}
5818

5819
int32_t tailFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
5820
#if 0
5821
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
5822
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pEntryInfo);
5823
  pEntryInfo->complete = true;
5824

5825
  int32_t type = pCtx->input.pData[0]->info.type;
5826
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
5827

5828
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
5829

5830
  // todo assign the tag value and the corresponding row data
5831
  int32_t currentRow = pBlock->info.rows;
5832
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
5833
    STailItem* pItem = pInfo->pItems[i];
5834
    colDataSetVal(pCol, currentRow, pItem->data, false);
5835
    currentRow += 1;
5836
  }
5837

5838
  return pEntryInfo->numOfRes;
5839
#endif
5840
  return 0;
×
5841
}
5842

5843
bool getUniqueFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
5844
#if 0
5845
  pEnv->calcMemSize = sizeof(SUniqueInfo) + UNIQUE_MAX_RESULT_SIZE;
5846
#endif
5847
  return true;
×
5848
}
5849

5850
int32_t uniqueFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
×
5851
#if 0
5852
  if (!functionSetup(pCtx, pResInfo)) {
5853
    return false;
5854
  }
5855

5856
  SUniqueInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5857
  pInfo->numOfPoints = 0;
5858
  pInfo->colType = pCtx->resDataInfo.type;
5859
  pInfo->colBytes = pCtx->resDataInfo.bytes;
5860
  if (pInfo->pHash != NULL) {
5861
    taosHashClear(pInfo->pHash);
5862
  } else {
5863
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
5864
  }
5865
#endif
5866
  return TSDB_CODE_SUCCESS;
×
5867
}
5868

5869
#if 0
5870
static void doUniqueAdd(SUniqueInfo* pInfo, char* data, TSKEY ts, bool isNull) {
5871
  // handle null elements
5872
  if (isNull == true) {
5873
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
5874
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
5875
    if (pInfo->hasNull == false && pItem->isNull == false) {
5876
      pItem->timestamp = ts;
5877
      pItem->isNull = true;
5878
      pInfo->numOfPoints++;
5879
      pInfo->hasNull = true;
5880
    } else if (pItem->timestamp > ts && pItem->isNull == true) {
5881
      pItem->timestamp = ts;
5882
    }
5883
    return;
5884
  }
5885

5886
  int32_t      hashKeyBytes = IS_VAR_DATA_TYPE(pInfo->colType) ? varDataTLen(data) : pInfo->colBytes;
5887
  SUniqueItem* pHashItem = taosHashGet(pInfo->pHash, data, hashKeyBytes);
5888
  if (pHashItem == NULL) {
5889
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
5890
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
5891
    pItem->timestamp = ts;
5892
    memcpy(pItem->data, data, pInfo->colBytes);
5893

5894
    taosHashPut(pInfo->pHash, data, hashKeyBytes, (char*)pItem, sizeof(SUniqueItem*));
5895
    pInfo->numOfPoints++;
5896
  } else if (pHashItem->timestamp > ts) {
5897
    pHashItem->timestamp = ts;
5898
  }
5899
}
5900
#endif
5901

5902
int32_t uniqueFunction(SqlFunctionCtx* pCtx) {
×
5903
#if 0
5904
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5905
  SUniqueInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5906

5907
  SInputColumnInfoData* pInput = &pCtx->input;
5908
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
5909

5910
  SColumnInfoData* pInputCol = pInput->pData[0];
5911
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
5912
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
5913

5914
  int32_t startOffset = pCtx->offset;
5915
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
5916
    char* data = colDataGetData(pInputCol, i);
5917
    doUniqueAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
5918

5919
    if (sizeof(SUniqueInfo) + pInfo->numOfPoints * (sizeof(SUniqueItem) + pInfo->colBytes) >= UNIQUE_MAX_RESULT_SIZE) {
5920
      taosHashCleanup(pInfo->pHash);
5921
      return 0;
5922
    }
5923
  }
5924

5925
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5926
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + i * (sizeof(SUniqueItem) + pInfo->colBytes));
5927
    if (pItem->isNull == true) {
5928
      colDataSetNULL(pOutput, i);
5929
    } else {
5930
      colDataSetVal(pOutput, i, pItem->data, false);
5931
    }
5932
    if (pTsOutput != NULL) {
5933
      colDataSetInt64(pTsOutput, i, &pItem->timestamp);
5934
    }
5935
  }
5936

5937
  return pInfo->numOfPoints;
5938
#endif
5939
  return 0;
×
5940
}
5941

5942
bool getModeFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
61,456✔
5943
  pEnv->calcMemSize = sizeof(SModeInfo);
61,456✔
5944
  return true;
61,456✔
5945
}
5946

5947
int32_t modeFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
61,417✔
5948
  if (pResInfo->initialized) {
61,417!
5949
    return TSDB_CODE_SUCCESS;
×
5950
  }
5951
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
61,417!
5952
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5953
  }
5954

5955
  SModeInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
61,417✔
5956
  pInfo->colType = pCtx->resDataInfo.type;
61,417✔
5957
  pInfo->colBytes = pCtx->resDataInfo.bytes;
61,417✔
5958
  if (pInfo->pHash != NULL) {
61,417!
5959
    taosHashClear(pInfo->pHash);
×
5960
  } else {
5961
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
61,417✔
5962
    if (NULL == pInfo->pHash) {
61,417!
5963
      return terrno;
×
5964
    }
5965
  }
5966
  pInfo->nullTupleSaved = false;
61,417✔
5967
  pInfo->nullTuplePos.pageId = -1;
61,417✔
5968

5969
  pInfo->buf = taosMemoryMalloc(pInfo->colBytes);
61,417!
5970
  if (NULL == pInfo->buf) {
61,417!
5971
    taosHashCleanup(pInfo->pHash);
×
5972
    pInfo->pHash = NULL;
×
5973
    return terrno;
×
5974
  }
5975
  pCtx->needCleanup = true;
61,417✔
5976
  return TSDB_CODE_SUCCESS;
61,417✔
5977
}
5978

5979
static void modeFunctionCleanup(SModeInfo* pInfo) {
61,416✔
5980
  taosHashCleanup(pInfo->pHash);
61,416✔
5981
  pInfo->pHash = NULL;
61,417✔
5982
  taosMemoryFreeClear(pInfo->buf);
61,417!
5983
}
61,417✔
5984

5985
void modeFunctionCleanupExt(SqlFunctionCtx* pCtx) {
×
5986
  if (pCtx == NULL || GET_RES_INFO(pCtx) == NULL || GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)) == NULL) {
×
5987
    return;
×
5988
  }
5989
  modeFunctionCleanup(GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)));
×
5990
}
5991

5992
static int32_t saveModeTupleData(SqlFunctionCtx* pCtx, char* data, SModeInfo* pInfo, STuplePos* pPos) {
234,659,626✔
5993
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
234,659,626!
5994
    if (pInfo->colType == TSDB_DATA_TYPE_JSON) {
112,704,548✔
5995
      (void)memcpy(pInfo->buf, data, getJsonValueLen(data));
1,188✔
5996
    } else if (IS_STR_DATA_BLOB(pInfo->colType)) {
112,703,360!
5997
      (void)memcpy(pInfo->buf, data, blobDataTLen(data));
×
5998
    } else {
5999
      (void)memcpy(pInfo->buf, data, varDataTLen(data));
112,703,530✔
6000
    }
6001
  } else {
6002
    (void)memcpy(pInfo->buf, data, pInfo->colBytes);
121,955,078✔
6003
  }
6004

6005
  return doSaveTupleData(&pCtx->saveHandle, pInfo->buf, pInfo->colBytes, NULL, pPos, pCtx->pStore);
234,659,626✔
6006
}
6007

6008
static int32_t doModeAdd(SModeInfo* pInfo, int32_t rowIndex, SqlFunctionCtx* pCtx, char* data) {
290,956,509✔
6009
  int32_t code = TSDB_CODE_SUCCESS;
290,956,509✔
6010
  int32_t hashKeyBytes;
6011
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
290,956,509✔
6012
    hashKeyBytes = calcStrBytesByType(pInfo->colType, data);
112,705,735✔
6013
  } else {
6014
    hashKeyBytes = pInfo->colBytes;
178,250,774✔
6015
  }
6016

6017
  SModeItem* pHashItem = (SModeItem*)taosHashGet(pInfo->pHash, data, hashKeyBytes);
290,956,204✔
6018
  if (pHashItem == NULL) {
290,953,306✔
6019
    int32_t   size = sizeof(SModeItem);
234,659,757✔
6020
    SModeItem item = {0};
234,659,757✔
6021

6022
    item.count += 1;
234,659,757✔
6023
    code = saveModeTupleData(pCtx, data, pInfo, &item.dataPos);
234,659,757✔
6024
    if (code != TSDB_CODE_SUCCESS) {
234,658,397!
6025
      return code;
×
6026
    }
6027

6028
    if (pCtx->subsidiaries.num > 0) {
234,658,397✔
6029
      code = saveTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &item.tuplePos);
130,126,138✔
6030
      if (code != TSDB_CODE_SUCCESS) {
130,126,138!
6031
        return code;
×
6032
      }
6033
    }
6034

6035
    code = taosHashPut(pInfo->pHash, data, hashKeyBytes, &item, sizeof(SModeItem));
234,658,397✔
6036
    if (code != TSDB_CODE_SUCCESS) {
234,663,534!
6037
      return code;
×
6038
    }
6039
  } else {
6040
    pHashItem->count += 1;
56,293,549✔
6041
    if (pCtx->subsidiaries.num > 0) {
56,293,549✔
6042
      code = updateTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &pHashItem->tuplePos);
40,693,164✔
6043
      if (code != TSDB_CODE_SUCCESS) {
40,693,164!
6044
        return code;
×
6045
      }
6046
    }
6047
  }
6048

6049
  return code;
290,957,083✔
6050
}
6051

6052
int32_t modeFunction(SqlFunctionCtx* pCtx) {
5,174,351✔
6053
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5,174,351✔
6054
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5,174,351✔
6055

6056
  SInputColumnInfoData* pInput = &pCtx->input;
5,174,351✔
6057

6058
  SColumnInfoData* pInputCol = pInput->pData[0];
5,174,351✔
6059
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
5,174,351✔
6060

6061
  int32_t numOfElems = 0;
5,174,351✔
6062
  int32_t startOffset = pCtx->offset;
5,174,351✔
6063
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
296,244,850✔
6064
    if (colDataIsNull_s(pInputCol, i)) {
582,141,088✔
6065
      continue;
113,644✔
6066
    }
6067
    numOfElems++;
290,956,900✔
6068

6069
    char*   data = colDataGetData(pInputCol, i);
290,956,900!
6070
    int32_t code = doModeAdd(pInfo, i, pCtx, data);
290,956,900✔
6071
    if (code != TSDB_CODE_SUCCESS) {
290,957,002✔
6072
      modeFunctionCleanup(pInfo);
147✔
6073
      return code;
×
6074
    }
6075
  }
6076

6077
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
5,174,306!
6078
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
30✔
6079
    if (code != TSDB_CODE_SUCCESS) {
30!
6080
      modeFunctionCleanup(pInfo);
×
6081
      return code;
×
6082
    }
6083
    pInfo->nullTupleSaved = true;
30✔
6084
  }
6085

6086
  SET_VAL(pResInfo, numOfElems, 1);
5,174,306✔
6087

6088
  return TSDB_CODE_SUCCESS;
5,174,306✔
6089
}
6090

6091
int32_t modeFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
61,415✔
6092
  int32_t              code = TSDB_CODE_SUCCESS;
61,415✔
6093
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
61,415✔
6094
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
61,415✔
6095
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
61,415✔
6096
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
61,415✔
6097
  int32_t              currentRow = pBlock->info.rows;
61,415✔
6098
  if (NULL == pCol) {
61,415!
6099
    modeFunctionCleanup(pInfo);
×
6100
    return TSDB_CODE_OUT_OF_RANGE;
×
6101
  }
6102

6103
  STuplePos resDataPos, resTuplePos;
6104
  int32_t   maxCount = 0;
61,415✔
6105

6106
  void* pIter = taosHashIterate(pInfo->pHash, NULL);
61,415✔
6107
  while (pIter != NULL) {
234,725,632✔
6108
    SModeItem* pItem = (SModeItem*)pIter;
234,664,216✔
6109
    if (pItem->count >= maxCount) {
234,664,216✔
6110
      maxCount = pItem->count;
212,572,810✔
6111
      resDataPos = pItem->dataPos;
212,572,810✔
6112
      resTuplePos = pItem->tuplePos;
212,572,810✔
6113
    }
6114

6115
    pIter = taosHashIterate(pInfo->pHash, pIter);
234,664,216✔
6116
  }
6117

6118
  if (maxCount != 0) {
61,416✔
6119
    char* pData = NULL;
60,511✔
6120
    code = loadTupleData(pCtx, &resDataPos, &pData);
60,511✔
6121
    if (pData == NULL || TSDB_CODE_SUCCESS != code) {
60,511!
6122
      code = terrno = TSDB_CODE_NOT_FOUND;
×
6123
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
×
6124
             resDataPos.streamTupleKey.groupId, resDataPos.streamTupleKey.ts);
6125
      modeFunctionCleanup(pInfo);
×
6126
      return code;
×
6127
    }
6128

6129
    code = colDataSetVal(pCol, currentRow, pData, false);
60,511✔
6130
    if (TSDB_CODE_SUCCESS != code) {
60,511!
6131
      modeFunctionCleanup(pInfo);
×
6132
      return code;
×
6133
    }
6134
    code = setSelectivityValue(pCtx, pBlock, &resTuplePos, currentRow);
60,511✔
6135
  } else {
6136
    colDataSetNULL(pCol, currentRow);
905!
6137
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
905✔
6138
  }
6139

6140
  modeFunctionCleanup(pInfo);
61,416✔
6141

6142
  return code;
61,417✔
6143
}
6144

6145
bool getTwaFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
228,029✔
6146
  pEnv->calcMemSize = sizeof(STwaInfo);
228,029✔
6147
  return true;
228,029✔
6148
}
6149

6150
int32_t twaFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
30,456,054✔
6151
  if (pResultInfo->initialized) {
30,456,054!
6152
    return TSDB_CODE_SUCCESS;
×
6153
  }
6154
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
30,456,054!
6155
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6156
  }
6157

6158
  STwaInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
30,456,252✔
6159
  pInfo->numOfElems = 0;
30,456,252✔
6160
  pInfo->p.key = INT64_MIN;
30,456,252✔
6161
  pInfo->win = TSWINDOW_INITIALIZER;
30,456,252✔
6162
  return TSDB_CODE_SUCCESS;
30,456,252✔
6163
}
6164

6165
static double twa_get_area(SPoint1 s, SPoint1 e) {
82,719,197✔
6166
  if (e.key == INT64_MAX || s.key == INT64_MIN) {
82,719,197!
6167
    return 0;
×
6168
  }
6169

6170
  if ((s.val >= 0 && e.val >= 0) || (s.val <= 0 && e.val <= 0)) {
82,719,629✔
6171
    return (s.val + e.val) * (e.key - s.key) / 2;
46,033,063✔
6172
  }
6173

6174
  double x = (s.key * e.val - e.key * s.val) / (e.val - s.val);
36,686,566✔
6175
  double val = (s.val * (x - s.key) + e.val * (e.key - x)) / 2;
36,686,566✔
6176
  return val;
36,686,566✔
6177
}
6178

6179
int32_t twaFunction(SqlFunctionCtx* pCtx) {
30,487,414✔
6180
  int32_t               code = TSDB_CODE_SUCCESS;
30,487,414✔
6181
  SInputColumnInfoData* pInput = &pCtx->input;
30,487,414✔
6182
  SColumnInfoData*      pInputCol = pInput->pData[0];
30,487,414✔
6183

6184
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
30,487,414✔
6185
  STwaInfo*            pInfo = GET_ROWCELL_INTERBUF(pResInfo);
30,487,414✔
6186
  SPoint1*             last = &pInfo->p;
30,487,414✔
6187

6188
  if (IS_NULL_TYPE(pInputCol->info.type)) {
30,487,414!
6189
    pInfo->numOfElems = 0;
×
6190
    goto _twa_over;
×
6191
  }
6192

6193
  funcInputUpdate(pCtx);
30,487,414✔
6194
  SFuncInputRow row = {0};
30,487,692✔
6195
  bool          result = false;
30,487,692✔
6196
  if (pCtx->start.key != INT64_MIN && last->key == INT64_MIN) {
30,487,692!
6197
    while (1) {
6198
      code = funcInputGetNextRow(pCtx, &row, &result);
12,178,367✔
6199
      if (TSDB_CODE_SUCCESS != code) {
12,178,401!
6200
        return code;
×
6201
      }
6202
      if (!result) {
12,178,401✔
6203
        break;
2✔
6204
      }
6205
      if (row.isDataNull) {
12,178,399✔
6206
        continue;
2✔
6207
      }
6208

6209
      last->key = row.ts;
12,178,397✔
6210

6211
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData, typeGetTypeModFromColInfo(&pInputCol->info));
12,178,397!
6212

6213
      pInfo->dOutput += twa_get_area(pCtx->start, *last);
12,178,397✔
6214
      pInfo->win.skey = pCtx->start.key;
12,178,339✔
6215
      pInfo->numOfElems++;
12,178,339✔
6216
      break;
12,178,339✔
6217
    }
6218
  } else if (pInfo->p.key == INT64_MIN) {
18,309,327✔
6219
    while (1) {
6220
      code = funcInputGetNextRow(pCtx, &row, &result);
18,335,139✔
6221
      if (TSDB_CODE_SUCCESS != code) {
18,335,638!
6222
        return code;
×
6223
      }
6224
      if (!result) {
18,335,638✔
6225
        break;
6,762✔
6226
      }
6227
      if (row.isDataNull) {
18,328,876✔
6228
        continue;
56,129✔
6229
      }
6230

6231
      last->key = row.ts;
18,272,747✔
6232

6233
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData, typeGetTypeModFromColInfo(&pInputCol->info));
18,272,747!
6234

6235
      pInfo->win.skey = last->key;
18,272,677✔
6236
      pInfo->numOfElems++;
18,272,677✔
6237
      break;
18,272,677✔
6238
    }
6239
  }
6240

6241
  SPoint1 st = {0};
30,488,097✔
6242

6243
  // calculate the value of
6244
  while (1) {
6245
    code = funcInputGetNextRow(pCtx, &row, &result);
88,399,539✔
6246
    if (TSDB_CODE_SUCCESS != code) {
88,393,773!
6247
      return code;
×
6248
    }
6249
    if (!result) {
88,393,773✔
6250
      break;
30,488,254✔
6251
    }
6252
    if (row.isDataNull) {
57,905,519✔
6253
      continue;
624✔
6254
    }
6255
    pInfo->numOfElems++;
57,904,895✔
6256
    switch (pInputCol->info.type) {
57,904,895!
6257
      case TSDB_DATA_TYPE_TINYINT: {
19,170,637✔
6258
        INIT_INTP_POINT(st, row.ts, *(int8_t*)row.pData);
19,170,637✔
6259
        break;
19,170,637✔
6260
      }
6261
      case TSDB_DATA_TYPE_SMALLINT: {
76,594✔
6262
        INIT_INTP_POINT(st, row.ts, *(int16_t*)row.pData);
76,594✔
6263
        break;
76,594✔
6264
      }
6265
      case TSDB_DATA_TYPE_INT: {
422,281✔
6266
        INIT_INTP_POINT(st, row.ts, *(int32_t*)row.pData);
422,281✔
6267
        break;
422,281✔
6268
      }
6269
      case TSDB_DATA_TYPE_BIGINT: {
29,698,114✔
6270
        INIT_INTP_POINT(st, row.ts, *(int64_t*)row.pData);
29,698,114✔
6271
        break;
29,698,114✔
6272
      }
6273
      case TSDB_DATA_TYPE_FLOAT: {
606,719✔
6274
        INIT_INTP_POINT(st, row.ts, *(float_t*)row.pData);
606,719✔
6275
        break;
606,719✔
6276
      }
6277
      case TSDB_DATA_TYPE_DOUBLE: {
7,670,938✔
6278
        INIT_INTP_POINT(st, row.ts, *(double*)row.pData);
7,670,938✔
6279
        break;
7,670,938✔
6280
      }
6281
      case TSDB_DATA_TYPE_UTINYINT: {
69,345✔
6282
        INIT_INTP_POINT(st, row.ts, *(uint8_t*)row.pData);
69,345✔
6283
        break;
69,345✔
6284
      }
6285
      case TSDB_DATA_TYPE_USMALLINT: {
69,232✔
6286
        INIT_INTP_POINT(st, row.ts, *(uint16_t*)row.pData);
69,232✔
6287
        break;
69,232✔
6288
      }
6289
      case TSDB_DATA_TYPE_UINT: {
67,843✔
6290
        INIT_INTP_POINT(st, row.ts, *(uint32_t*)row.pData);
67,843✔
6291
        break;
67,843✔
6292
      }
6293
      case TSDB_DATA_TYPE_UBIGINT: {
59,089✔
6294
        INIT_INTP_POINT(st, row.ts, *(uint64_t*)row.pData);
59,089✔
6295
        break;
59,089✔
6296
      }
6297
      default: {
×
6298
        return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
6299
      }
6300
    }
6301
    if (pInfo->p.key == st.key) {
57,910,792!
6302
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6303
    }
6304

6305
    pInfo->dOutput += twa_get_area(pInfo->p, st);
57,910,792✔
6306
    pInfo->p = st;
57,910,818✔
6307
  }
6308

6309
  // the last interpolated time window value
6310
  if (pCtx->end.key != INT64_MIN) {
30,488,254✔
6311
    pInfo->dOutput += twa_get_area(pInfo->p, pCtx->end);
12,635,268✔
6312
    pInfo->p = pCtx->end;
12,635,159✔
6313
    pInfo->numOfElems += 1;
12,635,159✔
6314
  }
6315

6316
  pInfo->win.ekey = pInfo->p.key;
30,488,145✔
6317

6318
_twa_over:
30,488,145✔
6319
  SET_VAL(pResInfo, 1, 1);
30,488,145✔
6320
  return TSDB_CODE_SUCCESS;
30,488,145✔
6321
}
6322

6323
/*
6324
 * To copy the input to interResBuf to avoid the input buffer space be over writen
6325
 * by next input data. The TWA function only applies to each table, so no merge procedure
6326
 * is required, we simply copy to the resut ot interResBuffer.
6327
 */
6328
// void twa_function_copy(SQLFunctionCtx *pCtx) {
6329
//   SResultRowEntryInfo *pResInfo = GET_RES_INFO(pCtx);
6330
//
6331
//   memcpy(GET_ROWCELL_INTERBUF(pResInfo), pCtx->pInput, (size_t)pCtx->inputBytes);
6332
//   pResInfo->hasResult = ((STwaInfo *)pCtx->pInput)->hasResult;
6333
// }
6334

6335
int32_t twaFinalize(struct SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
30,416,289✔
6336
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
30,416,289✔
6337

6338
  STwaInfo* pInfo = (STwaInfo*)GET_ROWCELL_INTERBUF(pResInfo);
30,416,289✔
6339
  if (pInfo->numOfElems == 0) {
30,416,289✔
6340
    pResInfo->numOfRes = 0;
6,686✔
6341
  } else {
6342
    if (pInfo->win.ekey == pInfo->win.skey) {
30,409,603✔
6343
      pInfo->dTwaRes = pInfo->p.val;
14,690,275✔
6344
    } else if (pInfo->win.ekey == INT64_MAX || pInfo->win.skey == INT64_MIN) {  // no data in timewindow
15,719,328!
6345
      pInfo->dTwaRes = 0;
×
6346
    } else {
6347
      pInfo->dTwaRes = pInfo->dOutput / (pInfo->win.ekey - pInfo->win.skey);
15,721,741✔
6348
    }
6349

6350
    pResInfo->numOfRes = 1;
30,409,603✔
6351
  }
6352

6353
  return functionFinalize(pCtx, pBlock);
30,416,289✔
6354
}
6355

6356
int32_t blockDistSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
4,874✔
6357
  if (pResultInfo->initialized) {
4,874!
6358
    return TSDB_CODE_SUCCESS;
×
6359
  }
6360
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
4,874!
6361
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6362
  }
6363

6364
  STableBlockDistInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4,874✔
6365
  pInfo->minRows = INT32_MAX;
4,874✔
6366
  return TSDB_CODE_SUCCESS;
4,874✔
6367
}
6368

6369
int32_t blockDistFunction(SqlFunctionCtx* pCtx) {
9,746✔
6370
  const int32_t BLOCK_DIST_RESULT_ROWS = 25;
9,746✔
6371

6372
  SInputColumnInfoData* pInput = &pCtx->input;
9,746✔
6373
  SColumnInfoData*      pInputCol = pInput->pData[0];
9,746✔
6374
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
9,746✔
6375
  STableBlockDistInfo*  pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
9,746✔
6376

6377
  STableBlockDistInfo p1 = {0};
9,746✔
6378
  if (tDeserializeBlockDistInfo(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
9,746!
6379
    qError("failed to deserialize block dist info");
×
6380
    return TSDB_CODE_FAILED;
×
6381
  }
6382

6383
  pDistInfo->numOfBlocks += p1.numOfBlocks;
9,746✔
6384
  pDistInfo->numOfTables += p1.numOfTables;
9,746✔
6385
  pDistInfo->numOfInmemRows += p1.numOfInmemRows;
9,746✔
6386
  pDistInfo->numOfSttRows += p1.numOfSttRows;
9,746✔
6387
  pDistInfo->totalSize += p1.totalSize;
9,746✔
6388
  pDistInfo->totalRows += p1.totalRows;
9,746✔
6389
  pDistInfo->numOfFiles += p1.numOfFiles;
9,746✔
6390

6391
  pDistInfo->defMinRows = p1.defMinRows;
9,746✔
6392
  pDistInfo->defMaxRows = p1.defMaxRows;
9,746✔
6393
  pDistInfo->rowSize = p1.rowSize;
9,746✔
6394

6395
  if (pDistInfo->minRows > p1.minRows) {
9,746✔
6396
    pDistInfo->minRows = p1.minRows;
5✔
6397
  }
6398
  if (pDistInfo->maxRows < p1.maxRows) {
9,746✔
6399
    pDistInfo->maxRows = p1.maxRows;
5✔
6400
  }
6401
  pDistInfo->numOfVgroups += (p1.numOfTables != 0 ? 1 : 0);
9,746✔
6402
  for (int32_t i = 0; i < tListLen(pDistInfo->blockRowsHisto); ++i) {
204,666✔
6403
    pDistInfo->blockRowsHisto[i] += p1.blockRowsHisto[i];
194,920✔
6404
  }
6405

6406
  pResInfo->numOfRes = BLOCK_DIST_RESULT_ROWS;  // default output rows
9,746✔
6407
  return TSDB_CODE_SUCCESS;
9,746✔
6408
}
6409

6410
int32_t tSerializeBlockDistInfo(void* buf, int32_t bufLen, const STableBlockDistInfo* pInfo) {
19,430✔
6411
  SEncoder encoder = {0};
19,430✔
6412
  int32_t  code = 0;
19,430✔
6413
  int32_t  lino;
6414
  int32_t  tlen;
6415
  tEncoderInit(&encoder, buf, bufLen);
19,430✔
6416

6417
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
19,461!
6418
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->rowSize));
38,884!
6419

6420
  TAOS_CHECK_EXIT(tEncodeU16(&encoder, pInfo->numOfFiles));
38,884!
6421
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfBlocks));
38,884!
6422
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfTables));
38,884!
6423

6424
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalSize));
38,884!
6425
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalRows));
38,884!
6426
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->maxRows));
38,884!
6427
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->minRows));
38,884!
6428
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMaxRows));
38,884!
6429
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMinRows));
38,884!
6430
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfInmemRows));
38,884!
6431
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfSttRows));
38,884!
6432
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfVgroups));
38,884!
6433

6434
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
407,378✔
6435
    TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->blockRowsHisto[i]));
775,872!
6436
  }
6437

6438
  tEndEncode(&encoder);
19,442✔
6439

6440
_exit:
19,456✔
6441
  if (code) {
19,456!
6442
    tlen = code;
×
6443
  } else {
6444
    tlen = encoder.pos;
19,456✔
6445
  }
6446
  tEncoderClear(&encoder);
19,456✔
6447
  return tlen;
19,440✔
6448
}
6449

6450
int32_t tDeserializeBlockDistInfo(void* buf, int32_t bufLen, STableBlockDistInfo* pInfo) {
9,746✔
6451
  SDecoder decoder = {0};
9,746✔
6452
  int32_t  code = 0;
9,746✔
6453
  int32_t  lino;
6454
  tDecoderInit(&decoder, buf, bufLen);
9,746✔
6455

6456
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
9,746!
6457
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->rowSize));
19,492!
6458

6459
  TAOS_CHECK_EXIT(tDecodeU16(&decoder, &pInfo->numOfFiles));
19,492!
6460
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfBlocks));
19,492!
6461
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfTables));
19,492!
6462

6463
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalSize));
19,492!
6464
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalRows));
19,492!
6465
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->maxRows));
19,492!
6466
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->minRows));
19,492!
6467
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMaxRows));
19,492!
6468
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMinRows));
19,492!
6469
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfInmemRows));
19,492!
6470
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfSttRows));
19,492!
6471
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfVgroups));
19,492!
6472

6473
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
204,666✔
6474
    TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->blockRowsHisto[i]));
389,840!
6475
  }
6476

6477
_exit:
9,746✔
6478
  tDecoderClear(&decoder);
9,746✔
6479
  return code;
9,746✔
6480
}
6481

6482
int32_t blockDistFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
4,874✔
6483
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
4,874✔
6484
  STableBlockDistInfo* pData = GET_ROWCELL_INTERBUF(pResInfo);
4,874✔
6485

6486
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
4,874✔
6487
  if (NULL == pColInfo) {
4,874!
6488
    return TSDB_CODE_OUT_OF_RANGE;
×
6489
  }
6490

6491
  if (pData->totalRows == 0) {
4,874✔
6492
    pData->minRows = 0;
4,869✔
6493
  }
6494

6495
  int32_t row = 0;
4,874✔
6496
  char    st[256] = {0};
4,874✔
6497
  double  averageSize = 0;
4,874✔
6498
  if (pData->numOfBlocks != 0) {
4,874✔
6499
    averageSize = ((double)pData->totalSize) / pData->numOfBlocks;
5✔
6500
  }
6501
  uint64_t totalRawSize = pData->totalRows * pData->rowSize;
4,874✔
6502
  double   compRatio = 0;
4,874✔
6503
  if (totalRawSize != 0) {
4,874✔
6504
    compRatio = pData->totalSize * 100 / (double)totalRawSize;
5✔
6505
  }
6506

6507
  int32_t len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
9,748✔
6508
                          "Total_Blocks=[%d] Total_Size=[%.2f KiB] Average_size=[%.2f KiB] Compression_Ratio=[%.2f %c]",
6509
                          pData->numOfBlocks, pData->totalSize / 1024.0, averageSize / 1024.0, compRatio, '%');
4,874✔
6510

6511
  varDataSetLen(st, len);
4,874✔
6512
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
4,874✔
6513
  if (TSDB_CODE_SUCCESS != code) {
4,874!
6514
    return code;
×
6515
  }
6516

6517
  int64_t avgRows = 0;
4,874✔
6518
  if (pData->numOfBlocks > 0) {
4,874✔
6519
    avgRows = pData->totalRows / pData->numOfBlocks;
5✔
6520
  }
6521

6522
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
4,874✔
6523
                  "Block_Rows=[%" PRId64 "] MinRows=[%d] MaxRows=[%d] AvgRows=[%" PRId64 "]", pData->totalRows,
6524
                  pData->minRows, pData->maxRows, avgRows);
6525
  varDataSetLen(st, len);
4,874✔
6526
  code = colDataSetVal(pColInfo, row++, st, false);
4,874✔
6527
  if (TSDB_CODE_SUCCESS != code) {
4,874!
6528
    return code;
×
6529
  }
6530

6531
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Inmem_Rows=[%u] Stt_Rows=[%u] ",
4,874✔
6532
                  pData->numOfInmemRows, pData->numOfSttRows);
6533
  varDataSetLen(st, len);
4,874✔
6534
  code = colDataSetVal(pColInfo, row++, st, false);
4,874✔
6535
  if (TSDB_CODE_SUCCESS != code) {
4,874!
6536
    return code;
×
6537
  }
6538

6539
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
9,748✔
6540
                  "Total_Tables=[%d] Total_Filesets=[%d] Total_Vgroups=[%d]", pData->numOfTables, pData->numOfFiles,
4,874✔
6541
                  pData->numOfVgroups);
6542

6543
  varDataSetLen(st, len);
4,874✔
6544
  code = colDataSetVal(pColInfo, row++, st, false);
4,874✔
6545
  if (TSDB_CODE_SUCCESS != code) {
4,874!
6546
    return code;
×
6547
  }
6548

6549
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
4,874✔
6550
                  "--------------------------------------------------------------------------------");
6551
  varDataSetLen(st, len);
4,874✔
6552
  code = colDataSetVal(pColInfo, row++, st, false);
4,874✔
6553
  if (TSDB_CODE_SUCCESS != code) {
4,874!
6554
    return code;
×
6555
  }
6556

6557
  int32_t maxVal = 0;
4,874✔
6558
  int32_t minVal = INT32_MAX;
4,874✔
6559
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
102,354✔
6560
    if (maxVal < pData->blockRowsHisto[i]) {
97,480✔
6561
      maxVal = pData->blockRowsHisto[i];
9✔
6562
    }
6563

6564
    if (minVal > pData->blockRowsHisto[i]) {
97,480✔
6565
      minVal = pData->blockRowsHisto[i];
4,875✔
6566
    }
6567
  }
6568

6569
  // maximum number of step is 80
6570
  double factor = pData->numOfBlocks / 80.0;
4,874✔
6571

6572
  int32_t numOfBuckets = sizeof(pData->blockRowsHisto) / sizeof(pData->blockRowsHisto[0]);
4,874✔
6573
  int32_t bucketRange = ceil(((double)(pData->defMaxRows - pData->defMinRows)) / numOfBuckets);
4,874✔
6574

6575
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
102,354✔
6576
    len =
97,480✔
6577
        tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "%04d |", pData->defMinRows + bucketRange * (i + 1));
97,480✔
6578

6579
    int32_t num = 0;
97,480✔
6580
    if (pData->blockRowsHisto[i] > 0) {
97,480✔
6581
      num = (pData->blockRowsHisto[i]) / factor;
11✔
6582
    }
6583

6584
    for (int32_t j = 0; j < num; ++j) {
97,876✔
6585
      int32_t x = tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "%c", '|');
396✔
6586
      len += x;
396✔
6587
    }
6588

6589
    if (pData->blockRowsHisto[i] > 0) {
97,480✔
6590
      double v = pData->blockRowsHisto[i] * 100.0 / pData->numOfBlocks;
11✔
6591
      len += tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "  %d (%.2f%c)",
11✔
6592
                       pData->blockRowsHisto[i], v, '%');
6593
    }
6594

6595
    varDataSetLen(st, len);
97,480✔
6596
    code = colDataSetVal(pColInfo, row++, st, false);
97,480✔
6597
    if (TSDB_CODE_SUCCESS != code) {
97,480!
6598
      return code;
×
6599
    }
6600
  }
6601

6602
  return TSDB_CODE_SUCCESS;
4,874✔
6603
}
6604
int32_t blockDBUsageSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
4✔
6605
  if (pResultInfo->initialized) {
4!
6606
    return TSDB_CODE_SUCCESS;
×
6607
  }
6608
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
4!
6609
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6610
  }
6611

6612
  SDBBlockUsageInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4✔
6613
  return TSDB_CODE_SUCCESS;
4✔
6614
}
6615
int32_t blockDBUsageFunction(SqlFunctionCtx* pCtx) {
8✔
6616
  const int32_t BLOCK_DISK_USAGE_RESULT_ROWS = 2;
8✔
6617

6618
  SInputColumnInfoData* pInput = &pCtx->input;
8✔
6619
  SColumnInfoData*      pInputCol = pInput->pData[0];
8✔
6620
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
8✔
6621
  SDBBlockUsageInfo*    pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
8✔
6622

6623
  SDBBlockUsageInfo p1 = {0};
8✔
6624
  if (tDeserializeBlockDbUsage(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
8!
6625
    qError("failed to deserialize block dist info");
×
6626
    return TSDB_CODE_FAILED;
×
6627
  }
6628

6629
  pDistInfo->dataInDiskSize += p1.dataInDiskSize;
8✔
6630
  pDistInfo->walInDiskSize += p1.walInDiskSize;
8✔
6631
  pDistInfo->rawDataSize += p1.rawDataSize;
8✔
6632
  pResInfo->numOfRes = BLOCK_DISK_USAGE_RESULT_ROWS;  // default output rows
8✔
6633
  return TSDB_CODE_SUCCESS;
8✔
6634
}
6635

6636
int32_t tSerializeBlockDbUsage(void* buf, int32_t bufLen, const SDBBlockUsageInfo* pInfo) {
16✔
6637
  SEncoder encoder = {0};
16✔
6638
  int32_t  code = 0;
16✔
6639
  int32_t  lino;
6640
  int32_t  tlen;
6641
  tEncoderInit(&encoder, buf, bufLen);
16✔
6642

6643
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
16!
6644

6645
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->dataInDiskSize));
32!
6646
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->walInDiskSize));
32!
6647
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->rawDataSize));
32!
6648

6649
  tEndEncode(&encoder);
16✔
6650

6651
_exit:
16✔
6652
  if (code) {
16!
6653
    tlen = code;
×
6654
  } else {
6655
    tlen = encoder.pos;
16✔
6656
  }
6657
  tEncoderClear(&encoder);
16✔
6658
  return tlen;
16✔
6659
}
6660
int32_t tDeserializeBlockDbUsage(void* buf, int32_t bufLen, SDBBlockUsageInfo* pInfo) {
8✔
6661
  SDecoder decoder = {0};
8✔
6662
  int32_t  code = 0;
8✔
6663
  int32_t  lino;
6664
  tDecoderInit(&decoder, buf, bufLen);
8✔
6665

6666
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
8!
6667
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->dataInDiskSize));
16!
6668
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->walInDiskSize));
16!
6669
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->rawDataSize));
16!
6670

6671
_exit:
8✔
6672
  tDecoderClear(&decoder);
8✔
6673
  return code;
8✔
6674
}
6675
int32_t blockDBUsageFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
4✔
6676
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
4✔
6677
  SDBBlockUsageInfo*   pData = GET_ROWCELL_INTERBUF(pResInfo);
4✔
6678

6679
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
4✔
6680
  if (NULL == pColInfo) {
4!
6681
    return TSDB_CODE_OUT_OF_RANGE;
×
6682
  }
6683
  int32_t len = 0;
4✔
6684
  int32_t row = 0;
4✔
6685
  char    st[256] = {0};
4✔
6686

6687
  uint64_t totalDiskSize = pData->dataInDiskSize;
4✔
6688
  uint64_t rawDataSize = pData->rawDataSize;
4✔
6689
  double   compressRatio = 0;
4✔
6690
  if (rawDataSize != 0) {
4✔
6691
    compressRatio = totalDiskSize * 100 / (double)rawDataSize;
3✔
6692
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[%.2f%]", compressRatio);
3✔
6693
  } else {
6694
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[NULL]");
1✔
6695
  }
6696

6697
  varDataSetLen(st, len);
4✔
6698
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
4✔
6699
  if (TSDB_CODE_SUCCESS != code) {
4!
6700
    return code;
×
6701
  }
6702

6703
  len =
4✔
6704
      tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Disk_occupied=[%" PRId64 "k]", pData->dataInDiskSize);
4✔
6705
  varDataSetLen(st, len);
4✔
6706
  code = colDataSetVal(pColInfo, row++, st, false);
4✔
6707
  if (TSDB_CODE_SUCCESS != code) {
4!
6708
    return code;
×
6709
  }
6710
  return code;
4✔
6711
}
6712

6713
bool getDerivativeFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
90,110✔
6714
  pEnv->calcMemSize = sizeof(SDerivInfo);
90,110✔
6715
  return true;
90,110✔
6716
}
6717

6718
int32_t derivativeFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
203,215✔
6719
  if (pResInfo->initialized) {
203,215✔
6720
    return TSDB_CODE_SUCCESS;
113,018✔
6721
  }
6722
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
90,197!
6723
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6724
  }
6725

6726
  SDerivInfo* pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
90,197✔
6727

6728
  pDerivInfo->ignoreNegative = pCtx->param[2].param.i;
90,197✔
6729
  pDerivInfo->prevTs = -1;
90,197✔
6730
  pDerivInfo->tsWindow = pCtx->param[1].param.i;
90,197✔
6731
  pDerivInfo->valueSet = false;
90,197✔
6732
  return TSDB_CODE_SUCCESS;
90,197✔
6733
}
6734

6735
int32_t derivativeFunction(SqlFunctionCtx* pCtx) {
113,105✔
6736
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
113,105✔
6737
  SDerivInfo*          pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
113,105✔
6738

6739
  SInputColumnInfoData* pInput = &pCtx->input;
113,105✔
6740
  SColumnInfoData*      pInputCol = pInput->pData[0];
113,105✔
6741

6742
  int32_t          numOfElems = 0;
113,105✔
6743
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
113,105✔
6744
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
113,105✔
6745
  int32_t          code = TSDB_CODE_SUCCESS;
113,105✔
6746

6747
  funcInputUpdate(pCtx);
113,105✔
6748

6749
  double v = 0;
113,105✔
6750
  if (pCtx->order == TSDB_ORDER_ASC) {
113,105✔
6751
    SFuncInputRow row = {0};
103,137✔
6752
    bool          result = false;
103,137✔
6753
    while (1) {
8,832,636✔
6754
      code = funcInputGetNextRow(pCtx, &row, &result);
8,935,773✔
6755
      if (TSDB_CODE_SUCCESS != code) {
8,935,773!
6756
        return code;
×
6757
      }
6758
      if (!result) {
8,935,773✔
6759
        break;
103,137✔
6760
      }
6761
      if (row.isDataNull) {
8,832,636✔
6762
        continue;
19,313✔
6763
      }
6764

6765
      char* d = row.pData;
8,813,323✔
6766
      GET_TYPED_DATA(v, double, pInputCol->info.type, d, typeGetTypeModFromColInfo(&pInputCol->info));
8,813,323!
6767

6768
      int32_t pos = pCtx->offset + numOfElems;
8,813,323✔
6769
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
8,813,323✔
6770
        pDerivInfo->valueSet = true;
80,034✔
6771
      } else {
6772
        if (row.ts == pDerivInfo->prevTs) {
8,733,289!
6773
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6774
        }
6775
        double r = ((v - pDerivInfo->prevValue) * pDerivInfo->tsWindow) / (row.ts - pDerivInfo->prevTs);
8,733,289✔
6776
        if (pDerivInfo->ignoreNegative && r < 0) {
8,733,289✔
6777
        } else {
6778
          if (isinf(r) || isnan(r)) {
5,529,669!
6779
            colDataSetNULL(pOutput, pos);
×
6780
          } else {
6781
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
5,529,669✔
6782
            if (code != TSDB_CODE_SUCCESS) {
5,529,669!
6783
              return code;
×
6784
            }
6785
          }
6786

6787
          if (pTsOutput != NULL) {
5,529,669!
6788
            colDataSetInt64(pTsOutput, pos, &row.ts);
×
6789
          }
6790

6791
          // handle selectivity
6792
          if (pCtx->subsidiaries.num > 0) {
5,529,669✔
6793
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
4,035,084✔
6794
            if (code != TSDB_CODE_SUCCESS) {
4,035,084!
6795
              return code;
×
6796
            }
6797
          }
6798

6799
          numOfElems++;
5,529,669✔
6800
        }
6801
      }
6802

6803
      pDerivInfo->prevValue = v;
8,813,323✔
6804
      pDerivInfo->prevTs = row.ts;
8,813,323✔
6805
    }
6806
  } else {
6807
    SFuncInputRow row = {0};
9,968✔
6808
    bool          result = false;
9,968✔
6809
    while (1) {
995,678✔
6810
      code = funcInputGetNextRow(pCtx, &row, &result);
1,005,646✔
6811
      if (TSDB_CODE_SUCCESS != code) {
1,005,646!
6812
        return code;
×
6813
      }
6814
      if (!result) {
1,005,646✔
6815
        break;
9,968✔
6816
      }
6817
      if (row.isDataNull) {
995,678✔
6818
        continue;
24✔
6819
      }
6820

6821
      char* d = row.pData;
995,654✔
6822
      GET_TYPED_DATA(v, double, pInputCol->info.type, d, typeGetTypeModFromColInfo(&pInputCol->info));
995,654!
6823

6824
      int32_t pos = pCtx->offset + numOfElems;
995,654✔
6825
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
995,654✔
6826
        pDerivInfo->valueSet = true;
9,965✔
6827
      } else {
6828
        if (row.ts == pDerivInfo->prevTs) {
985,689!
6829
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6830
        }
6831
        double r = ((pDerivInfo->prevValue - v) * pDerivInfo->tsWindow) / (pDerivInfo->prevTs - row.ts);
985,689✔
6832
        if (pDerivInfo->ignoreNegative && r < 0) {
985,689✔
6833
        } else {
6834
          if (isinf(r) || isnan(r)) {
678,120!
6835
            colDataSetNULL(pOutput, pos);
×
6836
          } else {
6837
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
678,120✔
6838
            if (code != TSDB_CODE_SUCCESS) {
678,120!
6839
              return code;
×
6840
            }
6841
          }
6842

6843
          if (pTsOutput != NULL) {
678,120!
6844
            colDataSetInt64(pTsOutput, pos, &pDerivInfo->prevTs);
×
6845
          }
6846

6847
          // handle selectivity
6848
          if (pCtx->subsidiaries.num > 0) {
678,120✔
6849
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
212,562✔
6850
            if (code != TSDB_CODE_SUCCESS) {
212,562!
6851
              return code;
×
6852
            }
6853
          }
6854
          numOfElems++;
678,120✔
6855
        }
6856
      }
6857

6858
      pDerivInfo->prevValue = v;
995,654✔
6859
      pDerivInfo->prevTs = row.ts;
995,654✔
6860
    }
6861
  }
6862

6863
  pResInfo->numOfRes = numOfElems;
113,105✔
6864

6865
  return TSDB_CODE_SUCCESS;
113,105✔
6866
}
6867

6868
int32_t getIrateInfoSize(int32_t pkBytes) { return (int32_t)sizeof(SRateInfo) + 2 * pkBytes; }
6,903,543✔
6869

6870
bool getIrateFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
364,253✔
6871
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
364,253✔
6872
  pEnv->calcMemSize = getIrateInfoSize(pkBytes);
364,253✔
6873
  return true;
364,634✔
6874
}
6875

6876
int32_t irateFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
32,919,055✔
6877
  if (pResInfo->initialized) {
32,919,055!
6878
    return TSDB_CODE_SUCCESS;
×
6879
  }
6880
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
32,919,055!
6881
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6882
  }
6883

6884
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
32,919,295✔
6885

6886
  pInfo->firstKey = INT64_MIN;
32,919,295✔
6887
  pInfo->lastKey = INT64_MIN;
32,919,295✔
6888
  pInfo->firstValue = (double)INT64_MIN;
32,919,295✔
6889
  pInfo->lastValue = (double)INT64_MIN;
32,919,295✔
6890

6891
  pInfo->hasResult = 0;
32,919,295✔
6892
  return TSDB_CODE_SUCCESS;
32,919,295✔
6893
}
6894

6895
static void doSaveRateInfo(SRateInfo* pRateInfo, bool isFirst, int64_t ts, char* pk, double v) {
118,212,326✔
6896
  if (isFirst) {
118,212,326✔
6897
    pRateInfo->firstValue = v;
45,922,271✔
6898
    pRateInfo->firstKey = ts;
45,922,271✔
6899
    if (pRateInfo->firstPk) {
45,922,271✔
6900
      int32_t pkBytes;
6901
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
35!
6902
        pkBytes = calcStrBytesByType(pRateInfo->pkType, pk);
8✔
6903
      } else {
6904
        pkBytes = pRateInfo->pkBytes;
27✔
6905
      }
6906
      (void)memcpy(pRateInfo->firstPk, pk, pkBytes);
35✔
6907
    }
6908
  } else {
6909
    pRateInfo->lastValue = v;
72,290,055✔
6910
    pRateInfo->lastKey = ts;
72,290,055✔
6911
    if (pRateInfo->lastPk) {
72,290,055✔
6912
      int32_t pkBytes;
6913
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
52!
6914
        pkBytes = calcStrBytesByType(pRateInfo->pkType, pk);
12✔
6915
      } else {
6916
        pkBytes = pRateInfo->pkBytes;
40✔
6917
      }
6918
      (void)memcpy(pRateInfo->lastPk, pk, pkBytes);
52✔
6919
    }
6920
  }
6921
}
118,212,326✔
6922

6923
static void initializeRateInfo(SqlFunctionCtx* pCtx, SRateInfo* pRateInfo, bool isMerge) {
39,523,993✔
6924
  if (pCtx->hasPrimaryKey) {
39,523,993✔
6925
    if (!isMerge) {
19✔
6926
      pRateInfo->pkType = pCtx->input.pPrimaryKey->info.type;
17✔
6927
      pRateInfo->pkBytes = pCtx->input.pPrimaryKey->info.bytes;
17✔
6928
      pRateInfo->firstPk = pRateInfo->pkData;
17✔
6929
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
17✔
6930
    } else {
6931
      pRateInfo->firstPk = pRateInfo->pkData;
2✔
6932
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
2✔
6933
    }
6934
  } else {
6935
    pRateInfo->firstPk = NULL;
39,523,974✔
6936
    pRateInfo->lastPk = NULL;
39,523,974✔
6937
  }
6938
}
39,523,993✔
6939

6940
int32_t irateFunction(SqlFunctionCtx* pCtx) {
26,451,208✔
6941
  int32_t              code = TSDB_CODE_SUCCESS;
26,451,208✔
6942
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
26,451,208✔
6943
  SRateInfo*           pRateInfo = GET_ROWCELL_INTERBUF(pResInfo);
26,451,208✔
6944

6945
  SInputColumnInfoData* pInput = &pCtx->input;
26,451,208✔
6946
  SColumnInfoData*      pInputCol = pInput->pData[0];
26,451,208✔
6947

6948
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
26,451,208✔
6949

6950
  funcInputUpdate(pCtx);
26,451,208✔
6951

6952
  initializeRateInfo(pCtx, pRateInfo, false);
26,451,381✔
6953

6954
  int32_t       numOfElems = 0;
26,451,888✔
6955
  int32_t       type = pInputCol->info.type;
26,451,888✔
6956
  SFuncInputRow row = {0};
26,451,888✔
6957
  bool          result = false;
26,451,888✔
6958
  while (1) {
66,777,420✔
6959
    code = funcInputGetNextRow(pCtx, &row, &result);
93,229,308✔
6960
    if (TSDB_CODE_SUCCESS != code) {
93,222,477!
6961
      return code;
×
6962
    }
6963
    if (!result) {
93,222,477✔
6964
      break;
26,451,179✔
6965
    }
6966
    if (row.isDataNull) {
66,771,298✔
6967
      continue;
54,511✔
6968
    }
6969

6970
    char*  data = row.pData;
66,716,787✔
6971
    double v = 0;
66,716,787✔
6972
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
66,716,787!
6973

6974
    if (INT64_MIN == pRateInfo->lastKey) {
66,727,913✔
6975
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
26,376,914✔
6976
      pRateInfo->hasResult = 1;
26,376,743✔
6977
      continue;
26,376,743✔
6978
    }
6979

6980
    if (row.ts > pRateInfo->lastKey) {
40,350,999✔
6981
      if ((INT64_MIN == pRateInfo->firstKey) || pRateInfo->lastKey > pRateInfo->firstKey) {
39,383,943!
6982
        doSaveRateInfo(pRateInfo, true, pRateInfo->lastKey, pRateInfo->lastPk, pRateInfo->lastValue);
39,383,961✔
6983
      }
6984
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
39,383,782✔
6985
      continue;
39,383,488✔
6986
    } else if (row.ts == pRateInfo->lastKey) {
967,056!
6987
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6988
    }
6989

6990
    if ((INT64_MIN == pRateInfo->firstKey) || row.ts > pRateInfo->firstKey) {
967,056!
6991
      doSaveRateInfo(pRateInfo, true, row.ts, row.pPk, v);
1,089✔
6992
    } else if (row.ts == pRateInfo->firstKey) {
965,967!
6993
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6994
    }
6995
  }
6996

6997
  numOfElems++;
26,451,179✔
6998

6999
  SET_VAL(pResInfo, numOfElems, 1);
26,451,179!
7000
  return TSDB_CODE_SUCCESS;
26,451,179✔
7001
}
7002

7003
static double doCalcRate(const SRateInfo* pRateInfo, double tickPerSec) {
26,354,427✔
7004
  if ((INT64_MIN == pRateInfo->lastKey) || (INT64_MIN == pRateInfo->firstKey) ||
26,354,427✔
7005
      (pRateInfo->firstKey >= pRateInfo->lastKey)) {
5,701,881!
7006
    return 0.0;
20,652,545✔
7007
  }
7008

7009
  double diff = 0;
5,701,882✔
7010
  // If the previous value of the last is greater than the last value, only keep the last point instead of the delta
7011
  // value between two values.
7012
  diff = pRateInfo->lastValue;
5,701,882✔
7013
  if (diff >= pRateInfo->firstValue) {
5,701,882✔
7014
    diff -= pRateInfo->firstValue;
2,167,588✔
7015
  }
7016

7017
  int64_t duration = pRateInfo->lastKey - pRateInfo->firstKey;
5,701,882✔
7018
  if (duration == 0) {
5,701,882!
7019
    return 0;
×
7020
  }
7021

7022
  return (duration > 0) ? ((double)diff) / (duration / tickPerSec) : 0.0;
5,701,882!
7023
}
7024

7025
static void irateTransferInfoImpl(TSKEY inputKey, SRateInfo* pInput, SRateInfo* pOutput, bool isFirstKey) {
688✔
7026
  if (inputKey > pOutput->lastKey) {
688✔
7027
    doSaveRateInfo(pOutput, true, pOutput->lastKey, pOutput->lastPk, pOutput->lastValue);
300✔
7028
    if (isFirstKey) {
300✔
7029
      doSaveRateInfo(pOutput, false, pInput->firstKey, pInput->firstPk, pInput->firstValue);
60✔
7030
    } else {
7031
      doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
240✔
7032
    }
7033
  } else if ((inputKey < pOutput->lastKey) && (inputKey > pOutput->firstKey)) {
388!
7034
    if (isFirstKey) {
244✔
7035
      doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
172✔
7036
    } else {
7037
      doSaveRateInfo(pOutput, true, pInput->lastKey, pInput->lastPk, pInput->lastValue);
72✔
7038
    }
7039
  } else {
7040
    // inputKey < pOutput->firstKey
7041
  }
7042
}
688✔
7043

7044
static void irateCopyInfo(SRateInfo* pInput, SRateInfo* pOutput) {
6,536,599✔
7045
  doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
6,536,599✔
7046
  doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
6,536,599✔
7047
}
6,536,599✔
7048

7049
static int32_t irateTransferInfo(SRateInfo* pInput, SRateInfo* pOutput) {
6,536,943✔
7050
  if ((pInput->firstKey != INT64_MIN &&
6,536,943✔
7051
       (pInput->firstKey == pOutput->firstKey || pInput->firstKey == pOutput->lastKey)) ||
2,667,183!
7052
      (pInput->lastKey != INT64_MIN && (pInput->lastKey == pOutput->firstKey || pInput->lastKey == pOutput->lastKey))) {
6,536,943!
7053
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7054
  }
7055

7056
  if (pOutput->hasResult == 0) {
6,536,943✔
7057
    irateCopyInfo(pInput, pOutput);
6,536,599✔
7058
    pOutput->hasResult = pInput->hasResult;
6,536,599✔
7059
    return TSDB_CODE_SUCCESS;
6,536,599✔
7060
  }
7061

7062
  if (pInput->firstKey != INT64_MIN) {
344!
7063
    irateTransferInfoImpl(pInput->firstKey, pInput, pOutput, true);
344✔
7064
  }
7065

7066
  if (pInput->lastKey != INT64_MIN) {
344!
7067
    irateTransferInfoImpl(pInput->lastKey, pInput, pOutput, false);
344✔
7068
  }
7069

7070
  pOutput->hasResult = pInput->hasResult;
344✔
7071
  return TSDB_CODE_SUCCESS;
344✔
7072
}
7073

7074
int32_t irateFunctionMerge(SqlFunctionCtx* pCtx) {
6,536,953✔
7075
  SInputColumnInfoData* pInput = &pCtx->input;
6,536,953✔
7076
  SColumnInfoData*      pCol = pInput->pData[0];
6,536,953✔
7077
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
6,536,953!
7078
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
7079
  }
7080

7081
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
6,536,953✔
7082
  initializeRateInfo(pCtx, pInfo, true);
6,536,953✔
7083

7084
  int32_t start = pInput->startRowIndex;
6,536,953✔
7085
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
13,073,906✔
7086
    char*      data = colDataGetData(pCol, i);
6,536,953!
7087
    SRateInfo* pInputInfo = (SRateInfo*)varDataVal(data);
6,536,953✔
7088
    initializeRateInfo(pCtx, pInfo, true);
6,536,953✔
7089
    if (pInputInfo->hasResult) {
6,536,953✔
7090
      int32_t code = irateTransferInfo(pInputInfo, pInfo);
6,536,943✔
7091
      if (code != TSDB_CODE_SUCCESS) {
6,536,943!
7092
        return code;
×
7093
      }
7094
    }
7095
  }
7096

7097
  if (pInfo->hasResult) {
6,536,953✔
7098
    GET_RES_INFO(pCtx)->numOfRes = 1;
6,536,943✔
7099
  }
7100

7101
  return TSDB_CODE_SUCCESS;
6,536,953✔
7102
}
7103

7104
int32_t iratePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
6,538,915✔
7105
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
6,538,915✔
7106
  SRateInfo*           pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
6,538,915✔
7107
  int32_t              resultBytes = getIrateInfoSize(pInfo->pkBytes);
6,538,915✔
7108
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
6,538,915!
7109

7110
  if (NULL == res) {
6,538,915!
7111
    return terrno;
×
7112
  }
7113
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
6,538,915✔
7114
  varDataSetLen(res, resultBytes);
6,538,915✔
7115

7116
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
6,538,915✔
7117
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
6,538,915✔
7118
  if (NULL == pCol) {
6,538,915!
7119
    taosMemoryFree(res);
×
7120
    return TSDB_CODE_OUT_OF_RANGE;
×
7121
  }
7122

7123
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
6,538,915✔
7124

7125
  taosMemoryFree(res);
6,538,915!
7126
  return code;
6,538,915✔
7127
}
7128

7129
int32_t irateFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
26,365,211✔
7130
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
26,365,211✔
7131
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
26,365,211✔
7132
  if (NULL == pCol) {
26,354,425!
7133
    return TSDB_CODE_OUT_OF_RANGE;
×
7134
  }
7135

7136
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
26,354,425✔
7137
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
26,354,425✔
7138

7139
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
26,354,425✔
7140
  double     result = doCalcRate(pInfo, (double)TSDB_TICK_PER_SECOND(pCtx->param[1].param.i));
26,354,425!
7141
  int32_t    code = colDataSetVal(pCol, pBlock->info.rows, (const char*)&result, pResInfo->isNullRes);
26,354,278✔
7142

7143
  return code;
26,345,560✔
7144
}
7145

7146
int32_t groupConstValueFunction(SqlFunctionCtx* pCtx) {
94,879,805✔
7147
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
94,879,805✔
7148
  SGroupKeyInfo*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
94,879,805✔
7149

7150
  SInputColumnInfoData* pInput = &pCtx->input;
94,879,805✔
7151
  SColumnInfoData*      pInputCol = pInput->pData[0];
94,879,805✔
7152

7153
  int32_t startIndex = pInput->startRowIndex;
94,879,805✔
7154

7155
  // escape rest of data blocks to avoid first entry to be overwritten.
7156
  if (pInfo->hasResult) {
94,879,805✔
7157
    goto _group_value_over;
7,369,224✔
7158
  }
7159

7160
  if (pInputCol->pData == NULL || colDataIsNull_s(pInputCol, startIndex)) {
174,527,581✔
7161
    pInfo->isNull = true;
2,735,997✔
7162
    pInfo->hasResult = true;
2,735,997✔
7163
    goto _group_value_over;
2,735,997✔
7164
  }
7165

7166
  char* data = colDataGetData(pInputCol, startIndex);
84,774,584!
7167
  if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
84,774,584!
7168
    int32_t bytes = calcStrBytesByType(pInputCol->info.type, data);
69,135,850✔
7169
    (void)memcpy(pInfo->data, data, bytes);
69,241,364✔
7170
  } else {
7171
    (void)memcpy(pInfo->data, data, pInputCol->info.bytes);
15,638,734✔
7172
  }
7173
  pInfo->hasResult = true;
84,880,098✔
7174

7175
_group_value_over:
94,985,319✔
7176

7177
  SET_VAL(pResInfo, 1, 1);
94,985,319✔
7178
  return TSDB_CODE_SUCCESS;
94,985,319✔
7179
}
7180

7181
int32_t groupKeyFunction(SqlFunctionCtx* pCtx) { return groupConstValueFunction(pCtx); }
94,822,640✔
7182

7183
int32_t groupConstValueFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
85,901,199✔
7184
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
85,901,199✔
7185
  int32_t          code = TSDB_CODE_SUCCESS;
85,901,199✔
7186
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
85,901,199✔
7187
  if (NULL == pCol) {
85,814,259!
7188
    return TSDB_CODE_OUT_OF_RANGE;
×
7189
  }
7190

7191
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
85,814,259✔
7192

7193
  SGroupKeyInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
85,814,259✔
7194

7195
  if (pInfo->hasResult) {
85,814,259!
7196
    int32_t currentRow = pBlock->info.rows;
85,848,208✔
7197
    for (; currentRow < pBlock->info.rows + pResInfo->numOfRes; ++currentRow) {
172,543,060✔
7198
      code = colDataSetVal(pCol, currentRow, pInfo->data, pInfo->isNull ? true : false);
85,922,379✔
7199
      if (TSDB_CODE_SUCCESS != code) {
86,694,852!
7200
        return code;
×
7201
      }
7202
    }
7203
  } else {
7204
    pResInfo->numOfRes = 0;
×
7205
  }
7206

7207
  return code;
86,586,732✔
7208
}
7209

7210
int32_t groupKeyFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) { return groupConstValueFinalize(pCtx, pBlock); }
85,896,426✔
7211

7212
int32_t groupKeyCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
7213
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
7214
  SGroupKeyInfo*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
7215

7216
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
7217
  SGroupKeyInfo*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
7218

7219
  // escape rest of data blocks to avoid first entry to be overwritten.
7220
  if (pDBuf->hasResult) {
×
7221
    goto _group_key_over;
×
7222
  }
7223

7224
  if (pSBuf->isNull) {
×
7225
    pDBuf->isNull = true;
×
7226
    pDBuf->hasResult = true;
×
7227
    goto _group_key_over;
×
7228
  }
7229

7230
  if (IS_VAR_DATA_TYPE(pSourceCtx->resDataInfo.type)) {
×
7231
    int32_t bytes = calcStrBytesByType(pSourceCtx->resDataInfo.type, pSBuf->data);
×
7232
    (void)memcpy(pDBuf->data, pSBuf->data, bytes);
×
7233
  } else {
7234
    (void)memcpy(pDBuf->data, pSBuf->data, pSourceCtx->resDataInfo.bytes);
×
7235
  }
7236

7237
  pDBuf->hasResult = true;
×
7238

7239
_group_key_over:
×
7240

7241
  SET_VAL(pDResInfo, 1, 1);
×
7242
  return TSDB_CODE_SUCCESS;
×
7243
}
7244

7245
int32_t cachedLastRowFunction(SqlFunctionCtx* pCtx) {
5,885✔
7246
  int32_t numOfElems = 0;
5,885✔
7247

7248
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5,885✔
7249
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5,885✔
7250

7251
  SInputColumnInfoData* pInput = &pCtx->input;
5,885✔
7252
  SColumnInfoData*      pInputCol = pInput->pData[0];
5,885✔
7253

7254
  int32_t bytes = pInputCol->info.bytes;
5,885✔
7255
  pInfo->bytes = bytes;
5,885✔
7256

7257
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
5,885✔
7258
  pInfo->pkType = -1;
5,885✔
7259
  __compar_fn_t pkCompareFn = NULL;
5,885✔
7260
  if (pCtx->hasPrimaryKey) {
5,885✔
7261
    pInfo->pkType = pkCol->info.type;
405✔
7262
    pInfo->pkBytes = pkCol->info.bytes;
405✔
7263
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
405✔
7264
  }
7265

7266
  // data is guaranteed to be in descending order
7267
  for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
12,298✔
7268
    numOfElems++;
6,414✔
7269

7270
    bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
6,414✔
7271
    char* data = isNull ? NULL : colDataGetData(pInputCol, i);
6,414!
7272

7273
    TSKEY cts = getRowPTs(pInput->pPTS, i);
6,414✔
7274
    if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
6,414✔
7275
      int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
5,745✔
7276
      if (code != TSDB_CODE_SUCCESS) {
5,744!
7277
        return code;
×
7278
      }
7279
      pResInfo->numOfRes = 1;
5,744✔
7280
    }
7281
  }
7282

7283
  SET_VAL(pResInfo, numOfElems, 1);
5,884!
7284
  return TSDB_CODE_SUCCESS;
5,884✔
7285
}
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