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

taosdata / TDengine / #4807

17 Oct 2025 06:47AM UTC coverage: 61.121% (+0.03%) from 61.094%
#4807

push

travis-ci

web-flow
Merge pull request #33289 from taosdata/3.0

enh: Code Optimization (#33283)

155421 of 324369 branches covered (47.91%)

Branch coverage included in aggregate %.

1 of 1 new or added line in 1 file covered. (100.0%)

2727 existing lines in 120 files now uncovered.

207582 of 269535 relevant lines covered (77.01%)

127069383.69 hits per line

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

63.94
/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
#include "ttypes.h"
32

33
bool ignoreNegative(int8_t ignoreOption) { return (ignoreOption & 0x1) == 0x1; }
2,147,483,647✔
34
bool ignoreNull(int8_t ignoreOption) { return (ignoreOption & 0x2) == 0x2; }
24,050,319✔
35

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

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

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

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

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

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

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

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

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

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

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

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

151
#define LEASTSQR_CAL(p, x, y, index, step) \
152
  do {                                     \
153
    (p)[0][0] += (double)(x) * (x);        \
154
    (p)[0][1] += (double)(x);              \
155
    (p)[0][2] += (double)(x) * (y)[index]; \
156
    (p)[1][2] += (y)[index];               \
157
    (x) += step;                           \
158
  } while (0)
159

160
#define STATE_COMP(_op, _lval, _param) STATE_COMP_IMPL(_op, _lval, GET_STATE_VAL(_param))
161

162
#define GET_STATE_VAL(param) ((param.nType == TSDB_DATA_TYPE_BIGINT) ? (param.i) : (param.d))
163

164
#define STATE_COMP_IMPL(_op, _lval, _rval) \
165
  do {                                     \
166
    switch (_op) {                         \
167
      case STATE_OPER_LT:                  \
168
        return ((_lval) < (_rval));        \
169
        break;                             \
170
      case STATE_OPER_GT:                  \
171
        return ((_lval) > (_rval));        \
172
        break;                             \
173
      case STATE_OPER_LE:                  \
174
        return ((_lval) <= (_rval));       \
175
        break;                             \
176
      case STATE_OPER_GE:                  \
177
        return ((_lval) >= (_rval));       \
178
        break;                             \
179
      case STATE_OPER_NE:                  \
180
        return ((_lval) != (_rval));       \
181
        break;                             \
182
      case STATE_OPER_EQ:                  \
183
        return ((_lval) == (_rval));       \
184
        break;                             \
185
      default:                             \
186
        break;                             \
187
    }                                      \
188
  } while (0)
189

190
#define INIT_INTP_POINT(_p, _k, _v) \
191
  do {                              \
192
    (_p).key = (_k);                \
193
    (_p).val = (_v);                \
194
  } while (0)
195

196
void funcInputUpdate(SqlFunctionCtx* pCtx) {
33,862,712✔
197
  SFuncInputRowIter* pIter = &pCtx->rowIter;
33,862,712✔
198

199
  if (!pCtx->bInputFinished) {
33,862,712!
200
    pIter->pInput = &pCtx->input;
33,862,712✔
201
    pIter->tsList = (TSKEY*)pIter->pInput->pPTS->pData;
33,862,712✔
202
    pIter->pDataCol = pIter->pInput->pData[0];
33,862,712✔
203
    pIter->pPkCol = pIter->pInput->pPrimaryKey;
33,862,712✔
204
    pIter->rowIndex = pIter->pInput->startRowIndex;
33,862,712✔
205
    pIter->inputEndIndex = pIter->rowIndex + pIter->pInput->numOfRows - 1;
33,862,081✔
206
    pIter->pSrcBlock = pCtx->pSrcBlock;
33,862,712✔
207
    if (!pIter->hasGroupId || pIter->groupId != pIter->pSrcBlock->info.id.groupId) {
33,862,712!
208
      pIter->hasGroupId = true;
3,664,113✔
209
      pIter->groupId = pIter->pSrcBlock->info.id.groupId;
3,663,482✔
210
      pIter->hasPrev = false;
3,664,113✔
211
    }
212
  } else {
213
    pIter->finalRow = true;
×
214
  }
215
}
33,862,712✔
216

217
int32_t funcInputGetNextRowDescPk(SFuncInputRowIter* pIter, SFuncInputRow* pRow, bool* res) {
×
218
  if (pIter->finalRow) {
×
219
    if (pIter->hasPrev) {
×
220
      pRow->ts = pIter->prevBlockTsEnd;
×
221
      pRow->isDataNull = pIter->prevIsDataNull;
×
222
      pRow->pData = pIter->pPrevData;
×
223
      pRow->block = pIter->pPrevRowBlock;
×
224
      pRow->rowIndex = 0;
×
225

226
      pIter->hasPrev = false;
×
227
      *res = true;
×
228
      return TSDB_CODE_SUCCESS;
×
229
    } else {
230
      *res = false;
×
231
      return TSDB_CODE_SUCCESS;
×
232
    }
233
  }
234
  if (pIter->hasPrev) {
×
235
    if (pIter->prevBlockTsEnd == pIter->tsList[pIter->inputEndIndex]) {
×
236
      blockDataDestroy(pIter->pPrevRowBlock);
×
237
      int32_t code = blockDataExtractBlock(pIter->pSrcBlock, pIter->inputEndIndex, 1, &pIter->pPrevRowBlock);
×
238
      if (code) {
×
239
        return code;
×
240
      }
241

242
      pIter->prevIsDataNull = colDataIsNull_f(pIter->pDataCol, pIter->inputEndIndex);
×
243

244
      pIter->pPrevData = taosMemoryMalloc(pIter->pDataCol->info.bytes);
×
245
      if (NULL == pIter->pPrevData) {
×
246
        qError("out of memory when function get input row.");
×
247
        return terrno;
×
248
      }
249
      char* srcData = colDataGetData(pIter->pDataCol, pIter->inputEndIndex);
×
250
      (void)memcpy(pIter->pPrevData, srcData, pIter->pDataCol->info.bytes);
×
251

252
      pIter->pPrevPk = taosMemoryMalloc(pIter->pPkCol->info.bytes);
×
253
      if (NULL == pIter->pPrevPk) {
×
254
        qError("out of memory when function get input row.");
×
255
        taosMemoryFree(pIter->pPrevData);
×
256
        return terrno;
×
257
      }
258
      char* pkData = colDataGetData(pIter->pPkCol, pIter->inputEndIndex);
×
259
      (void)memcpy(pIter->pPrevPk, pkData, pIter->pPkCol->info.bytes);
×
260

261
      code = blockDataExtractBlock(pIter->pSrcBlock, pIter->inputEndIndex, 1, &pIter->pPrevRowBlock);
×
262
      pIter->hasPrev = true;
×
263
      *res = false;
×
264
      return code;
×
265
    } else {
266
      int32_t idx = pIter->rowIndex;
×
267
      while (pIter->tsList[idx] == pIter->prevBlockTsEnd) {
×
268
        ++idx;
×
269
      }
270
      pRow->ts = pIter->prevBlockTsEnd;
×
271
      if (idx == pIter->pInput->startRowIndex) {
×
272
        pRow->isDataNull = pIter->prevIsDataNull;
×
273
        pRow->pData = pIter->pPrevData;
×
274
        pRow->block = pIter->pPrevRowBlock;
×
275
        pRow->rowIndex = 0;
×
276
      } else {
277
        pRow->ts = pIter->tsList[idx - 1];
×
278
        pRow->isDataNull = colDataIsNull_f(pIter->pDataCol, idx - 1);
×
279
        pRow->pData = colDataGetData(pIter->pDataCol, idx - 1);
×
280
        pRow->pPk = colDataGetData(pIter->pPkCol, idx - 1);
×
281
        pRow->block = pIter->pSrcBlock;
×
282
        pRow->rowIndex = idx - 1;
×
283
      }
284
      pIter->hasPrev = false;
×
285
      pIter->rowIndex = idx;
×
286
      *res = true;
×
287
      return TSDB_CODE_SUCCESS;
×
288
    }
289
  } else {
290
    TSKEY tsEnd = pIter->tsList[pIter->inputEndIndex];
×
291
    if (pIter->tsList[pIter->rowIndex] != tsEnd) {
×
292
      int32_t idx = pIter->rowIndex;
×
293
      while (pIter->tsList[idx + 1] == pIter->tsList[pIter->rowIndex]) {
×
294
        ++idx;
×
295
      }
296
      pRow->ts = pIter->tsList[idx];
×
297
      pRow->isDataNull = colDataIsNull_f(pIter->pDataCol, idx);
×
298
      pRow->pData = colDataGetData(pIter->pDataCol, idx);
×
299
      pRow->pPk = colDataGetData(pIter->pPkCol, idx);
×
300
      pRow->block = pIter->pSrcBlock;
×
301

302
      pIter->rowIndex = idx + 1;
×
303
      *res = true;
×
304
      return TSDB_CODE_SUCCESS;
×
305
    } else {
306
      pIter->hasPrev = true;
×
307
      pIter->prevBlockTsEnd = tsEnd;
×
308
      pIter->prevIsDataNull = colDataIsNull_f(pIter->pDataCol, pIter->inputEndIndex);
×
309
      pIter->pPrevData = taosMemoryMalloc(pIter->pDataCol->info.bytes);
×
310
      if (NULL == pIter->pPrevData) {
×
311
        qError("out of memory when function get input row.");
×
312
        return terrno;
×
313
      }
314
      (void)memcpy(pIter->pPrevData, colDataGetData(pIter->pDataCol, pIter->inputEndIndex),
×
315
                   pIter->pDataCol->info.bytes);
×
316
      pIter->pPrevPk = taosMemoryMalloc(pIter->pPkCol->info.bytes);
×
317
      if (NULL == pIter->pPrevPk) {
×
318
        qError("out of memory when function get input row.");
×
319
        taosMemoryFree(pIter->pPrevData);
×
320
        return terrno;
×
321
      }
322
      (void)memcpy(pIter->pPrevPk, colDataGetData(pIter->pPkCol, pIter->inputEndIndex), pIter->pPkCol->info.bytes);
×
323

324
      int32_t code = blockDataExtractBlock(pIter->pSrcBlock, pIter->inputEndIndex, 1, &pIter->pPrevRowBlock);
×
325
      *res = false;
×
326
      return code;
×
327
    }
328
  }
329
}
330

331
static void forwardToNextDiffTsRow(SFuncInputRowIter* pIter, int32_t rowIndex) {
47,344✔
332
  int32_t idx = rowIndex + 1;
47,344✔
333
  while (idx <= pIter->inputEndIndex && pIter->tsList[idx] == pIter->tsList[rowIndex]) {
108,354!
334
    ++idx;
61,010✔
335
  }
336
  pIter->rowIndex = idx;
47,344✔
337
}
47,344✔
338

339
static void setInputRowInfo(SFuncInputRow* pRow, SFuncInputRowIter* pIter, int32_t rowIndex, bool setPk) {
2,147,483,647✔
340
  pRow->ts = pIter->tsList[rowIndex];
2,147,483,647✔
341
  pRow->ts = pIter->tsList[rowIndex];
2,147,483,647✔
342
  pRow->isDataNull = colDataIsNull_f(pIter->pDataCol, rowIndex);
2,147,483,647!
343
  pRow->pData = colDataGetData(pIter->pDataCol, rowIndex);
2,147,483,647!
344
  pRow->pPk = setPk ? colDataGetData(pIter->pPkCol, rowIndex) : NULL;
2,147,483,647!
345
  pRow->block = pIter->pSrcBlock;
2,147,483,647✔
346
  pRow->rowIndex = rowIndex;
2,147,483,647✔
347
}
2,147,483,647✔
348

349
bool funcInputGetNextRowAscPk(SFuncInputRowIter* pIter, SFuncInputRow* pRow) {
93,426✔
350
  if (pIter->hasPrev) {
93,426!
351
    if (pIter->prevBlockTsEnd == pIter->tsList[pIter->inputEndIndex]) {
×
352
      pIter->hasPrev = true;
×
353
      return false;
×
354
    } else {
355
      int32_t idx = pIter->rowIndex;
×
356
      while (pIter->tsList[idx] == pIter->prevBlockTsEnd) {
×
357
        ++idx;
×
358
      }
359

360
      pIter->hasPrev = false;
×
361
      setInputRowInfo(pRow, pIter, idx, true);
×
362
      forwardToNextDiffTsRow(pIter, idx);
×
363
      return true;
×
364
    }
365
  } else {
366
    if (pIter->rowIndex <= pIter->inputEndIndex) {
93,426✔
367
      setInputRowInfo(pRow, pIter, pIter->rowIndex, true);
71,016✔
368

369
      TSKEY tsEnd = pIter->tsList[pIter->inputEndIndex];
71,016✔
370
      if (pIter->tsList[pIter->rowIndex] != tsEnd) {
71,016✔
371
        forwardToNextDiffTsRow(pIter, pIter->rowIndex);
47,344✔
372
      } else {
373
        pIter->rowIndex = pIter->inputEndIndex + 1;
23,672✔
374
      }
375
      return true;
71,016✔
376
    } else {
377
      TSKEY tsEnd = pIter->tsList[pIter->inputEndIndex];
22,410✔
378
      pIter->hasPrev = true;
22,410✔
379
      pIter->prevBlockTsEnd = tsEnd;
22,410✔
380
      return false;
22,410✔
381
    }
382
  }
383
}
384

385
bool funcInputGetNextRowNoPk(SFuncInputRowIter* pIter, SFuncInputRow* pRow) {
2,147,483,647✔
386
  if (pIter->rowIndex <= pIter->inputEndIndex) {
2,147,483,647✔
387
    setInputRowInfo(pRow, pIter, pIter->rowIndex, false);
2,147,483,647✔
388
    ++pIter->rowIndex;
2,147,483,647✔
389
    return true;
2,147,483,647✔
390
  } else {
391
    return false;
34,268,569✔
392
  }
393
}
394

395
int32_t funcInputGetNextRow(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, bool* res) {
2,147,483,647✔
396
  SFuncInputRowIter* pIter = &pCtx->rowIter;
2,147,483,647✔
397
  if (pCtx->hasPrimaryKey) {
2,147,483,647!
398
    if (pCtx->order == TSDB_ORDER_ASC) {
93,426!
399
      *res = funcInputGetNextRowAscPk(pIter, pRow);
93,426✔
400
      return TSDB_CODE_SUCCESS;
93,426✔
401
    } else {
402
      return funcInputGetNextRowDescPk(pIter, pRow, res);
×
403
    }
404
  } else {
405
    *res = funcInputGetNextRowNoPk(pIter, pRow);
2,147,483,647✔
406
    return TSDB_CODE_SUCCESS;
2,147,483,647✔
407
  }
408
  return TSDB_CODE_SUCCESS;
409
}
410

411
// This function append the selectivity to subsidiaries function context directly, without fetching data
412
// from intermediate disk based buf page
413
int32_t appendSelectivityCols(SqlFunctionCtx* pCtx, SSDataBlock* pSrcBlock, int32_t rowIndex, int32_t pos) {
2,147,483,647✔
414
  if (pCtx->subsidiaries.num <= 0) {
2,147,483,647!
415
    return TSDB_CODE_SUCCESS;
×
416
  }
417

418
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
2,147,483,647✔
419
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
2,147,483,647✔
420

421
    // get data from source col
422
    SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
2,147,483,647✔
423
    int32_t      srcSlotId = pFuncParam->pCol->slotId;
2,147,483,647✔
424

425
    SColumnInfoData* pSrcCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
2,147,483,647✔
426
    if (NULL == pSrcCol) {
2,147,483,647!
427
      return TSDB_CODE_OUT_OF_RANGE;
×
428
    }
429

430
    char* pData = colDataGetData(pSrcCol, rowIndex);
2,147,483,647!
431

432
    // append to dest col
433
    int32_t dstSlotId = pc->pExpr->base.resSchema.slotId;
2,147,483,647✔
434

435
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
2,147,483,647✔
436
    if (NULL == pDstCol) {
2,147,483,647!
437
      return TSDB_CODE_OUT_OF_RANGE;
×
438
    }
439
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
2,147,483,647!
440
      colDataSetNULL(pDstCol, pos);
3,149!
441
    } else {
442
      int32_t code = colDataSetVal(pDstCol, pos, pData, false);
2,147,483,647✔
443
      if (TSDB_CODE_SUCCESS != code) {
2,147,483,647!
444
        return code;
×
445
      }
446
    }
447
  }
448
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
449
}
450

451
bool funcInputGetNextRowIndex(SInputColumnInfoData* pInput, int32_t from, bool firstOccur, int32_t* pRowIndex,
452
                              int32_t* nextFrom);
453

454
static bool firstLastTransferInfoImpl(SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst);
455

456
int32_t functionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
2,147,483,647✔
457
  if (pResultInfo->initialized) {
2,147,483,647✔
458
    return TSDB_CODE_SUCCESS;  // already initialized
1,851,196✔
459
  }
460

461
  if (pCtx->pOutput != NULL) {
2,147,483,647!
462
    (void)memset(pCtx->pOutput, 0, (size_t)pCtx->resDataInfo.bytes);
×
463
  }
464

465
  initResultRowEntry(pResultInfo, pCtx->resDataInfo.interBufSize);
2,147,483,647✔
466
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
467
}
468

469
int32_t functionFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,147,483,647✔
470
  int32_t          code = TSDB_CODE_SUCCESS;
2,147,483,647✔
471
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
2,147,483,647✔
472
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,147,483,647✔
473
  if (NULL == pCol) {
2,147,483,647!
474
    return TSDB_CODE_OUT_OF_RANGE;
×
475
  }
476
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
477
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
2,147,483,647✔
478

479
  char* in = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
480
  code = colDataSetVal(pCol, pBlock->info.rows, in, pResInfo->isNullRes);
2,147,483,647✔
481

482
  return code;
2,147,483,647✔
483
}
484

485
int32_t firstCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
486
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
487
  SFirstLastRes*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
488
  int32_t              bytes = pDBuf->bytes;
×
489

490
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
491
  SFirstLastRes*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
492

493
  pDBuf->hasResult = firstLastTransferInfoImpl(pSBuf, pDBuf, true);
×
494

495
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
496
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
497
  return TSDB_CODE_SUCCESS;
×
498
}
499

500
int32_t functionFinalizeWithResultBuf(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, char* finalResult) {
31,218✔
501
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
31,218✔
502
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
31,218✔
503
  if (NULL == pCol) {
31,218!
504
    return TSDB_CODE_OUT_OF_RANGE;
×
505
  }
506
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
31,218✔
507
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
31,218✔
508

509
  char*   in = finalResult;
31,218✔
510
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, in, pResInfo->isNullRes);
31,218✔
511

512
  return code;
31,218✔
513
}
514

515
EFuncDataRequired countDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
7,675,875✔
516
  SNode* pParam = nodesListGetNode(pFunc->pParameterList, 0);
7,675,875✔
517
  if (QUERY_NODE_COLUMN == nodeType(pParam) && PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pParam)->colId) {
7,675,504✔
518
    return FUNC_DATA_REQUIRED_NOT_LOAD;
5,314,082✔
519
  }
520
  return FUNC_DATA_REQUIRED_SMA_LOAD;
2,361,422✔
521
}
522

523
bool getCountFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
37,093,408✔
524
  pEnv->calcMemSize = sizeof(int64_t);
37,093,408✔
525
  return true;
37,126,232✔
526
}
527

528
static int64_t getNumOfElems(SqlFunctionCtx* pCtx) {
2,147,483,647✔
529
  int64_t numOfElem = 0;
2,147,483,647✔
530

531
  /*
532
   * 1. column data missing (schema modified) causes pInputCol->hasNull == true. pInput->colDataSMAIsSet == true;
533
   * 2. for general non-primary key columns, pInputCol->hasNull may be true or false, pInput->colDataSMAIsSet == true;
534
   * 3. for primary key column, pInputCol->hasNull always be false, pInput->colDataSMAIsSet == false;
535
   */
536
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
537
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
538
  if (1 == pInput->numOfRows && pInput->blankFill) {
2,147,483,647!
539
    return 0;
23,046,464✔
540
  }
541
  if (pInput->colDataSMAIsSet && pInput->totalRows == pInput->numOfRows) {
2,147,483,647!
542
    numOfElem = pInput->numOfRows - pInput->pColumnDataAgg[0]->numOfNull;
471,906✔
543
  } else {
544
    if (pInputCol->hasNull) {
2,147,483,647✔
545
      for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
2,147,483,647✔
546
        if (colDataIsNull(pInputCol, pInput->totalRows, i, NULL)) {
2,147,483,647!
547
          continue;
2,147,483,647✔
548
        }
549
        numOfElem += 1;
2,147,483,647✔
550
      }
551
    } else {
552
      // when counting on the primary time stamp column and no statistics data is presented, use the size value
553
      // directly.
554
      numOfElem = pInput->numOfRows;
2,147,483,647✔
555
    }
556
  }
557
  return numOfElem;
2,147,483,647✔
558
}
559

560
/*
561
 * count function does need the finalize, if data is missing, the default value, which is 0, is used
562
 * count function does not use the pCtx->interResBuf to keep the intermediate buffer
563
 */
564
int32_t countFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
565
  int64_t numOfElem = 0;
2,147,483,647✔
566

567
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
568
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
569

570
  int32_t type = pInput->pData[0]->info.type;
2,147,483,647✔
571

572
  char*   buf = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
573
  int64_t val = *((int64_t*)buf);
2,147,483,647✔
574
  if (IS_NULL_TYPE(type)) {
2,147,483,647✔
575
    // select count(NULL) returns 0
576
    numOfElem = 1;
2,751,475✔
577
    val += 0;
2,751,475✔
578
  } else {
579
    numOfElem = getNumOfElems(pCtx);
2,147,483,647✔
580
    val += numOfElem;
2,147,483,647✔
581
  }
582
  taosSetInt64Aligned((int64_t*)buf, val);
583

584
  if (tsCountAlwaysReturnValue) {
2,147,483,647✔
585
    pResInfo->numOfRes = 1;
2,147,483,647✔
586
  } else {
587
    SET_VAL(pResInfo, val, 1);
3,531,314✔
588
  }
589

590
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
591
}
592

593
int32_t combineFunction(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
594
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
595
  char*                pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
596

597
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
598
  char*                pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
599
  *((int64_t*)pDBuf) += *((int64_t*)pSBuf);
×
600

601
  SET_VAL(pDResInfo, *((int64_t*)pDBuf), 1);
×
602
  return TSDB_CODE_SUCCESS;
×
603
}
604

605
int32_t sumFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
606
  int32_t numOfElem = 0;
2,147,483,647✔
607

608
  // Only the pre-computing information loaded and actual data does not loaded
609
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
610
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
2,147,483,647✔
611
  int32_t               type = pInput->pData[0]->info.type;
2,147,483,647✔
612
  pCtx->inputType = type;
2,147,483,647✔
613

614
  void* pSumRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,147,483,647✔
615
  SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, type);
2,147,483,647✔
616

617
  if (IS_NULL_TYPE(type)) {
2,147,483,647✔
618
    numOfElem = 0;
91,672✔
619
    goto _sum_over;
91,672✔
620
  }
621

622
  if (pInput->colDataSMAIsSet) {
2,147,483,647!
623
    numOfElem = pInput->numOfRows - pAgg->numOfNull;
1,839,960✔
624

625
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
1,839,960!
626
      SUM_RES_INC_ISUM(pSumRes, pAgg->sum);
1,837,309✔
627
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
2,651!
628
      SUM_RES_INC_USUM(pSumRes, pAgg->sum);
×
629
    } else if (IS_FLOAT_TYPE(type)) {
2,651!
630
      SUM_RES_INC_DSUM(pSumRes, GET_DOUBLE_VAL((const char*)&(pAgg->sum)));
×
631
    } else if (IS_DECIMAL_TYPE(type)) {
2,651!
632
      SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, TSDB_DATA_TYPE_DECIMAL);
2,651!
633
      const SDecimalOps* pOps = getDecimalOps(TSDB_DATA_TYPE_DECIMAL);
2,651✔
634
      if (pAgg->overflow || decimal128AddCheckOverflow((Decimal*)&SUM_RES_GET_DECIMAL_SUM(pSumRes),
4,820!
635
                                                       &pAgg->decimal128Sum, DECIMAL_WORD_NUM(Decimal))) {
2,169✔
636
        return TSDB_CODE_DECIMAL_OVERFLOW;
482✔
637
      }
638
      pOps->add(&SUM_RES_GET_DECIMAL_SUM(pSumRes), &pAgg->decimal128Sum, DECIMAL_WORD_NUM(Decimal));
2,169✔
639
    }
640
  } else {  // computing based on the true data block
641
    SColumnInfoData* pCol = pInput->pData[0];
2,147,483,647✔
642

643
    int32_t start = pInput->startRowIndex;
2,147,483,647✔
644
    int32_t numOfRows = pInput->numOfRows;
2,147,483,647✔
645

646
    if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
2,147,483,647✔
647
      if (type == TSDB_DATA_TYPE_TINYINT || type == TSDB_DATA_TYPE_BOOL) {
2,147,483,647✔
648
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int8_t, numOfElem);
286,481,528!
649
      } else if (type == TSDB_DATA_TYPE_SMALLINT) {
2,147,483,647✔
650
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int16_t, numOfElem);
156,930,721!
651
      } else if (type == TSDB_DATA_TYPE_INT) {
2,147,483,647✔
652
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int32_t, numOfElem);
2,147,483,647!
653
      } else if (type == TSDB_DATA_TYPE_BIGINT) {
890,397,202✔
654
        LIST_ADD_N(SUM_RES_GET_ISUM(pSumRes), pCol, start, numOfRows, int64_t, numOfElem);
2,147,483,647!
655
      }
656
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
212,429,824✔
657
      if (type == TSDB_DATA_TYPE_UTINYINT) {
183,466✔
658
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint8_t, numOfElem);
31,609,825!
659
      } else if (type == TSDB_DATA_TYPE_USMALLINT) {
173,641✔
660
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint16_t, numOfElem);
31,616,817!
661
      } else if (type == TSDB_DATA_TYPE_UINT) {
162,942✔
662
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint32_t, numOfElem);
32,007,973!
663
      } else if (type == TSDB_DATA_TYPE_UBIGINT) {
47,415!
664
        LIST_ADD_N(SUM_RES_GET_USUM(pSumRes), pCol, start, numOfRows, uint64_t, numOfElem);
32,068,135!
665
      }
666
    } else if (type == TSDB_DATA_TYPE_DOUBLE) {
212,246,358✔
667
      LIST_ADD_N(SUM_RES_GET_DSUM(pSumRes), pCol, start, numOfRows, double, numOfElem);
386,591,971!
668
    } else if (type == TSDB_DATA_TYPE_FLOAT) {
133,302,300✔
669
      LIST_ADD_N(SUM_RES_GET_DSUM(pSumRes), pCol, start, numOfRows, float, numOfElem);
357,813,584!
670
    } else if (IS_DECIMAL_TYPE(type)) {
12,424!
671
      SUM_RES_SET_TYPE(pSumRes, pCtx->inputType, TSDB_DATA_TYPE_DECIMAL);
12,424!
672
      int32_t overflow = false;
7,230✔
673
      if (TSDB_DATA_TYPE_DECIMAL64 == type) {
7,230✔
674
        LIST_ADD_DECIMAL_N(&SUM_RES_GET_DECIMAL_SUM(pSumRes), pCol, start, numOfRows, Decimal64, numOfElem);
1,929,928!
675
      } else if (TSDB_DATA_TYPE_DECIMAL == type) {
5,302!
676
        LIST_ADD_DECIMAL_N(&SUM_RES_GET_DECIMAL_SUM(pSumRes), pCol, start, numOfRows, Decimal128, numOfElem);
3,862,748!
677
      }
678
      if (overflow) return TSDB_CODE_DECIMAL_OVERFLOW;
7,230!
679
    }
680
  }
681

682
  // check for overflow
683
  if (IS_FLOAT_TYPE(type) && (isinf(SUM_RES_GET_DSUM(pSumRes)) || isnan(SUM_RES_GET_DSUM(pSumRes)))) {
2,147,483,647!
684
    numOfElem = 0;
×
685
  }
686

687
_sum_over:
2,147,483,647✔
688
  if (numOfElem == 0) {
2,147,483,647✔
689
    if (tsCountAlwaysReturnValue && pCtx->pExpr->pExpr->_function.pFunctNode->hasOriginalFunc &&
168,724,298!
690
        fmIsCountLikeFunc(pCtx->pExpr->pExpr->_function.pFunctNode->originalFuncId)) {
64,893,655✔
691
      numOfElem = 1;
×
692
    }
693
  }
694
  // data in the check operation are all null, not output
695
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
2,147,483,647✔
696
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
697
}
698

699
int32_t sumCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
700
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
701
  void*                pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
702
  int16_t              type = SUM_RES_GET_TYPE(pDBuf, pDestCtx->inputType);
×
703

704
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
705
  void*                pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
706
  type = (type == TSDB_DATA_TYPE_NULL) ? SUM_RES_GET_TYPE(pSBuf, pDestCtx->inputType) : type;
×
707

708
  if (IS_SIGNED_NUMERIC_TYPE(type) || type == TSDB_DATA_TYPE_BOOL) {
×
709
    SUM_RES_INC_ISUM(pDBuf, SUM_RES_GET_ISUM(pSBuf));
×
710
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
711
    SUM_RES_INC_USUM(pDBuf, SUM_RES_GET_USUM(pSBuf));
×
712
  } else if (IS_DECIMAL_TYPE(type)) {
×
713
    bool overflow = false;
×
714
    SUM_RES_INC_DECIMAL_SUM(pDBuf, &SUM_RES_GET_DECIMAL_SUM(pSBuf), type);
×
715
  } else if (type == TSDB_DATA_TYPE_DOUBLE || type == TSDB_DATA_TYPE_FLOAT) {
×
716
    SUM_RES_INC_DSUM(pDBuf, SUM_RES_GET_DSUM(pSBuf));
×
717
  }
718
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
719
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
720
  return TSDB_CODE_SUCCESS;
×
721
}
722

723
bool getSumFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
32,430,429✔
724
  pEnv->calcMemSize = SUM_RES_GET_SIZE(pFunc->node.resType.type);
32,430,429!
725
  return true;
32,435,473✔
726
}
727

728
static bool funcNotSupportStringSma(SFunctionNode* pFunc) {
5,825,541✔
729
  SNode* pParam;
730
  switch (pFunc->funcType) {
5,825,541!
731
    case FUNCTION_TYPE_MAX:
5,825,541✔
732
    case FUNCTION_TYPE_MIN:
733
    case FUNCTION_TYPE_SUM:
734
    case FUNCTION_TYPE_AVG:
735
    case FUNCTION_TYPE_AVG_PARTIAL:
736
    case FUNCTION_TYPE_PERCENTILE:
737
    case FUNCTION_TYPE_SPREAD:
738
    case FUNCTION_TYPE_SPREAD_PARTIAL:
739
    case FUNCTION_TYPE_SPREAD_MERGE:
740
    case FUNCTION_TYPE_TWA:
741
    case FUNCTION_TYPE_ELAPSED:
742
      pParam = nodesListGetNode(pFunc->pParameterList, 0);
5,825,541✔
743
      if (pParam && nodesIsExprNode(pParam) && (IS_VAR_DATA_TYPE(((SExprNode*)pParam)->resType.type))) {
5,825,541!
744
        return true;
38,166✔
745
      }
746
      break;
5,787,375✔
747
    default:
×
748
      break;
×
749
  }
750
  return false;
5,787,375✔
751
}
752

753
EFuncDataRequired statisDataRequired(SFunctionNode* pFunc, STimeWindow* pTimeWindow) {
5,825,541✔
754
  if (funcNotSupportStringSma(pFunc)) {
5,825,541✔
755
    return FUNC_DATA_REQUIRED_DATA_LOAD;
38,166✔
756
  }
757
  return FUNC_DATA_REQUIRED_SMA_LOAD;
5,787,375✔
758
}
759

760
int32_t minmaxFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
596,708,839✔
761
  if (pResultInfo->initialized) {
596,708,839!
762
    return TSDB_CODE_SUCCESS;
×
763
  }
764
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
596,839,800!
765
    return TSDB_CODE_FUNC_SETUP_ERROR;  // not initialized since it has been initialized
×
766
  }
767

768
  SMinmaxResInfo* buf = GET_ROWCELL_INTERBUF(pResultInfo);
596,883,070✔
769
  buf->assign = false;
596,844,588✔
770
  buf->tuplePos.pageId = -1;
596,868,359✔
771

772
  buf->nullTupleSaved = false;
596,881,439✔
773
  buf->nullTuplePos.pageId = -1;
596,897,344✔
774
  buf->str = NULL;
596,890,512✔
775
  return TSDB_CODE_SUCCESS;
596,923,135✔
776
}
777

778
bool getMinmaxFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
6,958,731✔
779
  COMPILE_TIME_ASSERT(sizeof(SMinmaxResInfo) == sizeof(SOldMinMaxResInfo));
780
  pEnv->calcMemSize = sizeof(SMinmaxResInfo);
6,958,731✔
781
  return true;
6,960,158✔
782
}
783

784
int32_t minFunction(SqlFunctionCtx* pCtx) {
455,181,991✔
785
  int32_t numOfElems = 0;
455,181,991✔
786
  int32_t code = doMinMaxHelper(pCtx, 1, &numOfElems);
455,318,405✔
787
  if (code != TSDB_CODE_SUCCESS) {
455,454,743!
788
    return code;
×
789
  }
790
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
455,454,743✔
791
  return TSDB_CODE_SUCCESS;
455,431,896✔
792
}
793

794
int32_t maxFunction(SqlFunctionCtx* pCtx) {
480,692,587✔
795
  int32_t numOfElems = 0;
480,692,587✔
796
  int32_t code = doMinMaxHelper(pCtx, 0, &numOfElems);
480,755,678✔
797
  if (code != TSDB_CODE_SUCCESS) {
480,747,826!
798
    return code;
×
799
  }
800
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
480,747,826✔
801
  return TSDB_CODE_SUCCESS;
480,718,833✔
802
}
803

804
static int32_t setNullSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t rowIndex);
805
static int32_t setSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, const STuplePos* pTuplePos,
806
                                   int32_t rowIndex);
807

808
int32_t minmaxFunctionFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
562,787,801✔
809
  int32_t code = TSDB_CODE_SUCCESS;
562,787,801✔
810

811
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
562,787,801✔
812
  SMinmaxResInfo*      pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
562,835,695✔
813

814
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
562,838,953✔
815
  int32_t currentRow = pBlock->info.rows;
562,863,847✔
816

817
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
562,843,908✔
818
  if (NULL == pCol) {
562,839,419!
819
    return TSDB_CODE_OUT_OF_RANGE;
×
820
  }
821
  pEntryInfo->isNullRes = (pEntryInfo->numOfRes == 0) ? 1 : 0;
562,839,419✔
822

823
  // NOTE: do nothing change it, for performance issue
824
  if (!pEntryInfo->isNullRes) {
562,785,956✔
825
    switch (pCol->info.type) {
464,955,796✔
826
      case TSDB_DATA_TYPE_UBIGINT:
139,187,368✔
827
      case TSDB_DATA_TYPE_BIGINT:
828
        ((int64_t*)pCol->pData)[currentRow] = pRes->v;
139,187,368✔
829
        break;
139,188,007✔
830
      case TSDB_DATA_TYPE_UINT:
240,560,146✔
831
      case TSDB_DATA_TYPE_INT:
832
        colDataSetInt32(pCol, currentRow, (int32_t*)&pRes->v);
240,560,146✔
833
        break;
240,535,903✔
834
      case TSDB_DATA_TYPE_USMALLINT:
1,549,674✔
835
      case TSDB_DATA_TYPE_SMALLINT:
836
        colDataSetInt16(pCol, currentRow, (int16_t*)&pRes->v);
1,549,674✔
837
        break;
1,549,674✔
838
      case TSDB_DATA_TYPE_BOOL:
23,007,324✔
839
      case TSDB_DATA_TYPE_UTINYINT:
840
      case TSDB_DATA_TYPE_TINYINT:
841
        colDataSetInt8(pCol, currentRow, (int8_t*)&pRes->v);
23,007,324✔
842
        break;
23,006,820✔
843
      case TSDB_DATA_TYPE_DOUBLE:
39,337,488✔
844
        colDataSetDouble(pCol, currentRow, (double*)&pRes->v);
39,337,488✔
845
        break;
39,364,276✔
846
      case TSDB_DATA_TYPE_FLOAT: {
19,777,770✔
847
        float v = GET_FLOAT_VAL(&pRes->v);
19,777,770✔
848
        colDataSetFloat(pCol, currentRow, &v);
19,777,770✔
849
        break;
19,777,770✔
850
      }
851
      case TSDB_DATA_TYPE_VARBINARY:
1,513,656✔
852
      case TSDB_DATA_TYPE_VARCHAR:
853
      case TSDB_DATA_TYPE_NCHAR: {
854
        code = colDataSetVal(pCol, currentRow, pRes->str, false);
1,513,656✔
855
        if (TSDB_CODE_SUCCESS != code) {
1,513,656!
856
          return code;
×
857
        }
858
        break;
1,513,656✔
859
      }
860
      case TSDB_DATA_TYPE_DECIMAL64:
11,126✔
861
        code = colDataSetVal(pCol, currentRow, (const char*)&pRes->v, false);
11,126✔
862
        break;
11,126✔
863
      case TSDB_DATA_TYPE_DECIMAL:
11,405✔
864
        code = colDataSetVal(pCol, currentRow, (void*)pRes->dec, false);
11,405✔
865
        break;
11,405✔
866
    }
867
  } else {
868
    colDataSetNULL(pCol, currentRow);
97,859,071!
869
  }
870

871
  if (IS_VAR_DATA_TYPE(pCol->info.type)) taosMemoryFreeClear(pRes->str);
562,788,633!
872
  if (pCtx->subsidiaries.num > 0) {
562,842,387✔
873
    if (pEntryInfo->numOfRes > 0) {
866,657✔
874
      code = setSelectivityValue(pCtx, pBlock, &pRes->tuplePos, currentRow);
727,250✔
875
    } else {
876
      code = setNullSelectivityValue(pCtx, pBlock, currentRow);
139,407✔
877
    }
878
  }
879

880
  return code;
562,817,805✔
881
}
882

883
int32_t setNullSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t rowIndex) {
1,641,700,093✔
884
  if (pCtx->subsidiaries.num <= 0) {
1,641,700,093✔
885
    return TSDB_CODE_SUCCESS;
1,641,544,879✔
886
  }
887

888
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
535,980✔
889
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
335,894✔
890
    int32_t         dstSlotId = pc->pExpr->base.resSchema.slotId;
335,894✔
891

892
    SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
335,894✔
893
    if (NULL == pDstCol) {
335,894!
894
      return terrno;
×
895
    }
896
    colDataSetNULL(pDstCol, rowIndex);
335,894!
897
  }
898

899
  return TSDB_CODE_SUCCESS;
200,086✔
900
}
901

902
int32_t setSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, const STuplePos* pTuplePos, int32_t rowIndex) {
2,147,483,647✔
903
  if (pCtx->subsidiaries.num <= 0) {
2,147,483,647✔
904
    return TSDB_CODE_SUCCESS;
2,147,483,647✔
905
  }
906

907
  if ((pCtx->saveHandle.pBuf != NULL && pTuplePos->pageId != -1) ||
68,591,113!
UNCOV
908
      (pCtx->saveHandle.pState && pTuplePos->streamTupleKey.ts > 0)) {
×
909
    int32_t numOfCols = pCtx->subsidiaries.num;
68,589,849✔
910
    char*   p = NULL;
68,589,217✔
911
    int32_t code = loadTupleData(pCtx, pTuplePos, &p);
68,587,947✔
912
    if (p == NULL || TSDB_CODE_SUCCESS != code) {
68,585,422!
913
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
×
914
             pTuplePos->streamTupleKey.groupId, pTuplePos->streamTupleKey.ts);
915
      return TSDB_CODE_NOT_FOUND;
×
916
    }
917

918
    bool* nullList = (bool*)p;
68,588,585✔
919
    char* pStart = (char*)(nullList + numOfCols * sizeof(bool));
68,588,585✔
920

921
    // todo set the offset value to optimize the performance.
922
    for (int32_t j = 0; j < numOfCols; ++j) {
235,403,954✔
923
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
166,814,111✔
924
      int32_t         dstSlotId = pc->pExpr->base.resSchema.slotId;
166,810,940✔
925

926
      SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
166,814,102✔
927
      if (NULL == pDstCol) {
166,808,411!
928
        return terrno;
×
929
      }
930
      if (nullList[j]) {
166,808,411!
931
        colDataSetNULL(pDstCol, rowIndex);
57,098,677!
932
      } else {
933
        code = colDataSetValOrCover(pDstCol, rowIndex, pStart, false);
109,710,367✔
934
        if (TSDB_CODE_SUCCESS != code) {
109,716,064!
935
          return code;
×
936
        }
937
      }
938
      pStart += pDstCol->info.bytes;
166,814,741✔
939
    }
940
  }
941

942
  return TSDB_CODE_SUCCESS;
68,589,211✔
943
}
944

945
// This function append the selectivity to subsidiaries function context directly, without fetching data
946
// from intermediate disk based buf page
947
int32_t appendSelectivityValue(SqlFunctionCtx* pCtx, int32_t rowIndex, int32_t pos) {
268,230✔
948
  if (pCtx->subsidiaries.num <= 0) {
268,230!
949
    return TSDB_CODE_SUCCESS;
×
950
  }
951

952
  int32_t code = TSDB_CODE_SUCCESS;
268,230✔
953
  for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
918,846✔
954
    SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
650,616✔
955

956
    // get data from source col
957
    SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
650,616✔
958
    int32_t      srcSlotId = pFuncParam->pCol->slotId;
650,616✔
959

960
    SColumnInfoData* pSrcCol = taosArrayGet(pCtx->pSrcBlock->pDataBlock, srcSlotId);
650,616✔
961
    if (NULL == pSrcCol) {
650,616!
962
      return TSDB_CODE_OUT_OF_RANGE;
×
963
    }
964

965
    char* pData = colDataGetData(pSrcCol, rowIndex);
650,616!
966

967
    // append to dest col
968
    int32_t dstSlotId = pc->pExpr->base.resSchema.slotId;
650,616✔
969

970
    SColumnInfoData* pDstCol = taosArrayGet(pCtx->pDstBlock->pDataBlock, dstSlotId);
650,616✔
971
    if (NULL == pDstCol) {
650,616!
972
      return TSDB_CODE_OUT_OF_RANGE;
×
973
    }
974

975
    if (colDataIsNull_s(pSrcCol, rowIndex) == true) {
1,301,232!
976
      colDataSetNULL(pDstCol, pos);
75,720!
977
    } else {
978
      code = colDataSetVal(pDstCol, pos, pData, false);
574,896✔
979
      if (TSDB_CODE_SUCCESS != code) {
574,896!
980
        return code;
×
981
      }
982
    }
983
  }
984
  return code;
268,230✔
985
}
986

987
void replaceTupleData(STuplePos* pDestPos, STuplePos* pSourcePos) { *pDestPos = *pSourcePos; }
×
988

989
#define COMPARE_MINMAX_DATA(type) (((*(type*)&pDBuf->v) < (*(type*)&pSBuf->v)) ^ isMinFunc)
990
int32_t minMaxCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx, int32_t isMinFunc) {
×
991
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
992
  SMinmaxResInfo*      pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
993

994
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
995
  SMinmaxResInfo*      pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
996
  int16_t              type = pDBuf->type == TSDB_DATA_TYPE_NULL ? pSBuf->type : pDBuf->type;
×
997

998
  switch (type) {
×
999
    case TSDB_DATA_TYPE_UBIGINT:
×
1000
    case TSDB_DATA_TYPE_BIGINT:
1001
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int64_t) || !pDBuf->assign)) {
×
1002
        pDBuf->v = pSBuf->v;
×
1003
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1004
        pDBuf->assign = true;
×
1005
      }
1006
      break;
×
1007
    case TSDB_DATA_TYPE_UINT:
×
1008
    case TSDB_DATA_TYPE_INT:
1009
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int32_t) || !pDBuf->assign)) {
×
1010
        pDBuf->v = pSBuf->v;
×
1011
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1012
        pDBuf->assign = true;
×
1013
      }
1014
      break;
×
1015
    case TSDB_DATA_TYPE_USMALLINT:
×
1016
    case TSDB_DATA_TYPE_SMALLINT:
1017
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int16_t) || !pDBuf->assign)) {
×
1018
        pDBuf->v = pSBuf->v;
×
1019
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1020
        pDBuf->assign = true;
×
1021
      }
1022
      break;
×
1023
    case TSDB_DATA_TYPE_BOOL:
×
1024
    case TSDB_DATA_TYPE_UTINYINT:
1025
    case TSDB_DATA_TYPE_TINYINT:
1026
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(int8_t) || !pDBuf->assign)) {
×
1027
        pDBuf->v = pSBuf->v;
×
1028
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1029
        pDBuf->assign = true;
×
1030
      }
1031
      break;
×
1032
    case TSDB_DATA_TYPE_DOUBLE:
×
1033
    case TSDB_DATA_TYPE_FLOAT: {
1034
      if (pSBuf->assign && (COMPARE_MINMAX_DATA(double) || !pDBuf->assign)) {
×
1035
        pDBuf->v = pSBuf->v;
×
1036
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1037
        pDBuf->assign = true;
×
1038
      }
1039
      break;
×
1040
    }
1041
    case TSDB_DATA_TYPE_DECIMAL64: {
×
1042
      const SDecimalOps* pOps = getDecimalOps(type);
×
1043
      if (pSBuf->assign &&
×
1044
          ((pOps->lt(&pDBuf->v, &pSBuf->v, DECIMAL_WORD_NUM(Decimal64)) ^ isMinFunc) || !pDBuf->assign)) {
×
1045
        pDBuf->v = pSBuf->v;
×
1046
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1047
        pDBuf->assign = true;
×
1048
      }
1049
    } break;
×
1050
    case TSDB_DATA_TYPE_DECIMAL: {
×
1051
      const SDecimalOps* pOps = getDecimalOps(type);
×
1052
      if (pSBuf->assign && (pOps->lt(pDBuf->dec, pSBuf->dec, DECIMAL_WORD_NUM(Decimal)) ^ isMinFunc) ||
×
1053
          !pDBuf->assign) {
×
1054
        memcpy(pDBuf->dec, pSBuf->dec, DECIMAL128_BYTES);
×
1055
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1056
        pDBuf->assign = true;
×
1057
      }
1058
    } break;
×
1059
    default:
×
1060
      if (pSBuf->assign && (strcmp(pDBuf->str, pSBuf->str) || !pDBuf->assign)) {
×
1061
        memcpy(pDBuf->str, pSBuf->str, varDataLen(pSBuf->str));
×
1062
        replaceTupleData(&pDBuf->tuplePos, &pSBuf->tuplePos);
×
1063
        pDBuf->assign = true;
×
1064
      }
1065
      break;
×
1066
  }
1067
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
1068
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
1069
  return TSDB_CODE_SUCCESS;
×
1070
}
1071

1072
int32_t minCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
1073
  return minMaxCombine(pDestCtx, pSourceCtx, 1);
×
1074
}
1075
int32_t maxCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
1076
  return minMaxCombine(pDestCtx, pSourceCtx, 0);
×
1077
}
1078

1079
int32_t getStdInfoSize() { return (int32_t)sizeof(SStdRes); }
28,952,560✔
1080

1081
bool getStdFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
1,946,410✔
1082
  pEnv->calcMemSize = sizeof(SStdRes);
1,946,410✔
1083
  return true;
1,947,324✔
1084
}
1085

1086
int32_t stdFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
117,595,324✔
1087
  if (pResultInfo->initialized) {
117,595,324!
1088
    return TSDB_CODE_SUCCESS;
×
1089
  }
1090
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
117,595,781!
1091
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1092
  }
1093

1094
  SStdRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
117,596,430✔
1095
  (void)memset(pRes, 0, sizeof(SStdRes));
117,597,090!
1096
  return TSDB_CODE_SUCCESS;
117,597,090✔
1097
}
1098

1099
int32_t stdFunction(SqlFunctionCtx* pCtx) {
91,692,061✔
1100
  int32_t numOfElem = 0;
91,692,061✔
1101

1102
  // Only the pre-computing information loaded and actual data does not loaded
1103
  SInputColumnInfoData* pInput = &pCtx->input;
91,692,061✔
1104
  int32_t               type = pInput->pData[0]->info.type;
91,692,295✔
1105

1106
  SStdRes* pStdRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
91,694,081✔
1107
  pStdRes->type = type;
91,691,818✔
1108

1109
  // computing based on the true data block
1110
  SColumnInfoData* pCol = pInput->pData[0];
91,690,946✔
1111

1112
  int32_t start = pInput->startRowIndex;
91,693,858✔
1113
  int32_t numOfRows = pInput->numOfRows;
91,692,933✔
1114

1115
  if (IS_NULL_TYPE(type)) {
91,689,374✔
1116
    numOfElem = 0;
119,382✔
1117
    goto _stddev_over;
119,382✔
1118
  }
1119

1120
  switch (type) {
91,569,992!
1121
    case TSDB_DATA_TYPE_TINYINT: {
408,306✔
1122
      int8_t* plist = (int8_t*)pCol->pData;
408,306✔
1123
      for (int32_t i = start; i < numOfRows + start; ++i) {
29,670,986✔
1124
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
29,262,680!
1125
          continue;
848,825✔
1126
        }
1127

1128
        numOfElem += 1;
28,413,855✔
1129
        pStdRes->count += 1;
28,413,855✔
1130
        double nr = (double)plist[i];
28,413,855✔
1131
        if (pStdRes->count == 1) {
28,413,855✔
1132
          pStdRes->dsum = nr;
234,396✔
1133
        } else {
1134
          double          s_kminusone = pStdRes->dsum;
28,179,459✔
1135
          volatile double diff = nr - s_kminusone;
28,179,459✔
1136
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
28,179,459!
1137
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
28,179,459✔
1138
        }
1139
      }
1140

1141
      break;
408,306✔
1142
    }
1143

1144
    case TSDB_DATA_TYPE_SMALLINT: {
53,067,304✔
1145
      int16_t* plist = (int16_t*)pCol->pData;
53,067,304✔
1146
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
152,195,507✔
1147
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
99,127,969!
1148
          continue;
1,398,757✔
1149
        }
1150

1151
        numOfElem += 1;
97,726,638✔
1152
        pStdRes->count += 1;
97,726,638✔
1153
        double nr = (double)plist[i];
97,722,426✔
1154
        if (pStdRes->count == 1) {
97,723,362✔
1155
          pStdRes->dsum = nr;
52,292,365✔
1156
        } else {
1157
          double          s_kminusone = pStdRes->dsum;
45,430,997✔
1158
          volatile double diff = nr - s_kminusone;
45,430,997✔
1159
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
45,430,997!
1160
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
45,431,231✔
1161
        }
1162
      }
1163
      break;
53,067,304✔
1164
    }
1165

1166
    case TSDB_DATA_TYPE_INT: {
18,195,876✔
1167
      int32_t* plist = (int32_t*)pCol->pData;
18,195,876✔
1168
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
2,147,483,647✔
1169
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,147,483,647!
1170
          continue;
4,892,673✔
1171
        }
1172

1173
        numOfElem += 1;
2,147,483,647✔
1174
        pStdRes->count += 1;
2,147,483,647✔
1175
        double nr = (double)plist[i];
2,147,483,647✔
1176
        if (pStdRes->count == 1) {
2,147,483,647✔
1177
          pStdRes->dsum = nr;
16,494,939✔
1178
        } else {
1179
          double          s_kminusone = pStdRes->dsum;
2,147,483,647✔
1180
          volatile double diff = nr - s_kminusone;
2,147,483,647✔
1181
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
2,147,483,647!
1182
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
2,147,483,647✔
1183
        }
1184
      }
1185

1186
      break;
18,195,876✔
1187
    }
1188

1189
    case TSDB_DATA_TYPE_BIGINT: {
1,789,081✔
1190
      int64_t* plist = (int64_t*)pCol->pData;
1,789,081✔
1191
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
92,574,361✔
1192
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
90,786,651!
1193
          continue;
17,067,947✔
1194
        }
1195

1196
        numOfElem += 1;
73,714,902✔
1197
        pStdRes->count += 1;
73,714,902✔
1198
        double nr = (double)plist[i];
73,714,891✔
1199
        if (pStdRes->count == 1) {
73,716,953✔
1200
          pStdRes->dsum = nr;
1,091,388✔
1201
        } else {
1202
          double          s_kminusone = pStdRes->dsum;
72,624,852✔
1203
          volatile double diff = nr - s_kminusone;
72,626,881✔
1204
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
72,626,881!
1205
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
72,621,510✔
1206
        }
1207
      }
1208
      break;
1,791,088✔
1209
    }
1210

1211
    case TSDB_DATA_TYPE_UTINYINT: {
9,272✔
1212
      uint8_t* plist = (uint8_t*)pCol->pData;
9,272✔
1213
      for (int32_t i = start; i < numOfRows + start; ++i) {
25,821,970✔
1214
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
25,812,698!
1215
          continue;
3,496✔
1216
        }
1217

1218
        numOfElem += 1;
25,809,202✔
1219
        pStdRes->count += 1;
25,809,202✔
1220
        double nr = (double)plist[i];
25,809,202✔
1221
        if (pStdRes->count == 1) {
25,809,202✔
1222
          pStdRes->dsum = nr;
2,177✔
1223
        } else {
1224
          double          s_kminusone = pStdRes->dsum;
25,807,025✔
1225
          volatile double diff = nr - s_kminusone;
25,807,025✔
1226
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
25,807,025!
1227
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
25,807,025✔
1228
        }
1229
      }
1230

1231
      break;
9,272✔
1232
    }
1233

1234
    case TSDB_DATA_TYPE_USMALLINT: {
9,490✔
1235
      uint16_t* plist = (uint16_t*)pCol->pData;
9,490✔
1236
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
25,953,662✔
1237
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
25,944,172!
1238
          continue;
×
1239
        }
1240

1241
        numOfElem += 1;
25,944,172✔
1242
        pStdRes->count += 1;
25,944,172✔
1243
        double nr = (double)plist[i];
25,944,172✔
1244
        if (pStdRes->count == 1) {
25,944,172✔
1245
          pStdRes->dsum = nr;
2,395✔
1246
        } else {
1247
          double          s_kminusone = pStdRes->dsum;
25,941,777✔
1248
          volatile double diff = nr - s_kminusone;
25,941,777✔
1249
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
25,941,777!
1250
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
25,941,777✔
1251
        }
1252
      }
1253
      break;
9,490✔
1254
    }
1255

1256
    case TSDB_DATA_TYPE_UINT: {
9,016✔
1257
      uint32_t* plist = (uint32_t*)pCol->pData;
9,016✔
1258
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
25,818,686✔
1259
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
25,809,670!
1260
          continue;
×
1261
        }
1262

1263
        numOfElem += 1;
25,809,670✔
1264
        pStdRes->count += 1;
25,809,670✔
1265
        double nr = (double)plist[i];
25,809,670✔
1266
        if (pStdRes->count == 1) {
25,809,670✔
1267
          pStdRes->dsum = nr;
1,921✔
1268
        } else {
1269
          double          s_kminusone = pStdRes->dsum;
25,807,749✔
1270
          volatile double diff = nr - s_kminusone;
25,807,749✔
1271
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
25,807,749!
1272
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
25,807,749✔
1273
        }
1274
      }
1275

1276
      break;
9,016✔
1277
    }
1278

1279
    case TSDB_DATA_TYPE_UBIGINT: {
8,398✔
1280
      uint64_t* plist = (uint64_t*)pCol->pData;
8,398✔
1281
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
25,814,978✔
1282
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
25,806,580!
1283
          continue;
×
1284
        }
1285

1286
        numOfElem += 1;
25,806,580✔
1287
        pStdRes->count += 1;
25,806,580✔
1288
        double nr = (double)plist[i];
25,806,580✔
1289
        if (pStdRes->count == 1) {
25,806,580✔
1290
          pStdRes->dsum = nr;
1,303✔
1291
        } else {
1292
          double          s_kminusone = pStdRes->dsum;
25,805,277✔
1293
          volatile double diff = nr - s_kminusone;
25,805,277✔
1294
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
25,805,277!
1295
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
25,805,277✔
1296
        }
1297
      }
1298
      break;
8,398✔
1299
    }
1300

1301
    case TSDB_DATA_TYPE_FLOAT: {
15,750,388✔
1302
      float* plist = (float*)pCol->pData;
15,750,388✔
1303
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
2,147,483,647✔
1304
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
2,147,483,647!
1305
          continue;
678,377✔
1306
        }
1307

1308
        numOfElem += 1;
2,147,483,647✔
1309
        pStdRes->count += 1;
2,147,483,647✔
1310
        double nr = (double)plist[i];
2,147,483,647✔
1311
        if (pStdRes->count == 1) {
2,147,483,647✔
1312
          pStdRes->dsum = nr;
14,633,756✔
1313
        } else {
1314
          double          s_kminusone = pStdRes->dsum;
2,147,483,647✔
1315
          volatile double diff = nr - s_kminusone;
2,147,483,647✔
1316
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
2,147,483,647!
1317
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
2,147,483,647✔
1318
        }
1319
      }
1320
      break;
15,751,048✔
1321
    }
1322

1323
    case TSDB_DATA_TYPE_DOUBLE: {
2,322,861✔
1324
      double* plist = (double*)pCol->pData;
2,322,861✔
1325
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
129,066,202✔
1326
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
126,770,766!
1327
          continue;
33,945,945✔
1328
        }
1329

1330
        numOfElem += 1;
92,822,960✔
1331
        pStdRes->count += 1;
92,822,960✔
1332
        double nr = (double)plist[i];
92,815,962✔
1333
        if (pStdRes->count == 1) {
92,818,982✔
1334
          pStdRes->dsum = nr;
1,230,423✔
1335
        } else {
1336
          double          s_kminusone = pStdRes->dsum;
91,587,846✔
1337
          volatile double diff = nr - s_kminusone;
91,589,707✔
1338
          pStdRes->dsum = s_kminusone + diff / (double)pStdRes->count;
91,589,707!
1339
          pStdRes->quadraticDSum += diff * (nr - pStdRes->dsum);
91,585,740✔
1340
        }
1341
      }
1342
      break;
2,324,912✔
1343
    }
1344

1345
    default:
×
1346
      break;
×
1347
  }
1348

1349
_stddev_over:
91,694,092✔
1350
  // data in the check operation are all null, not output
1351
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
91,694,092✔
1352
  return TSDB_CODE_SUCCESS;
91,692,741✔
1353
}
1354

1355
static void stdTransferInfo(SStdRes* pInput, SStdRes* pOutput) {
28,827,774✔
1356
  if (IS_NULL_TYPE(pInput->type)) {
28,827,774✔
1357
    return;
17,274✔
1358
  }
1359
  pOutput->type = pInput->type;
28,810,500✔
1360
  if (pOutput->count == 0) {
28,810,500✔
1361
    pOutput->quadraticDSum += pInput->quadraticDSum;
28,780,133✔
1362
    pOutput->dsum += pInput->dsum;
28,780,133✔
1363
    pOutput->count = pInput->count;
28,780,133✔
1364
  } else if (pInput->count > 0) {
30,367!
1365
    double totalCount = pOutput->count + pInput->count;
30,367✔
1366
    double totalSum = pInput->count * pInput->dsum + pOutput->count * pOutput->dsum;
30,367✔
1367
    double mean = totalSum / totalCount;
30,367!
1368

1369
    /*
1370
    pOutput->quadraticDSum += pInput->quadraticDSum + pInput->count * pInput->dsum * pInput->dsum +
1371
                              pOutput->count * pOutput->dsum * pOutput->dsum - totalSum * mean;
1372
    */
1373

1374
    double diff = pInput->dsum - pOutput->dsum;
30,367✔
1375
    pOutput->quadraticDSum += pInput->quadraticDSum + pInput->count * pOutput->count * (diff * diff) / totalCount;
30,367!
1376
    pOutput->dsum = mean;
30,367✔
1377
    pOutput->count += pInput->count;
30,367✔
1378
  }
1379
}
1380

1381
int32_t stdFunctionMerge(SqlFunctionCtx* pCtx) {
28,827,569✔
1382
  SInputColumnInfoData* pInput = &pCtx->input;
28,827,569✔
1383
  SColumnInfoData*      pCol = pInput->pData[0];
28,827,569✔
1384

1385
  if (IS_NULL_TYPE(pCol->info.type)) {
28,827,569!
1386
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
1387
    return TSDB_CODE_SUCCESS;
×
1388
  }
1389

1390
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
28,827,569!
1391
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
1392
  }
1393

1394
  SStdRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
28,827,569✔
1395

1396
  for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
57,655,343✔
1397
    if (colDataIsNull_s(pCol, i)) continue;
57,655,548!
1398
    char*    data = colDataGetData(pCol, i);
28,827,774!
1399
    SStdRes* pInputInfo = (SStdRes*)varDataVal(data);
28,827,774✔
1400
    stdTransferInfo(pInputInfo, pInfo);
28,827,774✔
1401
  }
1402

1403
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
28,827,569✔
1404
  return TSDB_CODE_SUCCESS;
28,827,569✔
1405
}
1406

1407
int32_t stddevFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
58,721,596✔
1408
  SInputColumnInfoData* pInput = &pCtx->input;
58,721,596✔
1409
  SStdRes*              pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
58,721,830✔
1410
  int32_t               type = pStddevRes->type;
58,721,596✔
1411
  double                avg;
1412

1413
  if (pStddevRes->count == 0) {
58,722,064✔
1414
    GET_RES_INFO(pCtx)->numOfRes = 0;
2,440,484✔
1415
    return functionFinalize(pCtx, pBlock);
2,440,707✔
1416
  }
1417

1418
  if (pStddevRes->count == 1) {
56,280,432✔
1419
    pStddevRes->result = 0.0;
46,894,810✔
1420
  } else {
1421
    pStddevRes->result = sqrt(pStddevRes->quadraticDSum / pStddevRes->count);
9,386,079!
1422
  }
1423

1424
  // check for overflow
1425
  if (isinf(pStddevRes->result) || isnan(pStddevRes->result)) {
56,280,655!
1426
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1427
  }
1428

1429
  return functionFinalize(pCtx, pBlock);
56,280,889✔
1430
}
1431

1432
int32_t stdvarFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
12,046,901✔
1433
  SInputColumnInfoData* pInput = &pCtx->input;
12,046,901✔
1434
  SStdRes*              pStdvarRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
12,046,901✔
1435
  int32_t               type = pStdvarRes->type;
12,046,901✔
1436
  double                avg;
1437

1438
  if (pStdvarRes->count == 0) {
12,046,901✔
1439
    GET_RES_INFO(pCtx)->numOfRes = 0;
1,727✔
1440
    return functionFinalize(pCtx, pBlock);
1,727✔
1441
  }
1442

1443
  if (pStdvarRes->count == 1) {
12,045,174✔
1444
    pStdvarRes->result = 0.0;
1,727✔
1445
  } else {
1446
    pStdvarRes->result = pStdvarRes->quadraticDSum / pStdvarRes->count;
12,043,447!
1447
  }
1448

1449
  // check for overflow
1450
  if (isinf(pStdvarRes->result) || isnan(pStdvarRes->result)) {
12,045,174!
1451
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1452
  }
1453

1454
  return functionFinalize(pCtx, pBlock);
12,045,174✔
1455
}
1456

1457
int32_t stdPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
28,827,774✔
1458
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
28,827,774✔
1459
  SStdRes*             pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
28,827,774✔
1460
  int32_t              resultBytes = getStdInfoSize();
28,827,774✔
1461
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
28,827,774!
1462

1463
  if (NULL == res) {
28,827,774!
1464
    return terrno;
×
1465
  }
1466
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
28,827,774!
1467
  varDataSetLen(res, resultBytes);
28,827,774✔
1468

1469
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
28,827,774✔
1470
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
28,827,774✔
1471
  if (NULL == pCol) {
28,827,774!
1472
    taosMemoryFree(res);
×
1473
    return TSDB_CODE_OUT_OF_RANGE;
×
1474
  }
1475

1476
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
28,827,774✔
1477

1478
  taosMemoryFree(res);
28,827,774!
1479
  return code;
28,827,774✔
1480
}
1481

1482
int32_t stdCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
1483
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
1484
  SStdRes*             pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
1485

1486
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
1487
  SStdRes*             pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
1488
  int16_t              type = pDBuf->type == TSDB_DATA_TYPE_NULL ? pSBuf->type : pDBuf->type;
×
1489

1490
  stdTransferInfo(pSBuf, pDBuf);
×
1491

1492
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
1493
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
1494
  return TSDB_CODE_SUCCESS;
×
1495
}
1496

1497
int32_t stddevsampFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
4,604,160✔
1498
  SInputColumnInfoData* pInput = &pCtx->input;
4,604,160✔
1499
  SStdRes*              pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4,604,160✔
1500
  double                avg;
1501

1502
  if (pStddevRes->count == 0) {
4,604,160✔
1503
    GET_RES_INFO(pCtx)->numOfRes = 0;
660✔
1504
    return functionFinalize(pCtx, pBlock);
660✔
1505
  }
1506

1507
  if (pStddevRes->count == 1) {
4,603,500✔
1508
    pStddevRes->result = 0.0;
660✔
1509
  } else {
1510
    pStddevRes->result = sqrt(pStddevRes->quadraticDSum / (pStddevRes->count - 1));
4,602,840!
1511
  }
1512

1513
  // check for overflow
1514
  if (isinf(pStddevRes->result) || isnan(pStddevRes->result)) {
4,603,500!
1515
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1516
  }
1517

1518
  return functionFinalize(pCtx, pBlock);
4,603,500✔
1519
}
1520

1521
int32_t stdvarsampFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
4,602,840✔
1522
  SInputColumnInfoData* pInput = &pCtx->input;
4,602,840✔
1523
  SStdRes*              pStddevRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
4,602,840✔
1524
  double                avg;
1525

1526
  if (pStddevRes->count == 0) {
4,602,840✔
1527
    GET_RES_INFO(pCtx)->numOfRes = 0;
660✔
1528
    return functionFinalize(pCtx, pBlock);
660✔
1529
  }
1530

1531
  if (pStddevRes->count == 1) {
4,602,180✔
1532
    pStddevRes->result = 0.0;
660✔
1533
  } else {
1534
    pStddevRes->result = pStddevRes->quadraticDSum / (pStddevRes->count - 1);
4,601,520!
1535
  }
1536

1537
  // check for overflow
1538
  if (isinf(pStddevRes->result) || isnan(pStddevRes->result)) {
4,602,180!
1539
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
1540
  }
1541

1542
  return functionFinalize(pCtx, pBlock);
4,602,180✔
1543
}
1544

1545
bool gconcatGetFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
1,321✔
1546
  pEnv->calcMemSize = sizeof(SGconcatRes);
1,321✔
1547
  return true;
1,321✔
1548
}
1549

1550
int32_t gconcatFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
1,321✔
1551
  if (pResultInfo->initialized) {
1,321!
1552
    return TSDB_CODE_SUCCESS;
×
1553
  }
1554
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
1,321!
1555
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1556
  }
1557

1558
  SGconcatRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
1,321✔
1559
  (void)memset(pRes, 0, sizeof(SStdRes));
1,321!
1560

1561
  // pRes->separator = varDataVal(pCtx->param[0].param.pz);
1562

1563
  int32_t sepParamIdx = pCtx->numOfParams - 1;
1,321✔
1564
  pRes->separator = pCtx->param[sepParamIdx].param.pz;
1,321✔
1565
  pRes->type = pCtx->param[sepParamIdx].param.nType;
1,321✔
1566

1567
  /*
1568
  SInputColumnInfoData* pInput = &pCtx->input;
1569
  int32_t               type = pInput->pData[0]->info.type;
1570

1571
  pRes->nchar = (type == TSDB_DATA_TYPE_NCHAR);
1572
  */
1573

1574
  return TSDB_CODE_SUCCESS;
1,321✔
1575
}
1576

1577
static int32_t gconcatHelper(const char* input, char* output, bool hasNchar, int32_t type, VarDataLenT* dataLen,
25,099✔
1578
                             void* charsetCxt) {
1579
  if (hasNchar && type == TSDB_DATA_TYPE_VARCHAR) {
25,099!
1580
    TdUcs4* newBuf = taosMemoryCalloc((varDataLen(input) + 1) * TSDB_NCHAR_SIZE, 1);
×
1581
    if (NULL == newBuf) {
×
1582
      return terrno;
×
1583
    }
1584
    int32_t len = varDataLen(input);
×
1585
    bool    ret =
1586
        taosMbsToUcs4(varDataVal(input), len, newBuf, (varDataLen(input) + 1) * TSDB_NCHAR_SIZE, &len, charsetCxt);
×
1587
    if (!ret) {
×
1588
      taosMemoryFree(newBuf);
×
1589
      return TSDB_CODE_SCALAR_CONVERT_ERROR;
×
1590
    }
1591
    (void)memcpy(varDataVal(output) + *dataLen, newBuf, len);
×
1592
    *dataLen += len;
×
1593
    taosMemoryFree(newBuf);
×
1594
  } else {
1595
    (void)memcpy(varDataVal(output) + *dataLen, varDataVal(input), varDataLen(input));
25,099!
1596
    *dataLen += varDataLen(input);
25,099✔
1597
  }
1598

1599
  return TSDB_CODE_SUCCESS;
25,099✔
1600
}
1601

1602
int32_t gconcatFunction(SqlFunctionCtx* pCtx) {
1,321✔
1603
  int32_t               code = 0, numOfElem = 0;
1,321✔
1604
  SInputColumnInfoData* pInput = &pCtx->input;
1,321✔
1605
  int32_t               rowStart = pInput->startRowIndex;
1,321✔
1606
  int32_t               numOfRows = pInput->numOfRows;
1,321✔
1607
  int32_t               numOfCols = pInput->numOfInputCols;
1,321✔
1608
  SGconcatRes*          pRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,321✔
1609
  char*                 sep = pRes->separator;
1,321✔
1610
  bool                  hasNchar = pRes->nchar;
1,321!
1611
  VarDataLenT           dataLen = 0;
1,321✔
1612
  bool                  prefixSep = false;
1,321✔
1613

1614
  if (!pRes->result) {
1,321!
1615
    pRes->result = taosMemoryCalloc(1, TSDB_MAX_FIELD_LEN);
1,321!
1616
    if (!pRes->result) {
1,321!
1617
      return terrno;
×
1618
    }
1619

1620
    varDataSetLen(pRes->result, 0);
1,321✔
1621

1622
    for (int c = 0; c < numOfCols - 1; ++c) {
2,642✔
1623
      SColumnInfoData* pCol = pInput->pData[c];
1,321✔
1624
      int32_t          type = pCol->info.type;
1,321✔
1625

1626
      if (TSDB_DATA_TYPE_NCHAR == type) {
1,321!
1627
        pRes->nchar = true;
×
1628
      }
1629
    }
1630
  } else {
1631
    dataLen = varDataLen(pRes->result);
×
1632

1633
    prefixSep = true;
×
1634
    /*
1635
    code = gconcatHelper(sep, pRes->result, hasNchar, pRes->type, &dataLen, NULL);
1636
    if (code) {
1637
      goto _over;
1638
    }
1639
    */
1640
  }
1641

1642
  // computing based on the true data block
1643
  char*            buf = pRes->result;
1,321✔
1644
  SColumnInfoData* pCol = pInput->pData[numOfCols - 1];
1,321✔
1645

1646
  sep = colDataGetData(pCol, 0);
1,321!
1647
  pRes->type = pCol->info.type;
1,321✔
1648
  for (int r = rowStart; r < rowStart + numOfRows; ++r) {
14,531✔
1649
    if (prefixSep) {
13,210✔
1650
      // concat the separator
1651
      // setup sepatator's charset instead of the default: pRes->charsetCxt
1652

1653
      code = gconcatHelper(sep, buf, hasNchar, pRes->type, &dataLen, NULL);
11,889✔
1654
      if (code) {
11,889!
1655
        goto _over;
×
1656
      }
1657
    }
1658

1659
    for (int c = 0; c < numOfCols - 1; ++c) {
26,420✔
1660
      SColumnInfoData* pCol = pInput->pData[c];
13,210✔
1661
      int32_t          type = pCol->info.type;
13,210✔
1662

1663
      if (IS_NULL_TYPE(type) || (pCol->hasNull && colDataIsNull_f(pCol, r))) {
13,210!
1664
        continue;
×
1665
      }
1666

1667
      // concat this row's all columns
1668
      code = gconcatHelper(colDataGetData(pCol, r), buf, hasNchar, pInput->pData[c]->info.type, &dataLen, NULL);
13,210!
1669
      if (code) {
13,210!
1670
        goto _over;
×
1671
      }
1672
    }
1673

1674
    prefixSep = true;
13,210✔
1675
  }
1676

1677
  varDataSetLen(buf, dataLen);
1,321✔
1678
  numOfElem += 1;
1,321✔
1679

1680
_over:
1,321✔
1681
  // data in the check operation are all null, not output
1682
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
1,321!
1683
  return code;
1,321✔
1684
}
1685

1686
int32_t gconcatFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,321✔
1687
  int32_t               code = 0;
1,321✔
1688
  SInputColumnInfoData* pInput = &pCtx->input;
1,321✔
1689
  SGconcatRes*          pRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,321✔
1690
  int32_t               slotId = pCtx->pExpr->base.resSchema.slotId;
1,321✔
1691
  SColumnInfoData*      pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,321✔
1692

1693
  if (NULL == pCol) {
1,321!
1694
    taosMemoryFree(pRes->result);
×
1695
    return TSDB_CODE_OUT_OF_RANGE;
×
1696
  }
1697

1698
  code = colDataSetVal(pCol, pBlock->info.rows, pRes->result, NULL == pRes->result);
1,321✔
1699

1700
  taosMemoryFree(pRes->result);
1,321!
1701

1702
  return code;
1,321✔
1703
}
1704

1705
bool getLeastSQRFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
537,940✔
1706
  pEnv->calcMemSize = sizeof(SLeastSQRInfo);
537,940✔
1707
  return true;
538,408✔
1708
}
1709

1710
int32_t leastSQRFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
2,579,360✔
1711
  if (pResultInfo->initialized) {
2,579,360!
1712
    return TSDB_CODE_SUCCESS;
×
1713
  }
1714
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
2,579,360!
1715
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1716
  }
1717

1718
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
2,579,137✔
1719

1720
  GET_TYPED_DATA(pInfo->startVal, double, pCtx->param[1].param.nType, &pCtx->param[1].param.i,
2,579,360!
1721
                 typeGetTypeModFromCol(pCtx->param[1].pCol));
1722
  GET_TYPED_DATA(pInfo->stepVal, double, pCtx->param[2].param.nType, &pCtx->param[2].param.i,
2,579,360!
1723
                 typeGetTypeModFromCol(pCtx->param[2].pCol));
1724
  return TSDB_CODE_SUCCESS;
2,579,360✔
1725
}
1726

1727
int32_t leastSQRFunction(SqlFunctionCtx* pCtx) {
3,695,251✔
1728
  int32_t numOfElem = 0;
3,695,251✔
1729

1730
  SInputColumnInfoData* pInput = &pCtx->input;
3,695,251✔
1731
  int32_t               type = pInput->pData[0]->info.type;
3,695,251✔
1732

1733
  SLeastSQRInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
3,694,805✔
1734

1735
  SColumnInfoData* pCol = pInput->pData[0];
3,695,028✔
1736

1737
  double(*param)[3] = pInfo->matrix;
3,695,251✔
1738
  double x = pInfo->startVal;
3,694,794✔
1739

1740
  int32_t start = pInput->startRowIndex;
3,694,794✔
1741
  int32_t numOfRows = pInput->numOfRows;
3,695,251✔
1742

1743
  switch (type) {
3,694,805!
1744
    case TSDB_DATA_TYPE_TINYINT: {
195,104✔
1745
      int8_t* plist = (int8_t*)pCol->pData;
195,104✔
1746
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
26,405,420✔
1747
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
26,210,316!
1748
          continue;
140,832✔
1749
        }
1750
        numOfElem++;
26,069,484✔
1751
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
26,069,484✔
1752
      }
1753
      break;
195,104✔
1754
    }
1755
    case TSDB_DATA_TYPE_SMALLINT: {
363,839✔
1756
      int16_t* plist = (int16_t*)pCol->pData;
363,839✔
1757
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
58,376,363✔
1758
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
58,012,524!
1759
          continue;
56,532✔
1760
        }
1761

1762
        numOfElem++;
57,955,992✔
1763
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
57,955,992✔
1764
      }
1765
      break;
363,839✔
1766
    }
1767

1768
    case TSDB_DATA_TYPE_INT: {
384,150✔
1769
      int32_t* plist = (int32_t*)pCol->pData;
384,150✔
1770
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
90,207,430✔
1771
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
89,823,280!
1772
          continue;
202,163✔
1773
        }
1774

1775
        numOfElem++;
89,621,117✔
1776
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
89,621,117✔
1777
      }
1778
      break;
384,810✔
1779
    }
1780

1781
    case TSDB_DATA_TYPE_BIGINT: {
1,294,187✔
1782
      int64_t* plist = (int64_t*)pCol->pData;
1,294,187✔
1783
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
60,411,450✔
1784
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
59,117,486!
1785
          continue;
32,971,525✔
1786
        }
1787

1788
        numOfElem++;
26,146,853✔
1789
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
26,146,853✔
1790
      }
1791
      break;
1,294,410✔
1792
    }
1793

1794
    case TSDB_DATA_TYPE_UTINYINT: {
24,926✔
1795
      uint8_t* plist = (uint8_t*)pCol->pData;
24,926✔
1796
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
25,880,450✔
1797
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
25,855,524!
1798
          continue;
14,542✔
1799
        }
1800
        numOfElem++;
25,840,982✔
1801
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
25,840,982✔
1802
      }
1803
      break;
24,926✔
1804
    }
1805
    case TSDB_DATA_TYPE_USMALLINT: {
24,926✔
1806
      uint16_t* plist = (uint16_t*)pCol->pData;
24,926✔
1807
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
25,880,450✔
1808
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
25,855,524!
1809
          continue;
13,220✔
1810
        }
1811

1812
        numOfElem++;
25,842,304✔
1813
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
25,842,304✔
1814
      }
1815
      break;
24,926✔
1816
    }
1817

1818
    case TSDB_DATA_TYPE_UINT: {
24,926✔
1819
      uint32_t* plist = (uint32_t*)pCol->pData;
24,926✔
1820
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
25,880,450✔
1821
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
25,855,524!
1822
          continue;
13,220✔
1823
        }
1824

1825
        numOfElem++;
25,842,304✔
1826
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
25,842,304✔
1827
      }
1828
      break;
24,926✔
1829
    }
1830

1831
    case TSDB_DATA_TYPE_UBIGINT: {
24,926✔
1832
      uint64_t* plist = (uint64_t*)pCol->pData;
24,926✔
1833
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
25,880,450✔
1834
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
25,855,524!
1835
          continue;
13,220✔
1836
        }
1837

1838
        numOfElem++;
25,842,304✔
1839
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
25,842,304✔
1840
      }
1841
      break;
24,926✔
1842
    }
1843

1844
    case TSDB_DATA_TYPE_FLOAT: {
965,407✔
1845
      float* plist = (float*)pCol->pData;
965,407✔
1846
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
27,789,231✔
1847
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
26,823,824!
1848
          continue;
120,332✔
1849
        }
1850

1851
        numOfElem++;
26,703,492✔
1852
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
26,703,492✔
1853
      }
1854
      break;
965,407✔
1855
    }
1856

1857
    case TSDB_DATA_TYPE_DOUBLE: {
392,414✔
1858
      double* plist = (double*)pCol->pData;
392,414✔
1859
      for (int32_t i = start; i < numOfRows + pInput->startRowIndex; ++i) {
27,207,106✔
1860
        if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
26,814,692!
1861
          continue;
77,032✔
1862
        }
1863

1864
        numOfElem++;
26,737,660✔
1865
        LEASTSQR_CAL(param, x, plist, i, pInfo->stepVal);
26,737,660✔
1866
      }
1867
      break;
392,414✔
1868
    }
1869
    case TSDB_DATA_TYPE_NULL: {
×
1870
      GET_RES_INFO(pCtx)->isNullRes = 1;
×
1871
      numOfElem = 1;
×
1872
      break;
×
1873
    }
1874

1875
    default:
×
1876
      break;
×
1877
  }
1878

1879
  pInfo->startVal = x;
3,695,688✔
1880
  pInfo->num += numOfElem;
3,695,251✔
1881

1882
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
3,695,911✔
1883

1884
  return TSDB_CODE_SUCCESS;
3,695,688✔
1885
}
1886

1887
int32_t leastSQRFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,577,836✔
1888
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,577,836✔
1889
  SLeastSQRInfo*       pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
2,577,836✔
1890
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
2,577,836✔
1891
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,577,836✔
1892

1893
  if (NULL == pCol) {
2,577,836!
1894
    return TSDB_CODE_OUT_OF_RANGE;
×
1895
  }
1896
  int32_t currentRow = pBlock->info.rows;
2,577,836✔
1897

1898
  if (0 == pInfo->num) {
2,577,836✔
1899
    colDataSetNULL(pCol, currentRow);
1,540,080!
1900
    return TSDB_CODE_SUCCESS;
1,540,080✔
1901
  }
1902

1903
  double(*param)[3] = pInfo->matrix;
1,037,756✔
1904

1905
  param[1][1] = (double)pInfo->num;
1,037,756✔
1906
  param[1][0] = param[0][1];
1,037,756✔
1907

1908
  double param00 = param[0][0] - param[1][0] * (param[0][1] / param[1][1]);
1,037,756!
1909
  double param02 = param[0][2] - param[1][2] * (param[0][1] / param[1][1]);
1,037,756!
1910

1911
  if (0 == param00) {
1,037,756✔
1912
    colDataSetNULL(pCol, currentRow);
658,919!
1913
    return TSDB_CODE_SUCCESS;
658,919✔
1914
  }
1915

1916
  // param[0][1] = 0;
1917
  double param12 = param[1][2] - param02 * (param[1][0] / param00);
378,837!
1918
  // param[1][0] = 0;
1919
  param02 /= param00;
378,837!
1920

1921
  param12 /= param[1][1];
378,837!
1922

1923
  char buf[LEASTSQUARES_BUFF_LENGTH] = {0};
378,837✔
1924
  char slopBuf[64] = {0};
378,837✔
1925
  char interceptBuf[64] = {0};
378,837✔
1926
  int  n = tsnprintf(slopBuf, 64, "%.6lf", param02);
378,837✔
1927
  if (n > LEASTSQUARES_DOUBLE_ITEM_LENGTH) {
378,837✔
1928
    (void)snprintf(slopBuf, 64, "%." DOUBLE_PRECISION_DIGITS, param02);
1,322✔
1929
  }
1930
  n = tsnprintf(interceptBuf, 64, "%.6lf", param12);
378,837✔
1931
  if (n > LEASTSQUARES_DOUBLE_ITEM_LENGTH) {
378,837✔
1932
    (void)snprintf(interceptBuf, 64, "%." DOUBLE_PRECISION_DIGITS, param12);
2,644✔
1933
  }
1934
  size_t len =
378,837✔
1935
      snprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE, "{slop:%s, intercept:%s}", slopBuf, interceptBuf);
378,837✔
1936
  varDataSetLen(buf, len);
378,837✔
1937

1938
  int32_t code = colDataSetVal(pCol, currentRow, buf, pResInfo->isNullRes);
378,837✔
1939

1940
  return code;
378,837✔
1941
}
1942

1943
int32_t leastSQRCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
1944
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
1945
  SLeastSQRInfo*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
1946
  int32_t              type = pDestCtx->input.pData[0]->info.type;
×
1947
  double(*pDparam)[3] = pDBuf->matrix;
×
1948

1949
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
1950
  SLeastSQRInfo*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
1951
  double(*pSparam)[3] = pSBuf->matrix;
×
1952
  for (int32_t i = 0; i < pSBuf->num; i++) {
×
1953
    pDparam[0][0] += pDBuf->startVal * pDBuf->startVal;
×
1954
    pDparam[0][1] += pDBuf->startVal;
×
1955
    pDBuf->startVal += pDBuf->stepVal;
×
1956
  }
1957
  pDparam[0][2] += pSparam[0][2] + pDBuf->num * pDBuf->stepVal * pSparam[1][2];
×
1958
  pDparam[1][2] += pSparam[1][2];
×
1959
  pDBuf->num += pSBuf->num;
×
1960
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
1961
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
1962
  return TSDB_CODE_SUCCESS;
×
1963
}
1964

1965
bool getPercentileFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
129,926✔
1966
  pEnv->calcMemSize = sizeof(SPercentileInfo);
129,926✔
1967
  return true;
129,926✔
1968
}
1969

1970
int32_t percentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
379,262✔
1971
  if (pResultInfo->initialized) {
379,262!
1972
    return TSDB_CODE_SUCCESS;
×
1973
  }
1974
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
379,262!
1975
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
1976
  }
1977

1978
  // in the first round, get the min-max value of all involved data
1979
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
379,262✔
1980
  SET_DOUBLE_VAL(&pInfo->minval, DBL_MAX);
379,262✔
1981
  SET_DOUBLE_VAL(&pInfo->maxval, -DBL_MAX);
379,262✔
1982
  pInfo->numOfElems = 0;
379,262✔
1983

1984
  return TSDB_CODE_SUCCESS;
379,262✔
1985
}
1986

1987
void percentileFunctionCleanupExt(SqlFunctionCtx* pCtx) {
3,276✔
1988
  if (pCtx == NULL || GET_RES_INFO(pCtx) == NULL || GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)) == NULL) {
3,276!
1989
    return;
×
1990
  }
1991
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
3,276✔
1992
  if (pInfo->pMemBucket != NULL) {
3,276✔
1993
    tMemBucketDestroy(&(pInfo->pMemBucket));
1,092✔
1994
    pInfo->pMemBucket = NULL;
1,092✔
1995
  }
1996
}
1997

1998
int32_t percentileFunction(SqlFunctionCtx* pCtx) {
2,074,944✔
1999
  int32_t              code = TSDB_CODE_SUCCESS;
2,074,944✔
2000
  int32_t              numOfElems = 0;
2,074,944✔
2001
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,074,944✔
2002

2003
  SInputColumnInfoData* pInput = &pCtx->input;
2,074,944✔
2004
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
2,074,944✔
2005

2006
  SColumnInfoData* pCol = pInput->pData[0];
2,074,944✔
2007
  int32_t          type = pCol->info.type;
2,074,944✔
2008

2009
  SPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,074,944✔
2010
  if (pCtx->scanFlag == MAIN_SCAN && pInfo->stage == 0) {
2,074,944✔
2011
    pInfo->stage += 1;
379,262✔
2012

2013
    // all data are null, set it completed
2014
    if (pInfo->numOfElems == 0) {
379,262✔
2015
      pResInfo->complete = true;
63,685✔
2016
      return TSDB_CODE_SUCCESS;
63,685✔
2017
    } else {
2018
      code = tMemBucketCreate(pCol->info.bytes, type, typeGetTypeModFromColInfo(&pCol->info), pInfo->minval,
315,577✔
2019
                              pInfo->maxval, pCtx->hasWindowOrGroup, &pInfo->pMemBucket, pInfo->numOfElems);
315,577!
2020
      if (TSDB_CODE_SUCCESS != code) {
315,577!
2021
        return code;
×
2022
      }
2023
    }
2024
  }
2025

2026
  // the first stage, only acquire the min/max value
2027
  if (pInfo->stage == 0) {
2,011,259✔
2028
    if (pCtx->input.colDataSMAIsSet) {
1,040,282!
2029
      double tmin = 0.0, tmax = 0.0;
×
2030
      if (IS_SIGNED_NUMERIC_TYPE(type)) {
×
2031
        tmin = (double)GET_INT64_VAL(&pAgg->min);
×
2032
        tmax = (double)GET_INT64_VAL(&pAgg->max);
×
2033
      } else if (IS_FLOAT_TYPE(type)) {
×
2034
        tmin = GET_DOUBLE_VAL(&pAgg->min);
×
2035
        tmax = GET_DOUBLE_VAL(&pAgg->max);
×
2036
      } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
2037
        tmin = (double)GET_UINT64_VAL(&pAgg->min);
×
2038
        tmax = (double)GET_UINT64_VAL(&pAgg->max);
×
2039
      }
2040

2041
      if (GET_DOUBLE_VAL(&pInfo->minval) > tmin) {
×
2042
        SET_DOUBLE_VAL(&pInfo->minval, tmin);
×
2043
      }
2044

2045
      if (GET_DOUBLE_VAL(&pInfo->maxval) < tmax) {
×
2046
        SET_DOUBLE_VAL(&pInfo->maxval, tmax);
×
2047
      }
2048

2049
      pInfo->numOfElems += (pInput->numOfRows - pAgg->numOfNull);
×
2050
    } else {
2051
      // check the valid data one by one
2052
      int32_t start = pInput->startRowIndex;
1,040,282✔
2053
      for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
27,050,441✔
2054
        if (colDataIsNull_f(pCol, i)) {
26,010,159!
2055
          continue;
189,772✔
2056
        }
2057

2058
        char* data = colDataGetData(pCol, i);
25,820,387!
2059

2060
        double v = 0;
25,820,387✔
2061
        GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
25,820,387!
2062
        if (v < GET_DOUBLE_VAL(&pInfo->minval)) {
25,820,387✔
2063
          SET_DOUBLE_VAL(&pInfo->minval, v);
356,460✔
2064
        }
2065

2066
        if (v > GET_DOUBLE_VAL(&pInfo->maxval)) {
25,820,387✔
2067
          SET_DOUBLE_VAL(&pInfo->maxval, v);
20,552,511✔
2068
        }
2069

2070
        pInfo->numOfElems += 1;
25,820,387✔
2071
      }
2072
    }
2073
  } else {
2074
    // the second stage, calculate the true percentile value
2075
    int32_t start = pInput->startRowIndex;
970,977✔
2076
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
26,725,844✔
2077
      if (colDataIsNull_f(pCol, i)) {
25,755,959!
2078
        continue;
×
2079
      }
2080

2081
      char* data = colDataGetData(pCol, i);
25,755,959!
2082
      numOfElems += 1;
25,755,959✔
2083
      code = tMemBucketPut(pInfo->pMemBucket, data, 1);
25,755,959✔
2084
      if (code != TSDB_CODE_SUCCESS) {
25,755,959✔
2085
        tMemBucketDestroy(&(pInfo->pMemBucket));
1,092✔
2086
        return code;
1,092✔
2087
      }
2088
    }
2089

2090
    SET_VAL(pResInfo, numOfElems, 1);
969,885!
2091
  }
2092

2093
  pCtx->needCleanup = true;
2,010,167✔
2094
  return TSDB_CODE_SUCCESS;
2,010,167✔
2095
}
2096

2097
int32_t percentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
377,078✔
2098
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
377,078✔
2099
  SPercentileInfo*     ppInfo = (SPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
377,078✔
2100

2101
  int32_t code = 0;
377,078✔
2102
  double  v = 0;
377,078✔
2103

2104
  tMemBucket** pMemBucket = &ppInfo->pMemBucket;
377,078✔
2105
  if ((*pMemBucket) != NULL && (*pMemBucket)->total > 0) {  // check for null
377,078!
2106
    if (pCtx->numOfParams > 2) {
313,393✔
2107
      char buf[3200] = {0};
3,966✔
2108
      // max length of double num is 317, e.g. use %.6lf to print -1.0e+308, consider the comma and bracket, 3200 is
2109
      // enough.
2110
      size_t len = 1;
3,966✔
2111

2112
      varDataVal(buf)[0] = '[';
3,966✔
2113
      for (int32_t i = 1; i < pCtx->numOfParams; ++i) {
43,626✔
2114
        SVariant* pVal = &pCtx->param[i].param;
39,660✔
2115

2116
        GET_TYPED_DATA(v, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[i].pCol));
39,660!
2117

2118
        code = getPercentile((*pMemBucket), v, &ppInfo->result);
39,660✔
2119
        if (code != TSDB_CODE_SUCCESS) {
39,660!
2120
          goto _fin_error;
×
2121
        }
2122

2123
        if (i == pCtx->numOfParams - 1) {
39,660✔
2124
          len += tsnprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf]", ppInfo->result);
3,966✔
2125
        } else {
2126
          len += tsnprintf(varDataVal(buf) + len, sizeof(buf) - VARSTR_HEADER_SIZE - len, "%.6lf, ", ppInfo->result);
35,694✔
2127
        }
2128
      }
2129

2130
      int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
3,966✔
2131
      SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
3,966✔
2132
      if (NULL == pCol) {
3,966!
2133
        code = terrno;
×
2134
        goto _fin_error;
×
2135
      }
2136

2137
      varDataSetLen(buf, len);
3,966✔
2138
      code = colDataSetVal(pCol, pBlock->info.rows, buf, false);
3,966✔
2139
      if (code != TSDB_CODE_SUCCESS) {
3,966!
2140
        goto _fin_error;
×
2141
      }
2142

2143
      tMemBucketDestroy(pMemBucket);
3,966✔
2144
      return TSDB_CODE_SUCCESS;
3,966✔
2145
    } else {
2146
      SVariant* pVal = &pCtx->param[1].param;
309,427✔
2147

2148
      GET_TYPED_DATA(v, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[1].pCol));
309,427!
2149

2150
      code = getPercentile((*pMemBucket), v, &ppInfo->result);
309,427✔
2151
      if (code != TSDB_CODE_SUCCESS) {
309,427!
2152
        goto _fin_error;
×
2153
      }
2154

2155
      tMemBucketDestroy(pMemBucket);
309,427✔
2156
      return functionFinalize(pCtx, pBlock);
309,427✔
2157
    }
2158
  } else {
2159
    return functionFinalize(pCtx, pBlock);
63,685✔
2160
  }
2161

2162
_fin_error:
×
2163

2164
  tMemBucketDestroy(pMemBucket);
×
2165
  return code;
×
2166
}
2167

2168
bool getApercentileFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
1,801,554✔
2169
  int32_t bytesHist =
1,801,554✔
2170
      (int32_t)(sizeof(SAPercentileInfo) + sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
2171
  int32_t bytesDigest = (int32_t)(sizeof(SAPercentileInfo) + TDIGEST_SIZE(COMPRESSION));
1,801,554✔
2172
  pEnv->calcMemSize = TMAX(bytesHist, bytesDigest);
1,801,554✔
2173
  return true;
1,801,835✔
2174
}
2175

2176
int32_t getApercentileMaxSize() {
183,469✔
2177
  int32_t bytesHist =
183,469✔
2178
      (int32_t)(sizeof(SAPercentileInfo) + sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
2179
  int32_t bytesDigest = (int32_t)(sizeof(SAPercentileInfo) + TDIGEST_SIZE(COMPRESSION));
183,469✔
2180
  return TMAX(bytesHist, bytesDigest);
183,469✔
2181
}
2182

2183
static int8_t getApercentileAlgo(char* algoStr) {
1,407,411✔
2184
  int8_t algoType;
2185
  if (strcasecmp(algoStr, "default") == 0) {
1,407,411!
2186
    algoType = APERCT_ALGO_DEFAULT;
700,830✔
2187
  } else if (strcasecmp(algoStr, "t-digest") == 0) {
706,581!
2188
    algoType = APERCT_ALGO_TDIGEST;
706,102✔
2189
  } else {
2190
    algoType = APERCT_ALGO_UNKNOWN;
479✔
2191
  }
2192

2193
  return algoType;
1,407,411✔
2194
}
2195

2196
static void buildHistogramInfo(SAPercentileInfo* pInfo) {
13,461,486✔
2197
  pInfo->pHisto = (SHistogramInfo*)((char*)pInfo + sizeof(SAPercentileInfo));
13,461,486✔
2198
  pInfo->pHisto->elems = (SHistBin*)((char*)pInfo->pHisto + sizeof(SHistogramInfo));
13,462,148✔
2199
}
13,462,594✔
2200

2201
static void buildTDigestInfo(SAPercentileInfo* pInfo) {
1,430,544✔
2202
  pInfo->pTDigest = (TDigest*)((char*)pInfo + sizeof(SAPercentileInfo));
1,430,544✔
2203
}
1,430,789✔
2204

2205
int32_t apercentileFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
5,317,815✔
2206
  if (pResultInfo->initialized) {
5,317,815!
2207
    return TSDB_CODE_SUCCESS;
×
2208
  }
2209
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
5,318,049!
2210
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
2211
  }
2212

2213
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
5,317,815✔
2214

2215
  SVariant* pVal = &pCtx->param[1].param;
5,318,049✔
2216
  pInfo->percent = 0;
5,318,038✔
2217
  GET_TYPED_DATA(pInfo->percent, double, pVal->nType, &pVal->i, typeGetTypeModFromCol(pCtx->param[1].pCol));
5,318,038!
2218

2219
  if (pCtx->numOfParams == 2) {
5,317,610✔
2220
    pInfo->algo = APERCT_ALGO_DEFAULT;
3,910,638✔
2221
  } else if (pCtx->numOfParams == 3) {
1,407,166!
2222
    pInfo->algo = getApercentileAlgo(varDataVal(pCtx->param[2].param.pz));
1,407,634✔
2223
    if (pInfo->algo == APERCT_ALGO_UNKNOWN) {
1,407,400!
2224
      return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
2225
    }
2226
  }
2227

2228
  char* tmp = (char*)pInfo + sizeof(SAPercentileInfo);
5,317,142✔
2229
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
5,317,142✔
2230
    pInfo->pTDigest = tdigestNewFrom(tmp, COMPRESSION);
706,336✔
2231
  } else {
2232
    buildHistogramInfo(pInfo);
4,610,817✔
2233
    pInfo->pHisto = tHistogramCreateFrom(tmp, MAX_HISTOGRAM_BIN);
4,610,806✔
2234
    qDebug("%s set up histogram, numOfElems:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
4,611,040!
2235
           pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2236
  }
2237

2238
  return TSDB_CODE_SUCCESS;
5,318,272✔
2239
}
2240

2241
int32_t apercentileFunction(SqlFunctionCtx* pCtx) {
5,410,716✔
2242
  int32_t               numOfElems = 0;
5,410,716✔
2243
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
5,410,716✔
2244
  SInputColumnInfoData* pInput = &pCtx->input;
5,411,173✔
2245

2246
  SColumnInfoData* pCol = pInput->pData[0];
5,411,173✔
2247
  int32_t          type = pCol->info.type;
5,409,546✔
2248

2249
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5,410,043✔
2250

2251
  int32_t start = pInput->startRowIndex;
5,411,173✔
2252
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
5,410,277✔
2253
    buildTDigestInfo(pInfo);
704,515✔
2254
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
705,908✔
2255
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
34,267,780✔
2256
      if (colDataIsNull_f(pCol, i)) {
33,561,649!
2257
        continue;
16,427,581✔
2258
      }
2259
      numOfElems += 1;
17,134,536✔
2260
      char* data = colDataGetData(pCol, i);
17,134,536!
2261

2262
      double  v = 0;  // value
17,135,472✔
2263
      int64_t w = 1;  // weigth
17,135,472✔
2264
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
17,135,472!
2265
      int32_t code = tdigestAdd(pInfo->pTDigest, v, w);
17,133,834✔
2266
      if (code != TSDB_CODE_SUCCESS) {
17,134,291!
2267
        return code;
×
2268
      }
2269
    }
2270
  } else {
2271
    // might be a race condition here that pHisto can be overwritten or setup function
2272
    // has not been called, need to relink the buffer pHisto points to.
2273
    buildHistogramInfo(pInfo);
4,704,603✔
2274
    qDebug("%s before add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
4,704,603!
2275
           __FUNCTION__, numOfElems, pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto,
2276
           pInfo->pHisto->elems);
2277
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
202,062,436✔
2278
      if (colDataIsNull_f(pCol, i)) {
197,358,829!
2279
        continue;
45,191,445✔
2280
      }
2281
      numOfElems += 1;
152,186,360✔
2282
      char* data = colDataGetData(pCol, i);
152,186,360!
2283

2284
      double v = 0;
152,238,812✔
2285
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
152,238,812!
2286
      int32_t code = tHistogramAdd(&pInfo->pHisto, v);
152,239,046✔
2287
      if (code != TSDB_CODE_SUCCESS) {
152,165,726!
2288
        return code;
×
2289
      }
2290
    }
2291

2292
    qDebug("%s after add %d elements into histogram, total:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems: %p",
4,705,265!
2293
           __FUNCTION__, numOfElems, pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto,
2294
           pInfo->pHisto->elems);
2295
  }
2296

2297
  SET_VAL(pResInfo, numOfElems, 1);
5,410,939✔
2298
  return TSDB_CODE_SUCCESS;
5,410,939✔
2299
}
2300

2301
static int32_t apercentileTransferInfo(SAPercentileInfo* pInput, SAPercentileInfo* pOutput, bool* hasRes) {
113,001✔
2302
  pOutput->percent = pInput->percent;
113,001✔
2303
  pOutput->algo = pInput->algo;
113,001✔
2304
  if (pOutput->algo == APERCT_ALGO_TDIGEST) {
113,001✔
2305
    buildTDigestInfo(pInput);
20,522✔
2306
    tdigestAutoFill(pInput->pTDigest, COMPRESSION);
20,522✔
2307

2308
    if (pInput->pTDigest->num_centroids == 0 && pInput->pTDigest->num_buffered_pts == 0) {
20,522!
2309
      return TSDB_CODE_SUCCESS;
662✔
2310
    }
2311

2312
    if (hasRes) {
19,860!
2313
      *hasRes = true;
19,860✔
2314
    }
2315

2316
    buildTDigestInfo(pOutput);
19,860✔
2317
    TDigest* pTDigest = pOutput->pTDigest;
19,860✔
2318
    tdigestAutoFill(pTDigest, COMPRESSION);
19,860✔
2319

2320
    if (pTDigest->num_centroids <= 0 && pTDigest->num_buffered_pts == 0) {
19,860!
2321
      (void)memcpy(pTDigest, pInput->pTDigest, (size_t)TDIGEST_SIZE(COMPRESSION));
19,860!
2322
      tdigestAutoFill(pTDigest, COMPRESSION);
19,860✔
2323
    } else {
2324
      int32_t code = tdigestMerge(pTDigest, pInput->pTDigest);
×
2325
      if (TSDB_CODE_SUCCESS != code) {
×
2326
        return code;
×
2327
      }
2328
    }
2329
  } else {
2330
    buildHistogramInfo(pInput);
92,479✔
2331
    if (pInput->pHisto->numOfElems <= 0) {
92,479✔
2332
      return TSDB_CODE_SUCCESS;
4,902✔
2333
    }
2334

2335
    if (hasRes) {
87,577!
2336
      *hasRes = true;
87,577✔
2337
    }
2338

2339
    buildHistogramInfo(pOutput);
87,577✔
2340
    SHistogramInfo* pHisto = pOutput->pHisto;
87,577✔
2341

2342
    if (pHisto->numOfElems <= 0) {
87,577✔
2343
      (void)memcpy(pHisto, pInput->pHisto, sizeof(SHistogramInfo) + sizeof(SHistBin) * (MAX_HISTOGRAM_BIN + 1));
70,895!
2344
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
70,895✔
2345

2346
      qDebug("%s merge histo, total:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems, pHisto->numOfEntries,
70,895!
2347
             pHisto);
2348
    } else {
2349
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
16,682✔
2350
      qDebug("%s input histogram, elem:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems,
16,682!
2351
             pHisto->numOfEntries, pInput->pHisto);
2352

2353
      SHistogramInfo* pRes = NULL;
16,682✔
2354
      int32_t         code = tHistogramMerge(pHisto, pInput->pHisto, MAX_HISTOGRAM_BIN, &pRes);
16,682✔
2355
      if (TSDB_CODE_SUCCESS != code) {
16,682!
2356
        tHistogramDestroy(&pRes);
×
2357
        return code;
×
2358
      }
2359
      (void)memcpy(pHisto, pRes, sizeof(SHistogramInfo) + sizeof(SHistBin) * MAX_HISTOGRAM_BIN);
16,682!
2360
      pHisto->elems = (SHistBin*)((char*)pHisto + sizeof(SHistogramInfo));
16,682✔
2361

2362
      qDebug("%s merge histo, total:%" PRId64 ", entry:%d, %p", __FUNCTION__, pHisto->numOfElems, pHisto->numOfEntries,
16,682!
2363
             pHisto);
2364
      tHistogramDestroy(&pRes);
16,682✔
2365
    }
2366
  }
2367
  return TSDB_CODE_SUCCESS;
107,437✔
2368
}
2369

2370
int32_t apercentileFunctionMerge(SqlFunctionCtx* pCtx) {
110,149✔
2371
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
110,149✔
2372

2373
  SInputColumnInfoData* pInput = &pCtx->input;
110,149✔
2374

2375
  SColumnInfoData* pCol = pInput->pData[0];
110,149✔
2376
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
110,149!
2377
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
2378
  }
2379

2380
  SAPercentileInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
110,149✔
2381

2382
  qDebug("%s total %" PRId64 " rows will merge, %p", __FUNCTION__, pInput->numOfRows, pInfo->pHisto);
110,149!
2383

2384
  bool    hasRes = false;
110,149✔
2385
  int32_t start = pInput->startRowIndex;
110,149✔
2386
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
223,150✔
2387
    char* data = colDataGetData(pCol, i);
113,001!
2388

2389
    SAPercentileInfo* pInputInfo = (SAPercentileInfo*)varDataVal(data);
113,001✔
2390
    int32_t           code = apercentileTransferInfo(pInputInfo, pInfo, &hasRes);
113,001✔
2391
    if (TSDB_CODE_SUCCESS != code) {
113,001!
2392
      return code;
×
2393
    }
2394
  }
2395

2396
  if (pInfo->algo != APERCT_ALGO_TDIGEST) {
110,149✔
2397
    buildHistogramInfo(pInfo);
89,627✔
2398
    qDebug("%s after merge, total:%" PRId64 ", numOfEntry:%d, %p", __FUNCTION__, pInfo->pHisto->numOfElems,
89,627!
2399
           pInfo->pHisto->numOfEntries, pInfo->pHisto);
2400
  }
2401

2402
  SET_VAL(pResInfo, hasRes ? 1 : 0, 1);
110,149!
2403
  return TSDB_CODE_SUCCESS;
110,149✔
2404
}
2405

2406
int32_t apercentileFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
4,561,328✔
2407
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
4,561,328✔
2408
  SAPercentileInfo*    pInfo = (SAPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
4,561,562✔
2409

2410
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
4,561,328✔
2411
    buildTDigestInfo(pInfo);
684,488✔
2412
    tdigestAutoFill(pInfo->pTDigest, COMPRESSION);
684,722✔
2413
    if (pInfo->pTDigest->size > 0) {
684,722!
2414
      pInfo->result = tdigestQuantile(pInfo->pTDigest, pInfo->percent / 100);
684,956✔
2415
    } else {  // no need to free
2416
      // setNull(pCtx->pOutput, pCtx->outputType, pCtx->outputBytes);
2417
      return TSDB_CODE_SUCCESS;
×
2418
    }
2419
  } else {
2420
    buildHistogramInfo(pInfo);
3,876,606✔
2421
    if (pInfo->pHisto->numOfElems > 0) {
3,876,606✔
2422
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d, pHisto:%p, elems:%p", __FUNCTION__,
1,783,755!
2423
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries, pInfo->pHisto, pInfo->pHisto->elems);
2424

2425
      double  ratio[] = {pInfo->percent};
1,783,755✔
2426
      double* res = NULL;
1,783,755✔
2427
      int32_t code = tHistogramUniform(pInfo->pHisto, ratio, 1, &res);
1,783,755✔
2428
      if (TSDB_CODE_SUCCESS != code) {
1,783,755!
2429
        taosMemoryFree(res);
×
2430
        return code;
×
2431
      }
2432
      pInfo->result = *res;
1,783,755✔
2433
      // memcpy(pCtx->pOutput, res, sizeof(double));
2434
      taosMemoryFree(res);
1,783,755!
2435
    } else {  // no need to free
2436
      // setNull(pCtx->pOutput, pCtx->outputType, pCtx->outputBytes);
2437
      // return TSDB_CODE_SUCCESS;
2438
      qDebug("%s get the final res, elements:%" PRId64 ", numOfEntry:%d. result is null", __FUNCTION__,
2,092,851!
2439
             pInfo->pHisto->numOfElems, pInfo->pHisto->numOfEntries);
2440
    }
2441
  }
2442

2443
  return functionFinalize(pCtx, pBlock);
4,561,328✔
2444
}
2445

2446
int32_t apercentilePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
113,001✔
2447
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
113,001✔
2448
  SAPercentileInfo*    pInfo = (SAPercentileInfo*)GET_ROWCELL_INTERBUF(pResInfo);
113,001✔
2449

2450
  int32_t resultBytes = getApercentileMaxSize();
113,001✔
2451
  char*   res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
113,001!
2452
  if (NULL == res) {
113,001!
2453
    return terrno;
×
2454
  }
2455

2456
  if (pInfo->algo == APERCT_ALGO_TDIGEST) {
113,001✔
2457
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
20,522!
2458
    varDataSetLen(res, resultBytes);
20,522✔
2459
  } else {
2460
    (void)memcpy(varDataVal(res), pInfo, resultBytes);
92,479!
2461
    varDataSetLen(res, resultBytes);
92,479✔
2462
  }
2463

2464
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
113,001✔
2465
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
113,001✔
2466
  if (NULL == pCol) {
113,001!
2467
    taosMemoryFree(res);
×
2468
    return TSDB_CODE_OUT_OF_RANGE;
×
2469
  }
2470

2471
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
113,001✔
2472

2473
  taosMemoryFree(res);
113,001!
2474
  return code;
113,001✔
2475
}
2476

2477
int32_t apercentileCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
2478
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
2479
  SAPercentileInfo*    pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
2480

2481
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
2482
  SAPercentileInfo*    pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
2483

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

2486
  int32_t code = apercentileTransferInfo(pSBuf, pDBuf, NULL);
×
2487
  if (TSDB_CODE_SUCCESS != code) {
×
2488
    return code;
×
2489
  }
2490
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
2491
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
2492
  return TSDB_CODE_SUCCESS;
×
2493
}
2494

2495
// TODO: change this function when block data info pks changed
2496
static int32_t comparePkDataWithSValue(int8_t pkType, char* pkData, SValue* pVal, int32_t order) {
30,169✔
2497
  char numVal[8] = {0};
30,169✔
2498
  switch (pkType) {
30,169✔
2499
    case TSDB_DATA_TYPE_INT:
7,711✔
2500
      *(int32_t*)numVal = (int32_t)VALUE_GET_TRIVIAL_DATUM(pVal);
7,711✔
2501
      break;
7,711✔
2502
    case TSDB_DATA_TYPE_UINT:
3,028✔
2503
      *(uint32_t*)numVal = (uint32_t)VALUE_GET_TRIVIAL_DATUM(pVal);
3,028✔
2504
      break;
3,028✔
2505
    case TSDB_DATA_TYPE_BIGINT:
3,028✔
2506
      *(int64_t*)numVal = (int64_t)VALUE_GET_TRIVIAL_DATUM(pVal);
3,028✔
2507
      break;
3,028✔
2508
    case TSDB_DATA_TYPE_UBIGINT:
3,028✔
2509
      *(uint64_t*)numVal = (uint64_t)VALUE_GET_TRIVIAL_DATUM(pVal);
3,028✔
2510
      break;
3,028✔
2511
    default:
13,374✔
2512
      break;
13,374✔
2513
  }
2514
  char*         blockData = (IS_NUMERIC_TYPE(pkType)) ? (char*)numVal : (char*)pVal->pData;
30,169!
2515
  __compar_fn_t fn = getKeyComparFunc(pkType, order);
30,169✔
2516
  return fn(pkData, blockData);
30,169✔
2517
}
2518

2519
EFuncDataRequired firstDynDataReq(void* pRes, SDataBlockInfo* pBlockInfo) {
2,147,483,647✔
2520
  SResultRowEntryInfo* pEntry = (SResultRowEntryInfo*)pRes;
2,147,483,647✔
2521

2522
  // not initialized yet, data is required
2523
  if (pEntry == NULL) {
2,147,483,647!
2524
    return FUNC_DATA_REQUIRED_DATA_LOAD;
×
2525
  }
2526

2527
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
2,147,483,647✔
2528
  if (pResult->hasResult) {
2,147,483,647!
2529
    if (pResult->pkBytes > 0) {
2,147,483,647✔
2530
      pResult->pkData = pResult->buf + pResult->bytes;
115,416✔
2531
    } else {
2532
      pResult->pkData = NULL;
2,147,483,647✔
2533
    }
2534
    if (pResult->ts < pBlockInfo->window.skey) {
2,147,483,647✔
2535
      return FUNC_DATA_REQUIRED_NOT_LOAD;
379,995✔
2536
    } else if (pResult->ts == pBlockInfo->window.skey) {
2,147,483,647✔
2537
      if (NULL == pResult->pkData) {
2,147,483,647✔
2538
        return FUNC_DATA_REQUIRED_NOT_LOAD;
2,147,483,647✔
2539
      }
2540
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 0, TSDB_ORDER_ASC) < 0) {
6,408✔
2541
        return FUNC_DATA_REQUIRED_NOT_LOAD;
1,866✔
2542
      }
2543
    }
2544
    return FUNC_DATA_REQUIRED_DATA_LOAD;
186,685✔
2545
  } else {
2546
    return FUNC_DATA_REQUIRED_DATA_LOAD;
3,013✔
2547
  }
2548
}
2549

2550
EFuncDataRequired lastDynDataReq(void* pRes, SDataBlockInfo* pBlockInfo) {
23,545,458✔
2551
  SResultRowEntryInfo* pEntry = (SResultRowEntryInfo*)pRes;
23,545,458✔
2552

2553
  // not initialized yet, data is required
2554
  if (pEntry == NULL) {
23,545,458!
2555
    return FUNC_DATA_REQUIRED_DATA_LOAD;
×
2556
  }
2557

2558
  SFirstLastRes* pResult = GET_ROWCELL_INTERBUF(pEntry);
23,545,458✔
2559
  if (pResult->hasResult) {
23,556,673!
2560
    if (pResult->pkBytes > 0) {
23,557,409✔
2561
      pResult->pkData = pResult->buf + pResult->bytes;
296,281✔
2562
    } else {
2563
      pResult->pkData = NULL;
23,260,080✔
2564
    }
2565
    if (pResult->ts > pBlockInfo->window.ekey) {
23,556,778✔
2566
      return FUNC_DATA_REQUIRED_NOT_LOAD;
846,559✔
2567
    } else if (pResult->ts == pBlockInfo->window.ekey && pResult->pkData) {
22,708,764✔
2568
      if (comparePkDataWithSValue(pResult->pkType, pResult->pkData, pBlockInfo->pks + 1, TSDB_ORDER_DESC) < 0) {
23,761✔
2569
        return FUNC_DATA_REQUIRED_NOT_LOAD;
11,860✔
2570
      }
2571
    }
2572
    return FUNC_DATA_REQUIRED_DATA_LOAD;
22,678,878✔
2573
  } else {
2574
    return FUNC_DATA_REQUIRED_DATA_LOAD;
5,937✔
2575
  }
2576
}
2577

2578
// TODO modify it to include primary key bytes
2579
int32_t getFirstLastInfoSize(int32_t resBytes, int32_t pkBytes) { return sizeof(SFirstLastRes) + resBytes + pkBytes; }
1,683,568,478✔
2580

2581
bool getFirstLastFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
52,634,802✔
2582
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
52,634,802✔
2583
  // TODO: change SFunctionNode to add pk info
2584
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
52,651,166!
2585
  pEnv->calcMemSize = getFirstLastInfoSize(pNode->node.resType.bytes, pkBytes);
52,634,726✔
2586
  return true;
52,628,530✔
2587
}
2588

2589
bool getSelectivityFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
11,654,174✔
2590
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
11,654,174✔
2591
  pEnv->calcMemSize = pNode->node.resType.bytes;
11,657,710✔
2592
  return true;
11,652,929✔
2593
}
2594

2595
bool getGroupKeyFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
13,944,506✔
2596
  SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
13,944,506✔
2597
  pEnv->calcMemSize = sizeof(SGroupKeyInfo) + pNode->node.resType.bytes;
13,955,438✔
2598
  return true;
13,936,002✔
2599
}
2600

2601
static FORCE_INLINE TSKEY getRowPTs(SColumnInfoData* pTsColInfo, int32_t rowIndex) {
2602
  if (pTsColInfo == NULL || pTsColInfo->pData == NULL) {
2,147,483,647!
2603
    return 0;
×
2604
  }
2605

2606
  return *(TSKEY*)colDataGetData(pTsColInfo, rowIndex);
2,147,483,647!
2607
}
2608

2609
int32_t firstLastFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
2,147,483,647✔
2610
  if (pResInfo->initialized) {
2,147,483,647!
2611
    return TSDB_CODE_SUCCESS;
×
2612
  }
2613
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
2,147,483,647!
2614
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
2615
  }
2616

2617
  SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
2618
  pRes->nullTupleSaved = false;
2,147,483,647✔
2619
  pRes->nullTuplePos.pageId = -1;
2,147,483,647✔
2620
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
2621
}
2622

2623
static int32_t prepareBuf(SqlFunctionCtx* pCtx) {
97,128,369✔
2624
  if (pCtx->subsidiaries.rowLen == 0) {
97,128,369✔
2625
    int32_t rowLen = 0;
4,448,721✔
2626
    for (int32_t j = 0; j < pCtx->subsidiaries.num; ++j) {
10,362,628✔
2627
      SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
5,917,639✔
2628
      rowLen += pc->pExpr->base.resSchema.bytes;
5,915,951✔
2629
    }
2630

2631
    pCtx->subsidiaries.rowLen = rowLen + pCtx->subsidiaries.num * sizeof(bool);
4,444,705✔
2632
    pCtx->subsidiaries.buf = taosMemoryMalloc(pCtx->subsidiaries.rowLen);
4,447,945!
2633
    if (NULL == pCtx->subsidiaries.buf) {
4,449,353!
2634
      return terrno;
×
2635
    }
2636
  }
2637
  return TSDB_CODE_SUCCESS;
97,129,614✔
2638
}
2639

2640
static int32_t firstlastSaveTupleData(const SSDataBlock* pSrcBlock, int32_t rowIndex, SqlFunctionCtx* pCtx,
2,147,483,647✔
2641
                                      SFirstLastRes* pInfo, bool noElements) {
2642
  int32_t code = TSDB_CODE_SUCCESS;
2,147,483,647✔
2643

2644
  if (pCtx->subsidiaries.num <= 0) {
2,147,483,647✔
2645
    return TSDB_CODE_SUCCESS;
2,147,483,647✔
2646
  }
2647

2648
  if (!pInfo->hasResult) {
58,409,282!
2649
    code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
56,873,024✔
2650
  } else if (!noElements) {
1,537,015✔
2651
    code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
1,516,034✔
2652
  } else {
2653
  }  // dothing
2654

2655
  return code;
58,410,671✔
2656
}
2657

2658
static int32_t doSaveCurrentVal(SqlFunctionCtx* pCtx, int32_t rowIndex, int64_t currentTs, char* pkData, int32_t type,
2,147,483,647✔
2659
                                char* pData) {
2660
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
2661
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
2662

2663
  if (IS_VAR_DATA_TYPE(type)) {
2,147,483,647!
2664
    pInfo->bytes = calcStrBytesByType(type, pData);
2,147,483,647✔
2665
    // if (type == TSDB_DATA_TYPE_JSON) {
2666
    //   pInfo->bytes = getJsonValueLen(pData);
2667
    // } else {
2668
    //   pInfo->bytes = varDataTLen(pData);
2669
    // }
2670
  }
2671

2672
  (void)memcpy(pInfo->buf, pData, pInfo->bytes);
2,147,483,647!
2673
  if (pkData != NULL) {
2,147,483,647✔
2674
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
2,986,459!
2675
      pInfo->pkBytes = calcStrBytesByType(pInfo->pkType, pkData);
1,000,181✔
2676
      // if (pInfo->pkType == TSDB_DATA_TYPE_JSON) {
2677
      //   pInfo->pkBytes = getJsonValueLen(pkData);
2678
      // } else {
2679
      //   pInfo->pkBytes = varDataTLen(pkData);
2680
      // }
2681
    }
2682
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
2,985,702!
2683
    pInfo->pkData = pInfo->buf + pInfo->bytes;
2,984,188✔
2684
  }
2685

2686
  pInfo->ts = currentTs;
2,147,483,647✔
2687
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
2,147,483,647✔
2688
  if (code != TSDB_CODE_SUCCESS) {
2,147,483,647!
2689
    return code;
×
2690
  }
2691

2692
  pInfo->hasResult = true;
2,147,483,647✔
2693
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
2694
}
2695

2696
// This ordinary first function does not care if current scan is ascending order or descending order scan
2697
// the OPTIMIZED version of first function will only handle the ascending order scan
2698
int32_t firstFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
2699
  int32_t numOfElems = 0;
2,147,483,647✔
2700

2701
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
2702
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
2703

2704
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
2705
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
2706

2707
  pInfo->bytes = pInputCol->info.bytes;
2,147,483,647✔
2708

2709
  if (IS_NULL_TYPE(pInputCol->info.type)) {
2,147,483,647✔
2710
    return TSDB_CODE_SUCCESS;
707,254✔
2711
  }
2712

2713
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
2,147,483,647✔
2714
  pInfo->pkType = -1;
2,147,483,647✔
2715
  __compar_fn_t pkCompareFn = NULL;
2,147,483,647✔
2716
  if (pCtx->hasPrimaryKey) {
2,147,483,647!
2717
    pInfo->pkType = pkCol->info.type;
1,402,307✔
2718
    pInfo->pkBytes = pkCol->info.bytes;
1,404,578✔
2719
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_ASC);
1,403,821✔
2720
  }
2721

2722
  // All null data column, return directly.
2723
  if (pInput->colDataSMAIsSet && (pInput->pColumnDataAgg[0]->numOfNull == pInput->totalRows) &&
2,147,483,647!
2724
      pInputCol->hasNull == true) {
×
2725
    // save selectivity value for column consisted of all null values
2726
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
×
2727
    if (code != TSDB_CODE_SUCCESS) {
×
2728
      return code;
×
2729
    }
2730
    pInfo->nullTupleSaved = true;
×
2731
    return TSDB_CODE_SUCCESS;
×
2732
  }
2733

2734
  SColumnDataAgg* pColAgg = (pInput->colDataSMAIsSet) ? pInput->pColumnDataAgg[0] : NULL;
2,147,483,647!
2735

2736
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
2,147,483,647✔
2737
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
2,147,483,647✔
2738

2739
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
2,147,483,647✔
2740

2741
  //  please ref. to the comment in lastRowFunction for the reason why disabling the opt version of last/first
2742
  //  function. we will use this opt implementation in an new version that is only available in scan subplan
2743
#if 0
2744
  if (blockDataOrder == TSDB_ORDER_ASC) {
2745
    // filter according to current result firstly
2746
    if (pResInfo->numOfRes > 0) {
2747
      if (pInfo->ts < startKey) {
2748
        return TSDB_CODE_SUCCESS;
2749
      }
2750
    }
2751

2752
    for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
2753
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2754
        continue;
2755
      }
2756

2757
      numOfElems++;
2758

2759
      char* data = colDataGetData(pInputCol, i);
2760
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2761
      if (pResInfo->numOfRes == 0 || pInfo->ts > cts) {
2762
        doSaveCurrentVal(pCtx, i, cts, pInputCol->info.type, data);
2763
        break;
2764
      }
2765
    }
2766
  } else {
2767
    // in case of descending order time stamp serial, which usually happens as the results of the nest query,
2768
    // all data needs to be check.
2769
    if (pResInfo->numOfRes > 0) {
2770
      if (pInfo->ts < endKey) {
2771
        return TSDB_CODE_SUCCESS;
2772
      }
2773
    }
2774

2775
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
2776
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2777
        continue;
2778
      }
2779

2780
      numOfElems++;
2781

2782
      char* data = colDataGetData(pInputCol, i);
2783
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2784

2785
      if (pResInfo->numOfRes == 0 || pInfo->ts > cts) {
2786
        doSaveCurrentVal(pCtx, i, cts, pInputCol->info.type, data);
2787
        break;
2788
      }
2789
    }
2790
  }
2791
#else
2792
  int64_t* pts = (int64_t*)pInput->pPTS->pData;
2,147,483,647✔
2793

2794
  int     from = -1;
2,147,483,647✔
2795
  int32_t i = -1;
2,147,483,647✔
2796
  while (funcInputGetNextRowIndex(pInput, from, true, &i, &from)) {
2,147,483,647✔
2797
    if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2,147,483,647!
2798
      continue;
2,147,483,647✔
2799
    }
2800

2801
    numOfElems++;
2,147,483,647✔
2802
    char* data = colDataGetData(pInputCol, i);
2,147,483,647!
2803
    char* pkData = NULL;
2,147,483,647✔
2804
    if (pCtx->hasPrimaryKey) {
2,147,483,647!
2805
      pkData = colDataGetData(pkCol, i);
3,295,852!
2806
    }
2807
    TSKEY cts = pts[i];
2,147,483,647✔
2808
    if (pResInfo->numOfRes == 0 || pInfo->ts > cts ||
2,147,483,647✔
2809
        (pInfo->ts == cts && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
2,147,483,647!
2810
      int32_t code = doSaveCurrentVal(pCtx, i, cts, pkData, pInputCol->info.type, data);
2,147,483,647✔
2811
      if (code != TSDB_CODE_SUCCESS) {
2,147,483,647!
2812
        return code;
×
2813
      }
2814
      pResInfo->numOfRes = 1;
2,147,483,647✔
2815
    }
2816
  }
2817
#endif
2818

2819
  if (numOfElems == 0) {
2,147,483,647✔
2820
    // save selectivity value for column consisted of all null values
2821
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
2,147,483,647✔
2822
    if (code != TSDB_CODE_SUCCESS) {
2,147,483,647!
2823
      return code;
×
2824
    }
2825
    pInfo->nullTupleSaved = true;
2,147,483,647✔
2826
  }
2827
  SET_VAL(pResInfo, numOfElems, 1);
2,147,483,647✔
2828
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
2829
}
2830

2831
int32_t lastFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
2832
  int32_t numOfElems = 0;
2,147,483,647✔
2833

2834
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
2835
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
2836

2837
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
2838
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
2839

2840
  int32_t type = pInputCol->info.type;
2,147,483,647✔
2841
  int32_t bytes = pInputCol->info.bytes;
2,147,483,647✔
2842

2843
  if (IS_NULL_TYPE(type)) {
2,147,483,647✔
2844
    return TSDB_CODE_SUCCESS;
696,407✔
2845
  }
2846
  pInfo->bytes = bytes;
2,147,483,647✔
2847

2848
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
2,147,483,647✔
2849
  pInfo->pkType = -1;
2,147,483,647✔
2850
  __compar_fn_t pkCompareFn = NULL;
2,147,483,647✔
2851
  if (pCtx->hasPrimaryKey) {
2,147,483,647!
2852
    pInfo->pkType = pkCol->info.type;
1,714,811✔
2853
    pInfo->pkBytes = pkCol->info.bytes;
1,714,054✔
2854
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
1,714,811✔
2855
  }
2856

2857
  // All null data column, return directly.
2858
  if (pInput->colDataSMAIsSet && (pInput->pColumnDataAgg[0]->numOfNull == pInput->totalRows) &&
2,147,483,647!
2859
      pInputCol->hasNull == true) {
×
2860
    // save selectivity value for column consisted of all null values
2861
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
×
2862
    if (code != TSDB_CODE_SUCCESS) {
×
2863
      return code;
×
2864
    }
2865
    pInfo->nullTupleSaved = true;
×
2866
    return TSDB_CODE_SUCCESS;
×
2867
  }
2868

2869
  SColumnDataAgg* pColAgg = (pInput->colDataSMAIsSet) ? pInput->pColumnDataAgg[0] : NULL;
2,147,483,647!
2870

2871
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
2,147,483,647✔
2872
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
2,147,483,647✔
2873

2874
  int32_t blockDataOrder = (startKey <= endKey) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
2,147,483,647✔
2875

2876
  //  please ref. to the comment in lastRowFunction for the reason why disabling the opt version of last/first function.
2877
#if 0
2878
  if (blockDataOrder == TSDB_ORDER_ASC) {
2879
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
2880
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2881
        continue;
2882
      }
2883

2884
      numOfElems++;
2885

2886
      char* data = colDataGetData(pInputCol, i);
2887
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2888
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2889
        doSaveCurrentVal(pCtx, i, cts, type, data);
2890
      }
2891

2892
      break;
2893
    }
2894
  } else {  // descending order
2895
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
2896
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2897
        continue;
2898
      }
2899

2900
      numOfElems++;
2901

2902
      char* data = colDataGetData(pInputCol, i);
2903
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2904
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2905
        doSaveCurrentVal(pCtx, i, cts, type, data);
2906
      }
2907
      break;
2908
    }
2909
  }
2910
#else
2911
  int64_t* pts = (int64_t*)pInput->pPTS->pData;
2,147,483,647✔
2912

2913
#if 0
2914
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
2915
      if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2916
        continue;
2917
      }
2918

2919
      numOfElems++;
2920
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i]) {
2921
        char* data = colDataGetData(pInputCol, i);
2922
        doSaveCurrentVal(pCtx, i, pts[i], type, data);
2923
        pResInfo->numOfRes = 1;
2924
      }
2925
    }
2926
#else
2927

2928
  // todo refactor
2929
  if (!pInputCol->hasNull && !pCtx->hasPrimaryKey) {
2,147,483,647!
2930
    numOfElems = 1;
2,147,483,647✔
2931

2932
    int32_t round = pInput->numOfRows >> 2;
2,147,483,647✔
2933
    int32_t reminder = pInput->numOfRows & 0x03;
2,147,483,647✔
2934

2935
    for (int32_t i = pInput->startRowIndex, tick = 0; tick < round; i += 4, tick += 1) {
2,147,483,647✔
2936
      int64_t cts = pts[i];
1,584,062,297✔
2937
      int32_t chosen = i;
1,582,157,384✔
2938

2939
      if (cts < pts[i + 1]) {
1,582,157,384✔
2940
        cts = pts[i + 1];
34,892,422✔
2941
        chosen = i + 1;
34,892,422✔
2942
      }
2943

2944
      if (cts < pts[i + 2]) {
1,579,998,040✔
2945
        cts = pts[i + 2];
34,892,880✔
2946
        chosen = i + 2;
34,892,880✔
2947
      }
2948

2949
      if (cts < pts[i + 3]) {
1,581,546,758✔
2950
        cts = pts[i + 3];
34,890,514✔
2951
        chosen = i + 3;
34,890,514✔
2952
      }
2953

2954
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
1,582,149,558✔
2955
        char*   data = colDataGetData(pInputCol, chosen);
398,275,467!
2956
        int32_t code = doSaveCurrentVal(pCtx, chosen, cts, NULL, type, data);
392,413,836✔
2957
        if (code != TSDB_CODE_SUCCESS) {
390,768,816!
2958
          return code;
×
2959
        }
2960
        pResInfo->numOfRes = 1;
390,768,816✔
2961
      }
2962
    }
2963

2964
    for (int32_t i = pInput->startRowIndex + round * 4; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
2,147,483,647✔
2965
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i]) {
2,147,483,647✔
2966
        char*   data = colDataGetData(pInputCol, i);
337,055,504!
2967
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], NULL, type, data);
326,153,344✔
2968
        if (code != TSDB_CODE_SUCCESS) {
325,770,447!
2969
          return code;
×
2970
        }
2971
        pResInfo->numOfRes = 1;
325,770,447✔
2972
      }
2973
    }
2974
  } else {
2975
    int     from = -1;
2,147,483,647✔
2976
    int32_t i = -1;
2,147,483,647✔
2977
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
2,147,483,647✔
2978
      if (colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) {
2,147,483,647!
2979
        continue;
2,147,483,647✔
2980
      }
2981

2982
      numOfElems++;
2,147,483,647✔
2983
      char* pkData = NULL;
2,147,483,647✔
2984
      if (pCtx->hasPrimaryKey && !colDataIsNull_s(pkCol, i)) {
2,147,483,647!
2985
        // pkCol[i] might be null when using cachemodel
2986
        // however, if using cachemodel, we don't need pk to determine the order
2987
        // because ts is enough
2988
        pkData = colDataGetData(pkCol, i);
3,776,395!
2989
      }
2990
      if (pResInfo->numOfRes == 0 || pInfo->ts < pts[i] ||
2,147,483,647✔
2991
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
2,147,483,647✔
2992
        char*   data = colDataGetData(pInputCol, i);
2,147,483,647!
2993
        int32_t code = doSaveCurrentVal(pCtx, i, pts[i], pkData, type, data);
2,147,483,647✔
2994
        if (code != TSDB_CODE_SUCCESS) {
2,147,483,647!
2995
          return code;
×
2996
        }
2997
        pResInfo->numOfRes = 1;
2,147,483,647✔
2998
      }
2999
    }
3000
  }
3001
#endif
3002

3003
#endif
3004

3005
  // save selectivity value for column consisted of all null values
3006
  if (numOfElems == 0) {
2,147,483,647✔
3007
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
2,147,483,647✔
3008
    if (code != TSDB_CODE_SUCCESS) {
2,147,483,647!
3009
      return code;
×
3010
    }
3011
    pInfo->nullTupleSaved = true;
2,147,483,647✔
3012
  }
3013

3014
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3015
}
3016

3017
static bool firstLastTransferInfoImpl(SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst) {
1,391,756,992✔
3018
  if (!pInput->hasResult) {
1,391,756,992!
3019
    return false;
×
3020
  }
3021
  __compar_fn_t pkCompareFn = NULL;
1,391,756,992✔
3022
  if (pInput->pkData) {
1,391,756,992✔
3023
    pkCompareFn = getKeyComparFunc(pInput->pkType, (isFirst) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC);
1,172,617✔
3024
  }
3025
  if (pOutput->hasResult) {
1,391,756,992!
3026
    if (isFirst) {
848,648,945✔
3027
      if (pInput->ts > pOutput->ts ||
497,230,418✔
3028
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
497,051,948✔
3029
        return false;
181,498✔
3030
      }
3031
    } else {
3032
      if (pInput->ts < pOutput->ts ||
351,418,527✔
3033
          (pInput->ts == pOutput->ts && pkCompareFn && pkCompareFn(pInput->pkData, pOutput->pkData) > 0)) {
342,277,840!
3034
        return false;
9,140,687✔
3035
      }
3036
    }
3037
  }
3038

3039
  pOutput->isNull = pInput->isNull;
1,382,434,807!
3040
  pOutput->ts = pInput->ts;
1,382,434,807✔
3041
  pOutput->bytes = pInput->bytes;
1,382,434,807✔
3042
  pOutput->pkType = pInput->pkType;
1,382,434,807✔
3043

3044
  (void)memcpy(pOutput->buf, pInput->buf, pOutput->bytes);
1,382,434,807!
3045
  if (pInput->pkData) {
1,382,434,807✔
3046
    pOutput->pkBytes = pInput->pkBytes;
1,037,871✔
3047
    (void)memcpy(pOutput->buf + pOutput->bytes, pInput->pkData, pOutput->pkBytes);
1,037,871!
3048
    pOutput->pkData = pOutput->buf + pOutput->bytes;
1,037,871✔
3049
  }
3050
  return true;
1,382,434,807✔
3051
}
3052

3053
static int32_t firstLastTransferInfo(SqlFunctionCtx* pCtx, SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst,
1,391,756,992✔
3054
                                     int32_t rowIndex) {
3055
  if (firstLastTransferInfoImpl(pInput, pOutput, isFirst)) {
1,391,756,992✔
3056
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pOutput, false);
1,382,434,807✔
3057
    if (TSDB_CODE_SUCCESS != code) {
1,382,434,807!
3058
      return code;
×
3059
    }
3060
    pOutput->hasResult = true;
1,382,434,807✔
3061
  }
3062
  return TSDB_CODE_SUCCESS;
1,391,756,992✔
3063
}
3064

3065
static int32_t firstLastFunctionMergeImpl(SqlFunctionCtx* pCtx, bool isFirstQuery) {
549,736,028✔
3066
  SInputColumnInfoData* pInput = &pCtx->input;
549,736,028✔
3067
  SColumnInfoData*      pCol = pInput->pData[0];
549,736,028✔
3068

3069
  if (IS_NULL_TYPE(pCol->info.type)) {
549,736,028!
3070
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
3071
    return TSDB_CODE_SUCCESS;
×
3072
  }
3073

3074
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
549,736,028!
3075
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3076
  }
3077

3078
  SFirstLastRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
549,736,028✔
3079

3080
  int32_t start = pInput->startRowIndex;
549,736,028✔
3081
  int32_t numOfElems = 0;
549,736,028✔
3082

3083
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
2,104,419,496✔
3084
    if (colDataIsNull_s(pCol, i)) {
2,147,483,647!
3085
      continue;
162,926,476✔
3086
    }
3087
    char*          data = colDataGetData(pCol, i);
1,391,756,992!
3088
    SFirstLastRes* pInputInfo = (SFirstLastRes*)varDataVal(data);
1,391,756,992✔
3089
    if (pCtx->hasPrimaryKey) {
1,391,756,992!
3090
      pInputInfo->pkData = pInputInfo->buf + pInputInfo->bytes;
1,172,617✔
3091
    } else {
3092
      pInputInfo->pkData = NULL;
1,390,584,375✔
3093
    }
3094

3095
    int32_t code = firstLastTransferInfo(pCtx, pInputInfo, pInfo, isFirstQuery, i);
1,391,756,992✔
3096
    if (code != TSDB_CODE_SUCCESS) {
1,391,756,992!
3097
      return code;
×
3098
    }
3099
    if (!numOfElems) {
1,391,756,992✔
3100
      numOfElems = pInputInfo->hasResult ? 1 : 0;
548,777,024!
3101
    }
3102
  }
3103

3104
  if (numOfElems == 0) {
549,736,028✔
3105
    int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
959,004✔
3106
    if (code != TSDB_CODE_SUCCESS) {
959,004!
3107
      return code;
×
3108
    }
3109
    pInfo->nullTupleSaved = true;
959,004✔
3110
  }
3111

3112
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
549,736,028✔
3113
  return TSDB_CODE_SUCCESS;
549,736,028✔
3114
}
3115

3116
int32_t firstFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, true); }
289,532,760✔
3117

3118
int32_t lastFunctionMerge(SqlFunctionCtx* pCtx) { return firstLastFunctionMergeImpl(pCtx, false); }
260,203,268✔
3119

3120
int32_t firstLastFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,147,483,647✔
3121
  int32_t          code = TSDB_CODE_SUCCESS;
2,147,483,647✔
3122
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
2,147,483,647✔
3123
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,147,483,647✔
3124
  if (NULL == pCol) {
2,147,483,647!
3125
    return TSDB_CODE_OUT_OF_RANGE;
×
3126
  }
3127

3128
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3129
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
2,147,483,647✔
3130

3131
  SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3132

3133
  if (pResInfo->isNullRes) {
2,147,483,647✔
3134
    colDataSetNULL(pCol, pBlock->info.rows);
1,471,159,330!
3135
    return setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
1,471,160,068✔
3136
  }
3137
  code = colDataSetVal(pCol, pBlock->info.rows, pRes->buf, pRes->isNull || pResInfo->isNullRes);
2,147,483,647!
3138
  if (TSDB_CODE_SUCCESS != code) {
2,147,483,647!
3139
    return code;
×
3140
  }
3141

3142
  // handle selectivity
3143
  code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
2,147,483,647✔
3144
  if (TSDB_CODE_SUCCESS != code) {
2,147,483,647!
3145
    qError("%s failed at %d, msg:%s", __func__, __LINE__, tstrerror(code));
×
3146
  }
3147

3148
  return code;
2,147,483,647✔
3149
}
3150

3151
int32_t firstLastPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,622,608,443✔
3152
  int32_t code = TSDB_CODE_SUCCESS;
1,622,608,443✔
3153

3154
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
1,622,608,443✔
3155
  SFirstLastRes*       pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
1,627,124,740✔
3156

3157
  int32_t resultBytes = getFirstLastInfoSize(pRes->bytes, pRes->pkBytes);
1,627,107,871✔
3158

3159
  // todo check for failure
3160
  char* res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
1,624,880,844!
3161
  if (NULL == res) {
1,621,684,330!
3162
    return terrno;
×
3163
  }
3164
  (void)memcpy(varDataVal(res), pRes, resultBytes);
1,621,684,330!
3165

3166
  varDataSetLen(res, resultBytes);
1,621,194,926✔
3167

3168
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,627,171,439✔
3169
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,623,088,342✔
3170
  if (NULL == pCol) {
1,626,027,960!
3171
    taosMemoryFree(res);
×
3172
    return TSDB_CODE_OUT_OF_RANGE;
×
3173
  }
3174

3175
  if (pEntryInfo->numOfRes == 0) {
1,626,027,960✔
3176
    colDataSetNULL(pCol, pBlock->info.rows);
170,438,844!
3177
    code = setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
170,435,152✔
3178
  } else {
3179
    code = colDataSetVal(pCol, pBlock->info.rows, res, false);
1,455,886,781✔
3180
    if (TSDB_CODE_SUCCESS != code) {
1,453,258,128!
3181
      taosMemoryFree(res);
×
3182
      return code;
×
3183
    }
3184
    code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
1,453,258,128✔
3185
  }
3186
  taosMemoryFree(res);
1,621,461,581!
3187
  return code;
1,621,612,718✔
3188
}
3189

3190
int32_t lastCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
3191
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
3192
  SFirstLastRes*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
3193
  int32_t              bytes = pDBuf->bytes;
×
3194

3195
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
3196
  SFirstLastRes*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
3197

3198
  pDBuf->hasResult = firstLastTransferInfoImpl(pSBuf, pDBuf, false);
×
3199
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
3200
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
3201
  return TSDB_CODE_SUCCESS;
×
3202
}
3203

3204
static int32_t doSaveLastrow(SqlFunctionCtx* pCtx, char* pData, int32_t rowIndex, int64_t cts, SFirstLastRes* pInfo) {
24,423,264✔
3205
  SInputColumnInfoData* pInput = &pCtx->input;
24,423,264✔
3206
  SColumnInfoData*      pInputCol = pInput->pData[0];
24,426,173✔
3207
  SColumnInfoData*      pkCol = pInput->pPrimaryKey;
24,429,000✔
3208

3209
  if (colDataIsNull_s(pInputCol, rowIndex)) {
48,843,809!
3210
    pInfo->isNull = true;
1,463,193✔
3211
  } else {
3212
    pInfo->isNull = false;
22,957,695✔
3213

3214
    if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
22,955,530!
3215
      pInfo->bytes = calcStrBytesByType(pInputCol->info.type, pData);
2,579,416✔
3216
      // if (pInputCol->info.type == TSDB_DATA_TYPE_JSON) {
3217
      //   pInfo->bytes = getJsonValueLen(pData);
3218
      // } else {
3219
      //   pInfo->bytes = varDataTLen(pData);
3220
      // }
3221
    }
3222

3223
    (void)memcpy(pInfo->buf, pData, pInfo->bytes);
22,945,725!
3224
  }
3225

3226
  if (pCtx->hasPrimaryKey && !colDataIsNull_s(pkCol, rowIndex)) {
25,806,125!
3227
    char* pkData = colDataGetData(pkCol, rowIndex);
1,395,004!
3228
    if (IS_VAR_DATA_TYPE(pInfo->pkType)) {
1,394,247!
3229
      pInfo->pkBytes = calcStrBytesByType(pInfo->pkType, pkData);
462,224✔
3230
    }
3231
    (void)memcpy(pInfo->buf + pInfo->bytes, pkData, pInfo->pkBytes);
1,395,761!
3232
    pInfo->pkData = pInfo->buf + pInfo->bytes;
1,395,004✔
3233
  }
3234
  pInfo->ts = cts;
24,419,515✔
3235
  int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pInfo, false);
24,404,839✔
3236
  if (code != TSDB_CODE_SUCCESS) {
24,405,426!
3237
    return code;
×
3238
  }
3239

3240
  pInfo->hasResult = true;
24,405,426✔
3241

3242
  return TSDB_CODE_SUCCESS;
24,404,035✔
3243
}
3244

3245
int32_t lastRowFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
3246
  int32_t numOfElems = 0;
2,147,483,647✔
3247

3248
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3249
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3250

3251
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
3252
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
3253

3254
  int32_t type = pInputCol->info.type;
2,147,483,647✔
3255
  int32_t bytes = pInputCol->info.bytes;
2,147,483,647✔
3256
  pInfo->bytes = bytes;
2,147,483,647✔
3257

3258
  if (IS_NULL_TYPE(type)) {
2,147,483,647✔
3259
    return TSDB_CODE_SUCCESS;
26,734✔
3260
  }
3261
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
2,147,483,647✔
3262
  pInfo->pkType = -1;
2,147,483,647✔
3263
  __compar_fn_t pkCompareFn = NULL;
2,147,483,647✔
3264
  if (pCtx->hasPrimaryKey) {
2,147,483,647!
3265
    pInfo->pkType = pkCol->info.type;
1,383,355✔
3266
    pInfo->pkBytes = pkCol->info.bytes;
1,382,598✔
3267
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
1,384,112✔
3268
  }
3269
  TSKEY startKey = getRowPTs(pInput->pPTS, 0);
2,147,483,647✔
3270
  TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1);
2,147,483,647✔
3271

3272
  if (pCtx->order == TSDB_ORDER_ASC && !pCtx->hasPrimaryKey) {
2,147,483,647!
3273
    for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
32,539,255!
3274
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
16,274,366!
3275
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
16,276,301!
3276
      TSKEY cts = getRowPTs(pInput->pPTS, i);
16,280,160!
3277
      numOfElems++;
16,281,439✔
3278

3279
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
16,281,439✔
3280
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
5,229,589✔
3281
        if (code != TSDB_CODE_SUCCESS) return code;
5,211,738!
3282
      }
3283

3284
      break;
16,262,309✔
3285
    }
3286
  } else if (pCtx->order == TSDB_ORDER_DESC && !pCtx->hasPrimaryKey) {
2,147,483,647!
3287
    // the optimized version only valid if all tuples in one block are monotonious increasing or descreasing.
3288
    // this assumption is NOT always works if project operator exists in downstream.
3289
    for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
2,147,483,647✔
3290
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
2,147,483,647!
3291
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
2,147,483,647!
3292
      TSKEY cts = getRowPTs(pInput->pPTS, i);
2,147,483,647✔
3293
      numOfElems++;
2,147,483,647✔
3294

3295
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
2,147,483,647✔
3296
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
15,497,332✔
3297
        if (code != TSDB_CODE_SUCCESS) return code;
14,864,349!
3298
      }
3299
      break;
2,147,483,647✔
3300
    }
3301
  } else {
3302
    int64_t* pts = (int64_t*)pInput->pPTS->pData;
2,588,463✔
3303
    int      from = -1;
2,152,699✔
3304
    int32_t  i = -1;
2,151,942✔
3305
    while (funcInputGetNextRowIndex(pInput, from, false, &i, &from)) {
10,282,548✔
3306
      bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
8,125,307!
3307
      char* data = isNull ? NULL : colDataGetData(pInputCol, i);
8,130,806!
3308
      TSKEY cts = pts[i];
8,130,806✔
3309

3310
      numOfElems++;
8,133,634✔
3311
      char* pkData = NULL;
8,133,634✔
3312
      if (pCtx->hasPrimaryKey) {
8,133,634!
3313
        pkData = colDataGetData(pkCol, i);
3,533,867!
3314
      }
3315
      if (pResInfo->numOfRes == 0 || pInfo->ts < cts ||
8,127,226✔
3316
          (pInfo->ts == pts[i] && pkCompareFn && pkCompareFn(pkData, pInfo->pkData) < 0)) {
4,356,816✔
3317
        int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
3,781,926✔
3318
        if (code != TSDB_CODE_SUCCESS) {
3,777,170!
3319
          return code;
×
3320
        }
3321
        pResInfo->numOfRes = 1;
3,777,170✔
3322
      }
3323
    }
3324
  }
3325

3326
  SET_VAL(pResInfo, numOfElems, 1);
2,147,483,647!
3327
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3328
}
3329

3330
bool getDiffFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
390,609✔
3331
  pEnv->calcMemSize = sizeof(SDiffInfo);
390,609✔
3332
  return true;
390,609✔
3333
}
3334

3335
int32_t diffFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
24,440,928✔
3336
  if (pResInfo->initialized) {
24,440,928✔
3337
    return TSDB_CODE_SUCCESS;
21,687,591✔
3338
  }
3339
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
2,753,337!
3340
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3341
  }
3342
  SDiffInfo* pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,753,337✔
3343
  pDiffInfo->hasPrev = false;
2,753,337✔
3344
  pDiffInfo->isFirstRow = true;
2,753,337✔
3345
  pDiffInfo->prev.i64 = 0;
2,753,337✔
3346
  pDiffInfo->prevTs = -1;
2,753,337✔
3347
  if (pCtx->numOfParams > 1) {
2,753,337!
3348
    pDiffInfo->ignoreOption = pCtx->param[1].param.i;  // TODO set correct param
2,753,337✔
3349
  } else {
3350
    pDiffInfo->ignoreOption = 0;
×
3351
  }
3352
  return TSDB_CODE_SUCCESS;
2,753,337✔
3353
}
3354

3355
static int32_t doSetPrevVal(SDiffInfo* pDiffInfo, int32_t type, const char* pv, int64_t ts) {
2,684,212✔
3356
  switch (type) {
2,684,212!
3357
    case TSDB_DATA_TYPE_BOOL:
5,676✔
3358
      pDiffInfo->prev.i64 = *(bool*)pv ? 1 : 0;
5,676!
3359
      break;
5,676✔
3360
    case TSDB_DATA_TYPE_UTINYINT:
36,502✔
3361
    case TSDB_DATA_TYPE_TINYINT:
3362
      pDiffInfo->prev.i64 = *(int8_t*)pv;
36,502✔
3363
      break;
36,502✔
3364
    case TSDB_DATA_TYPE_UINT:
2,363,151✔
3365
    case TSDB_DATA_TYPE_INT:
3366
      pDiffInfo->prev.i64 = *(int32_t*)pv;
2,363,151✔
3367
      break;
2,363,151✔
3368
    case TSDB_DATA_TYPE_USMALLINT:
35,887✔
3369
    case TSDB_DATA_TYPE_SMALLINT:
3370
      pDiffInfo->prev.i64 = *(int16_t*)pv;
35,887✔
3371
      break;
35,887✔
3372
    case TSDB_DATA_TYPE_TIMESTAMP:
150,884✔
3373
    case TSDB_DATA_TYPE_UBIGINT:
3374
    case TSDB_DATA_TYPE_BIGINT:
3375
      pDiffInfo->prev.i64 = *(int64_t*)pv;
150,884✔
3376
      break;
150,884✔
3377
    case TSDB_DATA_TYPE_FLOAT:
21,593✔
3378
      pDiffInfo->prev.d64 = *(float*)pv;
21,593✔
3379
      break;
21,593✔
3380
    case TSDB_DATA_TYPE_DOUBLE:
70,519✔
3381
      pDiffInfo->prev.d64 = *(double*)pv;
70,519✔
3382
      break;
70,519✔
3383
    default:
×
3384
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3385
  }
3386
  pDiffInfo->prevTs = ts;
2,684,212✔
3387
  pDiffInfo->hasPrev = true;
2,684,212✔
3388
  return TSDB_CODE_SUCCESS;
2,684,212✔
3389
}
3390

3391
static bool diffIsNegtive(SDiffInfo* pDiffInfo, int32_t type, const char* pv) {
1,186,859✔
3392
  switch (type) {
1,186,859!
3393
    case TSDB_DATA_TYPE_UINT: {
×
3394
      int64_t v = *(uint32_t*)pv;
×
3395
      return v < pDiffInfo->prev.i64;
×
3396
    }
3397
    case TSDB_DATA_TYPE_INT: {
63,210✔
3398
      int64_t v = *(int32_t*)pv;
63,210✔
3399
      return v < pDiffInfo->prev.i64;
63,210✔
3400
    }
3401
    case TSDB_DATA_TYPE_BOOL: {
×
3402
      int64_t v = *(bool*)pv;
×
3403
      return v < pDiffInfo->prev.i64;
×
3404
    }
3405
    case TSDB_DATA_TYPE_UTINYINT: {
×
3406
      int64_t v = *(uint8_t*)pv;
×
3407
      return v < pDiffInfo->prev.i64;
×
3408
    }
3409
    case TSDB_DATA_TYPE_TINYINT: {
233,019✔
3410
      int64_t v = *(int8_t*)pv;
233,019✔
3411
      return v < pDiffInfo->prev.i64;
233,019✔
3412
    }
3413
    case TSDB_DATA_TYPE_USMALLINT: {
×
3414
      int64_t v = *(uint16_t*)pv;
×
3415
      return v < pDiffInfo->prev.i64;
×
3416
    }
3417
    case TSDB_DATA_TYPE_SMALLINT: {
213,011✔
3418
      int64_t v = *(int16_t*)pv;
213,011✔
3419
      return v < pDiffInfo->prev.i64;
213,011✔
3420
    }
3421
    case TSDB_DATA_TYPE_UBIGINT: {
5,048✔
3422
      uint64_t v = *(uint64_t*)pv;
5,048✔
3423
      return v < (uint64_t)pDiffInfo->prev.i64;
5,048✔
3424
    }
3425
    case TSDB_DATA_TYPE_TIMESTAMP:
192,257✔
3426
    case TSDB_DATA_TYPE_BIGINT: {
3427
      int64_t v = *(int64_t*)pv;
192,257✔
3428
      return v < pDiffInfo->prev.i64;
192,257✔
3429
    }
3430
    case TSDB_DATA_TYPE_FLOAT: {
283,867✔
3431
      float v = *(float*)pv;
283,867✔
3432
      return v < pDiffInfo->prev.d64;
283,867✔
3433
    }
3434
    case TSDB_DATA_TYPE_DOUBLE: {
196,447✔
3435
      double v = *(double*)pv;
196,447✔
3436
      return v < pDiffInfo->prev.d64;
196,447✔
3437
    }
3438
    default:
×
3439
      return false;
×
3440
  }
3441

3442
  return false;
3443
}
3444

3445
static void tryToSetInt64(SDiffInfo* pDiffInfo, int32_t type, SColumnInfoData* pOutput, int64_t v, int32_t pos) {
2,147,483,647✔
3446
  bool isNegative = v < pDiffInfo->prev.i64;
2,147,483,647✔
3447
  if (type == TSDB_DATA_TYPE_UBIGINT) {
2,147,483,647✔
3448
    isNegative = (uint64_t)v < (uint64_t)pDiffInfo->prev.i64;
95,281✔
3449
  }
3450
  int64_t delta = v - pDiffInfo->prev.i64;
2,147,483,647✔
3451
  if (isNegative && ignoreNegative(pDiffInfo->ignoreOption)) {
2,147,483,647✔
3452
    colDataSetNull_f_s(pOutput, pos);
328,552!
3453
    pOutput->hasNull = true;
328,552✔
3454
  } else {
3455
    colDataSetInt64(pOutput, pos, &delta);
2,147,483,647✔
3456
  }
3457
  pDiffInfo->prev.i64 = v;
2,147,483,647✔
3458
}
2,147,483,647✔
3459

3460
static void tryToSetDouble(SDiffInfo* pDiffInfo, SColumnInfoData* pOutput, double v, int32_t pos) {
40,147,882✔
3461
  double delta = v - pDiffInfo->prev.d64;
40,147,882✔
3462
  if (delta < 0 && ignoreNegative(pDiffInfo->ignoreOption)) {
40,147,882✔
3463
    colDataSetNull_f_s(pOutput, pos);
241,774!
3464
  } else {
3465
    colDataSetDouble(pOutput, pos, &delta);
39,906,108✔
3466
  }
3467
  pDiffInfo->prev.d64 = v;
40,147,882✔
3468
}
40,147,882✔
3469

3470
static int32_t doHandleDiff(SDiffInfo* pDiffInfo, int32_t type, const char* pv, SColumnInfoData* pOutput, int32_t pos,
2,147,483,647✔
3471
                            int64_t ts) {
3472
  if (!pDiffInfo->hasPrev) {
2,147,483,647!
3473
    colDataSetNull_f_s(pOutput, pos);
92,797!
3474
    return doSetPrevVal(pDiffInfo, type, pv, ts);
92,797✔
3475
  }
3476
  pDiffInfo->prevTs = ts;
2,147,483,647✔
3477
  switch (type) {
2,147,483,647!
3478
    case TSDB_DATA_TYPE_UINT: {
86,447✔
3479
      int64_t v = *(uint32_t*)pv;
86,447✔
3480
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
86,447✔
3481
      break;
86,447✔
3482
    }
3483
    case TSDB_DATA_TYPE_INT: {
1,141,209,032✔
3484
      int64_t v = *(int32_t*)pv;
1,141,209,032✔
3485
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
1,141,209,032✔
3486
      break;
1,141,209,032✔
3487
    }
3488
    case TSDB_DATA_TYPE_BOOL: {
6,427,309✔
3489
      int64_t v = *(bool*)pv;
6,427,309!
3490
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
6,427,309✔
3491
      break;
6,427,309✔
3492
    }
3493
    case TSDB_DATA_TYPE_UTINYINT: {
85,185✔
3494
      int64_t v = *(uint8_t*)pv;
85,185✔
3495
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
85,185✔
3496
      break;
85,185✔
3497
    }
3498
    case TSDB_DATA_TYPE_TINYINT: {
13,138,722✔
3499
      int64_t v = *(int8_t*)pv;
13,138,722✔
3500
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
13,138,722✔
3501
      break;
13,138,722✔
3502
    }
3503
    case TSDB_DATA_TYPE_USMALLINT: {
85,185✔
3504
      int64_t v = *(uint16_t*)pv;
85,185✔
3505
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
85,185✔
3506
      break;
85,185✔
3507
    }
3508
    case TSDB_DATA_TYPE_SMALLINT: {
13,453,845✔
3509
      int64_t v = *(int16_t*)pv;
13,453,845✔
3510
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
13,453,845✔
3511
      break;
13,453,845✔
3512
    }
3513
    case TSDB_DATA_TYPE_TIMESTAMP:
2,147,483,647✔
3514
    case TSDB_DATA_TYPE_UBIGINT:
3515
    case TSDB_DATA_TYPE_BIGINT: {
3516
      int64_t v = *(int64_t*)pv;
2,147,483,647✔
3517
      tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
2,147,483,647✔
3518
      break;
2,147,483,647✔
3519
    }
3520
    case TSDB_DATA_TYPE_FLOAT: {
19,900,407✔
3521
      double v = *(float*)pv;
19,900,407✔
3522
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
19,900,407✔
3523
      break;
19,900,407✔
3524
    }
3525
    case TSDB_DATA_TYPE_DOUBLE: {
20,247,475✔
3526
      double v = *(double*)pv;
20,247,475✔
3527
      tryToSetDouble(pDiffInfo, pOutput, v, pos);
20,247,475✔
3528
      break;
20,247,475✔
3529
    }
3530
    default:
×
3531
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
3532
  }
3533
  pDiffInfo->hasPrev = true;
2,147,483,647✔
3534
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3535
}
3536

3537
// TODO: the primary key compare can be skipped for ordered pk if knonwn before
3538
// TODO: for desc ordered, pk shall select the smallest one for one ts. if across block boundaries.
3539
bool funcInputGetNextRowIndex(SInputColumnInfoData* pInput, int32_t from, bool firstOccur, int32_t* pRowIndex,
2,147,483,647✔
3540
                              int32_t* nextFrom) {
3541
  if (pInput->pPrimaryKey == NULL) {
2,147,483,647✔
3542
    if (from == -1) {
2,147,483,647✔
3543
      from = pInput->startRowIndex;
2,147,483,647✔
3544
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
2,147,483,647✔
3545
      return false;
2,147,483,647✔
3546
    }
3547
    *pRowIndex = from;
2,147,483,647✔
3548
    *nextFrom = from + 1;
2,147,483,647✔
3549
    return true;
2,147,483,647✔
3550
  } else {
3551
    if (from == -1) {
15,907,753✔
3552
      from = pInput->startRowIndex;
4,504,258✔
3553
    } else if (from >= pInput->numOfRows + pInput->startRowIndex) {
11,403,495✔
3554
      return false;
4,504,258✔
3555
    }
3556
    TSKEY*           tsList = (int64_t*)pInput->pPTS->pData;
11,400,467✔
3557
    SColumnInfoData* pkCol = pInput->pPrimaryKey;
11,409,551✔
3558
    int8_t           pkType = pkCol->info.type;
11,407,280✔
3559
    int32_t          order = (firstOccur) ? TSDB_ORDER_ASC : TSDB_ORDER_DESC;
11,410,308✔
3560
    __compar_fn_t    compareFunc = getKeyComparFunc(pkType, order);
11,410,308✔
3561
    int32_t          select = from;
11,408,794✔
3562
    char*            val = colDataGetData(pkCol, select);
11,408,794!
3563
    while (from < pInput->numOfRows + pInput->startRowIndex - 1 && tsList[from + 1] == tsList[from]) {
22,134,269✔
3564
      char* val1 = colDataGetData(pkCol, from + 1);
10,726,989!
3565
      if (compareFunc(val1, val) < 0) {
10,717,905✔
3566
        select = from + 1;
1,022✔
3567
        val = val1;
1,022✔
3568
      }
3569
      from = from + 1;
10,718,662✔
3570
    }
3571
    *pRowIndex = select;
11,377,757✔
3572
    *nextFrom = from + 1;
11,407,280✔
3573
    return true;
11,403,495✔
3574
  }
3575
}
3576

3577
bool getForecastConfEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
×
3578
  pEnv->calcMemSize = sizeof(double);
×
3579
  return true;
×
3580
}
3581

3582
int32_t diffResultIsNull(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
2,147,483,647✔
3583
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3584
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3585

3586
  if (pRow->isDataNull || !pDiffInfo->hasPrev) {
2,147,483,647!
3587
    return true;
7,091,003✔
3588
  } else if (ignoreNegative(pDiffInfo->ignoreOption)) {
2,147,483,647✔
3589
    return diffIsNegtive(pDiffInfo, pCtx->input.pData[0]->info.type, pRow->pData);
1,186,859✔
3590
  }
3591
  return false;
2,147,483,647✔
3592
}
3593

3594
bool isFirstRow(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
2,147,483,647✔
3595
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3596
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3597
  return pDiffInfo->isFirstRow;
2,147,483,647!
3598
}
3599

3600
int32_t trySetPreVal(SqlFunctionCtx* pCtx, SFuncInputRow* pRow) {
2,768,878✔
3601
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,768,878✔
3602
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,768,878✔
3603
  pDiffInfo->isFirstRow = false;
2,768,878✔
3604
  if (pRow->isDataNull) {
2,768,878!
3605
    return TSDB_CODE_SUCCESS;
177,463✔
3606
  }
3607

3608
  SInputColumnInfoData* pInput = &pCtx->input;
2,591,415✔
3609
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,591,415✔
3610
  int8_t                inputType = pInputCol->info.type;
2,591,415✔
3611

3612
  char* pv = pRow->pData;
2,591,415✔
3613
  return doSetPrevVal(pDiffInfo, inputType, pv, pRow->ts);
2,591,415✔
3614
}
3615

3616
int32_t setDoDiffResult(SqlFunctionCtx* pCtx, SFuncInputRow* pRow, int32_t pos) {
2,147,483,647✔
3617
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
3618
  SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
3619

3620
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
3621
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
3622
  int8_t                inputType = pInputCol->info.type;
2,147,483,647✔
3623
  SColumnInfoData*      pOutput = (SColumnInfoData*)pCtx->pOutput;
2,147,483,647✔
3624
  int32_t               code = TSDB_CODE_SUCCESS;
2,147,483,647✔
3625
  if (pRow->isDataNull) {
2,147,483,647!
3626
    colDataSetNull_f_s(pOutput, pos);
4,240,055!
3627
    pOutput->hasNull = true;
4,240,055✔
3628

3629
    // handle selectivity
3630
    if (pCtx->subsidiaries.num > 0) {
4,240,055✔
3631
      code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
30,282✔
3632
      if (code != TSDB_CODE_SUCCESS) {
30,282!
3633
        return code;
×
3634
      }
3635
    }
3636
    return TSDB_CODE_SUCCESS;
4,240,055✔
3637
  }
3638

3639
  char* pv = pRow->pData;
2,147,483,647✔
3640

3641
  if (pRow->ts == pDiffInfo->prevTs) {
2,147,483,647✔
3642
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
11,519✔
3643
  }
3644
  code = doHandleDiff(pDiffInfo, inputType, pv, pOutput, pos, pRow->ts);
2,147,483,647✔
3645
  if (code != TSDB_CODE_SUCCESS) {
2,147,483,647!
3646
    return code;
×
3647
  }
3648
  // handle selectivity
3649
  if (pCtx->subsidiaries.num > 0) {
2,147,483,647✔
3650
    code = appendSelectivityCols(pCtx, pRow->block, pRow->rowIndex, pos);
2,147,483,647✔
3651
    if (code != TSDB_CODE_SUCCESS) {
2,147,483,647!
3652
      return code;
×
3653
    }
3654
  }
3655

3656
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
3657
}
3658

3659
int32_t diffFunction(SqlFunctionCtx* pCtx) { return TSDB_CODE_SUCCESS; }
24,050,319✔
3660

3661
int32_t diffFunctionByRow(SArray* pCtxArray) {
24,016,245✔
3662
  int32_t code = TSDB_CODE_SUCCESS;
24,016,245✔
3663
  int     diffColNum = pCtxArray->size;
24,016,245✔
3664
  if (diffColNum == 0) {
24,016,245!
3665
    return TSDB_CODE_SUCCESS;
×
3666
  }
3667
  int32_t numOfElems = 0;
24,016,245✔
3668

3669
  SArray* pRows = taosArrayInit_s(sizeof(SFuncInputRow), diffColNum);
24,016,245✔
3670
  if (NULL == pRows) {
24,016,245!
3671
    return terrno;
×
3672
  }
3673

3674
  bool keepNull = false;
24,016,245✔
3675
  for (int i = 0; i < diffColNum; ++i) {
48,066,564✔
3676
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
24,050,319✔
3677
    if (NULL == pCtx) {
24,050,319!
3678
      code = terrno;
×
3679
      goto _exit;
×
3680
    }
3681
    funcInputUpdate(pCtx);
24,050,319✔
3682
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
24,050,319✔
3683
    SDiffInfo*           pDiffInfo = GET_ROWCELL_INTERBUF(pResInfo);
24,050,319✔
3684
    if (!ignoreNull(pDiffInfo->ignoreOption)) {
24,050,319✔
3685
      keepNull = true;
24,024,448✔
3686
    }
3687
  }
3688

3689
  SqlFunctionCtx* pCtx0 = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, 0);
24,016,245✔
3690
  SFuncInputRow*  pRow0 = (SFuncInputRow*)taosArrayGet(pRows, 0);
24,016,245✔
3691
  if (NULL == pCtx0 || NULL == pRow0) {
24,016,245!
3692
    code = terrno;
×
3693
    goto _exit;
×
3694
  }
3695
  int32_t startOffset = pCtx0->offset;
24,016,245✔
3696
  bool    result = false;
24,016,245✔
3697
  while (1) {
2,147,483,647✔
3698
    code = funcInputGetNextRow(pCtx0, pRow0, &result);
2,147,483,647✔
3699
    if (TSDB_CODE_SUCCESS != code) {
2,147,483,647!
3700
      goto _exit;
×
3701
    }
3702
    if (!result) {
2,147,483,647!
3703
      break;
24,004,726✔
3704
    }
3705
    bool hasNotNullValue = !diffResultIsNull(pCtx0, pRow0);
2,147,483,647✔
3706
    for (int i = 1; i < diffColNum; ++i) {
2,147,483,647✔
3707
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
7,255,238✔
3708
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
7,255,238✔
3709
      if (NULL == pCtx || NULL == pRow) {
7,255,238!
3710
        code = terrno;
×
3711
        goto _exit;
×
3712
      }
3713
      code = funcInputGetNextRow(pCtx, pRow, &result);
7,255,238✔
3714
      if (TSDB_CODE_SUCCESS != code) {
7,255,238!
3715
        goto _exit;
×
3716
      }
3717
      if (!result) {
7,255,238!
3718
        // rows are not equal
3719
        code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
×
3720
        goto _exit;
×
3721
      }
3722
      if (!diffResultIsNull(pCtx, pRow)) {
7,255,238✔
3723
        hasNotNullValue = true;
7,161,850✔
3724
      }
3725
    }
3726
    int32_t pos = startOffset + numOfElems;
2,147,483,647✔
3727

3728
    bool newRow = false;
2,147,483,647✔
3729
    for (int i = 0; i < diffColNum; ++i) {
2,147,483,647✔
3730
      SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
2,147,483,647✔
3731
      SFuncInputRow*  pRow = (SFuncInputRow*)taosArrayGet(pRows, i);
2,147,483,647✔
3732
      if (NULL == pCtx || NULL == pRow) {
2,147,483,647!
3733
        code = terrno;
×
3734
        goto _exit;
×
3735
      }
3736
      if ((keepNull || hasNotNullValue) && !isFirstRow(pCtx, pRow)) {
2,147,483,647✔
3737
        code = setDoDiffResult(pCtx, pRow, pos);
2,147,483,647✔
3738
        if (code != TSDB_CODE_SUCCESS) {
2,147,483,647✔
3739
          goto _exit;
11,519✔
3740
        }
3741
        newRow = true;
2,147,483,647✔
3742
      } else {
3743
        code = trySetPreVal(pCtx, pRow);
2,768,878✔
3744
        if (code != TSDB_CODE_SUCCESS) {
2,768,878!
3745
          goto _exit;
×
3746
        }
3747
      }
3748
    }
3749
    if (newRow) ++numOfElems;
2,147,483,647✔
3750
  }
3751

3752
  for (int i = 0; i < diffColNum; ++i) {
48,042,895✔
3753
    SqlFunctionCtx* pCtx = *(SqlFunctionCtx**)taosArrayGet(pCtxArray, i);
24,038,169✔
3754
    if (NULL == pCtx) {
24,038,169!
3755
      code = terrno;
×
3756
      goto _exit;
×
3757
    }
3758
    SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
24,038,169✔
3759
    pResInfo->numOfRes = numOfElems;
24,038,169✔
3760
  }
3761

3762
_exit:
24,016,245✔
3763
  if (pRows) {
24,016,245!
3764
    taosArrayDestroy(pRows);
24,016,245✔
3765
    pRows = NULL;
24,016,245✔
3766
  }
3767
  return code;
24,016,245✔
3768
}
3769

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

3772
bool getTopBotFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
2,177,751✔
3773
  SValueNode* pkNode = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
2,177,751✔
3774
  pEnv->calcMemSize = sizeof(STopBotRes) + pkNode->datum.i * sizeof(STopBotResItem);
2,177,751✔
3775
  return true;
2,177,118✔
3776
}
3777

3778
int32_t topBotFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
8,965,989✔
3779
  if (pResInfo->initialized) {
8,965,989!
3780
    return TSDB_CODE_SUCCESS;
×
3781
  }
3782
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
8,965,989!
3783
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
3784
  }
3785

3786
  STopBotRes*           pRes = GET_ROWCELL_INTERBUF(pResInfo);
8,966,503✔
3787
  SInputColumnInfoData* pInput = &pCtx->input;
8,966,503✔
3788

3789
  pRes->maxSize = pCtx->param[1].param.i;
8,966,503✔
3790

3791
  pRes->nullTupleSaved = false;
8,965,890✔
3792
  pRes->nullTuplePos.pageId = -1;
8,965,277✔
3793
  return TSDB_CODE_SUCCESS;
8,966,503✔
3794
}
3795

3796
static STopBotRes* getTopBotOutputInfo(SqlFunctionCtx* pCtx) {
1,017,182,665✔
3797
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,017,182,665✔
3798
  STopBotRes*          pRes = GET_ROWCELL_INTERBUF(pResInfo);
1,017,204,916✔
3799
  pRes->pItems = (STopBotResItem*)((char*)pRes + sizeof(STopBotRes));
1,017,215,758✔
3800

3801
  return pRes;
1,017,519,499✔
3802
}
3803

3804
static int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock,
3805
                               uint16_t type, uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery);
3806

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

3809
int32_t topFunction(SqlFunctionCtx* pCtx) {
9,077,366✔
3810
  int32_t              numOfElems = 0;
9,077,366✔
3811
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
9,077,366✔
3812

3813
  SInputColumnInfoData* pInput = &pCtx->input;
9,078,592✔
3814
  SColumnInfoData*      pCol = pInput->pData[0];
9,078,592✔
3815

3816
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
9,079,205✔
3817
  pRes->type = pInput->pData[0]->info.type;
9,078,592✔
3818

3819
  int32_t start = pInput->startRowIndex;
9,079,205✔
3820
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
671,554,888✔
3821
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
663,881,159!
3822
      continue;
1,492,434✔
3823
    }
3824

3825
    numOfElems++;
662,113,272✔
3826
    char*   data = colDataGetData(pCol, i);
662,113,272!
3827
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, true);
663,148,632✔
3828
    if (code != TSDB_CODE_SUCCESS) {
660,984,475!
3829
      return code;
×
3830
    }
3831
  }
3832

3833
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
9,078,592!
3834
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
6,797✔
3835
    if (code != TSDB_CODE_SUCCESS) {
6,797!
3836
      return code;
×
3837
    }
3838
    pRes->nullTupleSaved = true;
6,797✔
3839
  }
3840
  return TSDB_CODE_SUCCESS;
9,077,979✔
3841
}
3842

3843
int32_t bottomFunction(SqlFunctionCtx* pCtx) {
806,454✔
3844
  int32_t              numOfElems = 0;
806,454✔
3845
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
806,454✔
3846

3847
  SInputColumnInfoData* pInput = &pCtx->input;
806,454✔
3848
  SColumnInfoData*      pCol = pInput->pData[0];
806,454✔
3849

3850
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
806,454✔
3851
  pRes->type = pInput->pData[0]->info.type;
806,454✔
3852

3853
  int32_t start = pInput->startRowIndex;
806,454✔
3854
  for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
337,315,805✔
3855
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
336,510,007!
3856
      continue;
1,271,570✔
3857
    }
3858

3859
    numOfElems++;
335,239,068✔
3860
    char*   data = colDataGetData(pCol, i);
335,239,068!
3861
    int32_t code = doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, false);
335,252,729✔
3862
    if (code != TSDB_CODE_SUCCESS) {
335,237,781!
3863
      return code;
×
3864
    }
3865
  }
3866

3867
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
806,454!
3868
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
5,263✔
3869
    if (code != TSDB_CODE_SUCCESS) {
5,263!
3870
      return code;
×
3871
    }
3872
    pRes->nullTupleSaved = true;
5,263✔
3873
  }
3874

3875
  return TSDB_CODE_SUCCESS;
806,454✔
3876
}
3877

3878
static int32_t topBotResComparFn(const void* p1, const void* p2, const void* param) {
494,406,513✔
3879
  uint16_t type = *(uint16_t*)param;
494,406,513✔
3880

3881
  STopBotResItem* val1 = (STopBotResItem*)p1;
494,406,673✔
3882
  STopBotResItem* val2 = (STopBotResItem*)p2;
494,406,673✔
3883

3884
  if (IS_SIGNED_NUMERIC_TYPE(type)) {
494,406,673!
3885
    if (val1->v.i == val2->v.i) {
271,454,663✔
3886
      return 0;
55,387,910✔
3887
    }
3888

3889
    return (val1->v.i > val2->v.i) ? 1 : -1;
216,895,158✔
3890
  } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
222,952,010!
3891
    if (val1->v.u == val2->v.u) {
105,870,115✔
3892
      return 0;
21,962,931✔
3893
    }
3894

3895
    return (val1->v.u > val2->v.u) ? 1 : -1;
84,563,370✔
3896
  } else if (TSDB_DATA_TYPE_FLOAT == type) {
117,081,895✔
3897
    if (val1->v.f == val2->v.f) {
1,278,533✔
3898
      return 0;
39,753✔
3899
    }
3900

3901
    return (val1->v.f > val2->v.f) ? 1 : -1;
1,238,780✔
3902
  }
3903

3904
  if (val1->v.d == val2->v.d) {
115,803,362✔
3905
    return 0;
6,941✔
3906
  }
3907

3908
  return (val1->v.d > val2->v.d) ? 1 : -1;
115,859,009✔
3909
}
3910

3911
int32_t doAddIntoResult(SqlFunctionCtx* pCtx, void* pData, int32_t rowIndex, SSDataBlock* pSrcBlock, uint16_t type,
997,493,419✔
3912
                        uint64_t uid, SResultRowEntryInfo* pEntryInfo, bool isTopQuery) {
3913
  STopBotRes* pRes = getTopBotOutputInfo(pCtx);
997,493,419✔
3914
  int32_t     code = TSDB_CODE_SUCCESS;
998,584,402✔
3915

3916
  SVariant val = {0};
998,584,402✔
3917
  TAOS_CHECK_RETURN(taosVariantCreateFromBinary(&val, pData, tDataTypes[type].bytes, type));
999,057,789!
3918

3919
  STopBotResItem* pItems = pRes->pItems;
997,470,677✔
3920

3921
  // not full yet
3922
  if (pEntryInfo->numOfRes < pRes->maxSize) {
997,897,319✔
3923
    STopBotResItem* pItem = &pItems[pEntryInfo->numOfRes];
48,941,300✔
3924
    pItem->v = val;
48,941,300✔
3925
    pItem->uid = uid;
48,941,300✔
3926

3927
    // save the data of this tuple
3928
    if (pCtx->subsidiaries.num > 0) {
48,942,724✔
3929
      code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
9,726,425✔
3930
      if (code != TSDB_CODE_SUCCESS) {
9,722,727!
3931
        return code;
×
3932
      }
3933
    }
3934
#ifdef BUF_PAGE_DEBUG
3935
    qDebug("page_saveTuple i:%d, item:%p,pageId:%d, offset:%d\n", pEntryInfo->numOfRes, pItem, pItem->tuplePos.pageId,
3936
           pItem->tuplePos.offset);
3937
#endif
3938
    // allocate the buffer and keep the data of this row into the new allocated buffer
3939
    pEntryInfo->numOfRes++;
48,937,800✔
3940
    code = taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type,
48,940,865✔
3941
                        topBotResComparFn, !isTopQuery);
48,939,639✔
3942
    if (code != TSDB_CODE_SUCCESS) {
48,942,012!
3943
      return code;
×
3944
    }
3945
  } else {  // replace the minimum value in the result
3946
    if ((isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i > pItems[0].v.i) ||
948,312,321!
3947
                        (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u > pItems[0].v.u) ||
601,796,561!
3948
                        (TSDB_DATA_TYPE_FLOAT == type && val.f > pItems[0].v.f) ||
590,435,799✔
3949
                        (TSDB_DATA_TYPE_DOUBLE == type && val.d > pItems[0].v.d))) ||
590,570,272✔
3950
        (!isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && val.i < pItems[0].v.i) ||
909,283,666!
3951
                         (IS_UNSIGNED_NUMERIC_TYPE(type) && val.u < pItems[0].v.u) ||
330,296,459!
3952
                         (TSDB_DATA_TYPE_FLOAT == type && val.f < pItems[0].v.f) ||
330,035,392✔
3953
                         (TSDB_DATA_TYPE_DOUBLE == type && val.d < pItems[0].v.d)))) {
329,985,660✔
3954
      // replace the old data and the coresponding tuple data
3955
      STopBotResItem* pItem = &pItems[0];
40,729,168✔
3956
      pItem->v = val;
40,729,168✔
3957
      pItem->uid = uid;
41,007,617✔
3958

3959
      // save the data of this tuple by over writing the old data
3960
      if (pCtx->subsidiaries.num > 0) {
41,011,394✔
3961
        code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pItem->tuplePos);
25,181,068✔
3962
        if (code != TSDB_CODE_SUCCESS) {
25,177,390!
3963
          return code;
×
3964
        }
3965
      }
3966
#ifdef BUF_PAGE_DEBUG
3967
      qDebug("page_copyTuple pageId:%d, offset:%d", pItem->tuplePos.pageId, pItem->tuplePos.offset);
3968
#endif
3969
      code = taosheapadjust((void*)pItems, sizeof(STopBotResItem), 0, pEntryInfo->numOfRes - 1, (const void*)&type,
41,007,103✔
3970
                            topBotResComparFn, NULL, !isTopQuery);
41,007,103✔
3971
      if (code != TSDB_CODE_SUCCESS) {
41,003,958!
3972
        return code;
×
3973
      }
3974
    }
3975
  }
3976

3977
  return TSDB_CODE_SUCCESS;
997,625,041✔
3978
}
3979

3980
/*
3981
 * +------------------------------------+--------------+--------------+
3982
 * |            null bitmap             |              |              |
3983
 * |(n columns, one bit for each column)| src column #1| src column #2|
3984
 * +------------------------------------+--------------+--------------+
3985
 */
3986
int32_t serializeTupleData(const SSDataBlock* pSrcBlock, int32_t rowIndex, SSubsidiaryResInfo* pSubsidiaryies,
97,128,982✔
3987
                           char* buf, char** res) {
3988
  char* nullList = buf;
97,128,982✔
3989
  char* pStart = (char*)(nullList + sizeof(bool) * pSubsidiaryies->num);
97,128,982✔
3990

3991
  int32_t offset = 0;
97,127,680✔
3992
  for (int32_t i = 0; i < pSubsidiaryies->num; ++i) {
300,362,555✔
3993
    SqlFunctionCtx* pc = pSubsidiaryies->pCtx[i];
203,235,038✔
3994

3995
    // group_key function has its own process function
3996
    // do not process there
3997
    if (fmIsGroupKeyFunc(pc->functionId)) {
203,234,722!
3998
      continue;
×
3999
    }
4000

4001
    SFunctParam* pFuncParam = &pc->pExpr->base.pParam[0];
203,232,069✔
4002
    int32_t      srcSlotId = pFuncParam->pCol->slotId;
203,232,572✔
4003

4004
    SColumnInfoData* pCol = taosArrayGet(pSrcBlock->pDataBlock, srcSlotId);
203,232,663✔
4005
    if (NULL == pCol) {
203,233,683!
4006
      return TSDB_CODE_OUT_OF_RANGE;
×
4007
    }
4008
    if ((nullList[i] = colDataIsNull_s(pCol, rowIndex)) == true) {
406,469,589!
4009
      offset += pCol->info.bytes;
57,293,641✔
4010
      continue;
57,293,641✔
4011
    }
4012

4013
    char* p = colDataGetData(pCol, rowIndex);
145,933,404!
4014
    if (IS_VAR_DATA_TYPE(pCol->info.type)) {
145,939,219!
4015
      int32_t bytes = calcStrBytesByType(pCol->info.type, p);
11,155,384✔
4016
      (void)memcpy(pStart + offset, p, bytes);
11,153,214!
4017
    } else {
4018
      (void)memcpy(pStart + offset, p, pCol->info.bytes);
134,783,763!
4019
    }
4020

4021
    offset += pCol->info.bytes;
145,939,539✔
4022
  }
4023

4024
  *res = buf;
97,117,237✔
4025
  return TSDB_CODE_SUCCESS;
97,134,537✔
4026
}
4027

4028
static int32_t doSaveTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, SWinKey* key,
123,283,106✔
4029
                               STuplePos* pPos, SFunctionStateStore* pStore) {
4030
  STuplePos p = {0};
123,283,106✔
4031
  if (pHandle->pBuf != NULL) {
123,283,106✔
4032
    SFilePage* pPage = NULL;
123,281,880✔
4033

4034
    if (pHandle->currentPage == -1) {
123,281,880✔
4035
      pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
4,635,997✔
4036
      if (pPage == NULL) {
4,642,936!
4037
        return terrno;
×
4038
      }
4039
      pPage->num = sizeof(SFilePage);
4,642,936✔
4040
    } else {
4041
      pPage = getBufPage(pHandle->pBuf, pHandle->currentPage);
118,644,125✔
4042
      if (pPage == NULL) {
118,643,492!
4043
        return terrno;
×
4044
      }
4045
      if (pPage->num + length > getBufPageSize(pHandle->pBuf)) {
118,643,492✔
4046
        // current page is all used, let's prepare a new buffer page
4047
        releaseBufPage(pHandle->pBuf, pPage);
40,410✔
4048
        pPage = getNewBufPage(pHandle->pBuf, &pHandle->currentPage);
40,410✔
4049
        if (pPage == NULL) {
40,410!
4050
          return terrno;
×
4051
        }
4052
        pPage->num = sizeof(SFilePage);
40,410✔
4053
      }
4054
    }
4055

4056
    p = (STuplePos){.pageId = pHandle->currentPage, .offset = pPage->num};
123,286,227✔
4057
    (void)memcpy(pPage->data + pPage->num, pBuf, length);
123,285,595!
4058

4059
    pPage->num += length;
123,286,839✔
4060
    setBufPageDirty(pPage, true);
123,286,860✔
4061
    releaseBufPage(pHandle->pBuf, pPage);
123,285,815✔
4062
  } else {  // other tuple save policy
4063
    if (pStore->streamStateFuncPut(pHandle->pState, key, pBuf, length) >= 0) {
2,040!
4064
      p.streamTupleKey = *key;
×
4065
    }
4066
  }
4067

4068
  *pPos = p;
123,283,775✔
4069
  return TSDB_CODE_SUCCESS;
123,283,775✔
4070
}
4071

4072
int32_t saveTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
69,037,450✔
4073
  int32_t code = prepareBuf(pCtx);
69,037,450✔
4074
  if (TSDB_CODE_SUCCESS != code) {
69,037,443!
4075
    return code;
×
4076
  }
4077

4078
  SWinKey key = {0};
69,037,443✔
4079
  if (pCtx->saveHandle.pBuf == NULL) {
69,038,669!
4080
    SColumnInfoData* pColInfo = taosArrayGet(pSrcBlock->pDataBlock, pCtx->saveHandle.pState->tsIndex);
×
4081
    if (NULL == pColInfo) {
×
4082
      return TSDB_CODE_OUT_OF_RANGE;
×
4083
    }
4084
    if (pColInfo->info.type != TSDB_DATA_TYPE_TIMESTAMP) {
×
4085
      return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4086
    }
4087
    key.groupId = pSrcBlock->info.id.groupId;
×
4088
    key.ts = *(int64_t*)colDataGetData(pColInfo, rowIndex);
×
4089
    key.numInGroup = pCtx->pExpr->pExpr->_function.bindExprID;
×
4090
  }
4091

4092
  char* buf = NULL;
69,036,031✔
4093
  code = serializeTupleData(pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
69,037,424✔
4094
  if (TSDB_CODE_SUCCESS != code) {
69,039,263!
4095
    return code;
×
4096
  }
4097
  return doSaveTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, &key, pPos, pCtx->pStore);
69,039,263✔
4098
}
4099

4100
static int32_t doUpdateTupleData(SSerializeDataHandle* pHandle, const void* pBuf, size_t length, STuplePos* pPos,
28,094,010✔
4101
                                 SFunctionStateStore* pStore) {
4102
  if (pHandle->pBuf != NULL) {
28,094,010!
4103
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
28,095,236✔
4104
    if (pPage == NULL) {
28,093,751!
4105
      return terrno;
×
4106
    }
4107
    (void)memcpy(pPage->data + pPos->offset, pBuf, length);
28,093,751!
4108
    setBufPageDirty(pPage, true);
28,093,751✔
4109
    releaseBufPage(pHandle->pBuf, pPage);
28,095,236✔
4110
  } else {
4111
    int32_t code = pStore->streamStateFuncPut(pHandle->pState, &pPos->streamTupleKey, pBuf, length);
×
4112
    if (TSDB_CODE_SUCCESS != code) {
×
4113
      return code;
×
4114
    }
4115
  }
4116

4117
  return TSDB_CODE_SUCCESS;
28,092,525✔
4118
}
4119

4120
int32_t updateTupleData(SqlFunctionCtx* pCtx, int32_t rowIndex, const SSDataBlock* pSrcBlock, STuplePos* pPos) {
28,096,108✔
4121
  int32_t code = prepareBuf(pCtx);
28,096,108✔
4122
  if (TSDB_CODE_SUCCESS != code) {
28,095,849!
4123
    return code;
×
4124
  }
4125

4126
  char* buf = NULL;
28,095,849✔
4127
  code = serializeTupleData(pSrcBlock, rowIndex, &pCtx->subsidiaries, pCtx->subsidiaries.buf, &buf);
28,095,849✔
4128
  if (TSDB_CODE_SUCCESS != code) {
28,044,357!
4129
    return code;
×
4130
  }
4131
  return doUpdateTupleData(&pCtx->saveHandle, buf, pCtx->subsidiaries.rowLen, pPos, pCtx->pStore);
28,044,357✔
4132
}
4133

4134
static int32_t doLoadTupleData(SSerializeDataHandle* pHandle, const STuplePos* pPos, SFunctionStateStore* pStore,
69,136,651✔
4135
                               char** value) {
4136
  if (pHandle->pBuf != NULL) {
69,136,651!
4137
    SFilePage* pPage = getBufPage(pHandle->pBuf, pPos->pageId);
69,138,547✔
4138
    if (pPage == NULL) {
69,136,018!
4139
      *value = NULL;
×
4140
      return terrno;
×
4141
    }
4142
    *value = pPage->data + pPos->offset;
69,136,018✔
4143
    releaseBufPage(pHandle->pBuf, pPage);
69,135,384✔
4144
    return TSDB_CODE_SUCCESS;
69,136,016✔
4145
  } else {
UNCOV
4146
    *value = NULL;
×
4147
    int32_t vLen;
×
4148
    int32_t code = pStore->streamStateFuncGet(pHandle->pState, &pPos->streamTupleKey, (void**)(value), &vLen);
×
4149
    if (TSDB_CODE_SUCCESS != code) {
×
4150
      return code;
×
4151
    }
4152
    return TSDB_CODE_SUCCESS;
×
4153
  }
4154
}
4155

4156
int32_t loadTupleData(SqlFunctionCtx* pCtx, const STuplePos* pPos, char** value) {
69,136,651✔
4157
  return doLoadTupleData(&pCtx->saveHandle, pPos, pCtx->pStore, value);
69,136,651✔
4158
}
4159

4160
int32_t topBotFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
8,967,927✔
4161
  int32_t code = TSDB_CODE_SUCCESS;
8,967,927✔
4162

4163
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
8,967,927✔
4164
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
8,967,927✔
4165

4166
  int16_t type = pCtx->pExpr->base.resSchema.type;
8,967,294✔
4167
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
8,967,927✔
4168

4169
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
8,967,294✔
4170
  if (NULL == pCol) {
8,967,927!
4171
    return TSDB_CODE_OUT_OF_RANGE;
×
4172
  }
4173

4174
  // todo assign the tag value and the corresponding row data
4175
  int32_t currentRow = pBlock->info.rows;
8,967,927✔
4176
  if (pEntryInfo->numOfRes <= 0) {
8,967,927✔
4177
    colDataSetNULL(pCol, currentRow);
29,436!
4178
    code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, currentRow);
29,436✔
4179
    return code;
29,436✔
4180
  }
4181
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
57,882,639✔
4182
    STopBotResItem* pItem = &pRes->pItems[i];
48,944,148✔
4183
    code = colDataSetVal(pCol, currentRow, (const char*)&pItem->v.i, false);
48,944,148✔
4184
    if (TSDB_CODE_SUCCESS != code) {
48,944,148!
4185
      return code;
×
4186
    }
4187
#ifdef BUF_PAGE_DEBUG
4188
    qDebug("page_finalize i:%d,item:%p,pageId:%d, offset:%d\n", i, pItem, pItem->tuplePos.pageId,
4189
           pItem->tuplePos.offset);
4190
#endif
4191
    code = setSelectivityValue(pCtx, pBlock, &pRes->pItems[i].tuplePos, currentRow);
48,944,148✔
4192
    if (TSDB_CODE_SUCCESS != code) {
48,944,148!
4193
      return code;
×
4194
    }
4195
    currentRow += 1;
48,944,148✔
4196
  }
4197

4198
  return code;
8,938,491✔
4199
}
4200

4201
int32_t addResult(SqlFunctionCtx* pCtx, STopBotResItem* pSourceItem, int16_t type, bool isTopQuery) {
×
4202
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
×
4203
  STopBotRes*          pRes = getTopBotOutputInfo(pCtx);
×
4204
  STopBotResItem*      pItems = pRes->pItems;
×
4205
  int32_t              code = TSDB_CODE_SUCCESS;
×
4206

4207
  // not full yet
4208
  if (pEntryInfo->numOfRes < pRes->maxSize) {
×
4209
    STopBotResItem* pItem = &pItems[pEntryInfo->numOfRes];
×
4210
    pItem->v = pSourceItem->v;
×
4211
    pItem->uid = pSourceItem->uid;
×
4212
    pItem->tuplePos.pageId = -1;
×
4213
    replaceTupleData(&pItem->tuplePos, &pSourceItem->tuplePos);
×
4214
    pEntryInfo->numOfRes++;
×
4215
    code = taosheapsort((void*)pItems, sizeof(STopBotResItem), pEntryInfo->numOfRes, (const void*)&type,
×
4216
                        topBotResComparFn, !isTopQuery);
×
4217
    if (TSDB_CODE_SUCCESS != code) {
×
4218
      return code;
×
4219
    }
4220
  } else {  // replace the minimum value in the result
4221
    if ((isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && pSourceItem->v.i > pItems[0].v.i) ||
×
4222
                        (IS_UNSIGNED_NUMERIC_TYPE(type) && pSourceItem->v.u > pItems[0].v.u) ||
×
4223
                        (TSDB_DATA_TYPE_FLOAT == type && pSourceItem->v.f > pItems[0].v.f) ||
×
4224
                        (TSDB_DATA_TYPE_DOUBLE == type && pSourceItem->v.d > pItems[0].v.d))) ||
×
4225
        (!isTopQuery && ((IS_SIGNED_NUMERIC_TYPE(type) && pSourceItem->v.i < pItems[0].v.i) ||
×
4226
                         (IS_UNSIGNED_NUMERIC_TYPE(type) && pSourceItem->v.u < pItems[0].v.u) ||
×
4227
                         (TSDB_DATA_TYPE_FLOAT == type && pSourceItem->v.f < pItems[0].v.f) ||
×
4228
                         (TSDB_DATA_TYPE_DOUBLE == type && pSourceItem->v.d < pItems[0].v.d)))) {
×
4229
      // replace the old data and the coresponding tuple data
4230
      STopBotResItem* pItem = &pItems[0];
×
4231
      pItem->v = pSourceItem->v;
×
4232
      pItem->uid = pSourceItem->uid;
×
4233

4234
      // save the data of this tuple by over writing the old data
4235
      replaceTupleData(&pItem->tuplePos, &pSourceItem->tuplePos);
×
4236
      code = taosheapadjust((void*)pItems, sizeof(STopBotResItem), 0, pEntryInfo->numOfRes - 1, (const void*)&type,
×
4237
                            topBotResComparFn, NULL, !isTopQuery);
×
4238
      if (TSDB_CODE_SUCCESS != code) {
×
4239
        return code;
×
4240
      }
4241
    }
4242
  }
4243
  return code;
×
4244
}
4245

4246
int32_t topCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4247
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4248
  STopBotRes*          pSBuf = getTopBotOutputInfo(pSourceCtx);
×
4249
  int16_t              type = pSBuf->type;
×
4250
  int32_t              code = TSDB_CODE_SUCCESS;
×
4251
  for (int32_t i = 0; i < pSResInfo->numOfRes; i++) {
×
4252
    code = addResult(pDestCtx, pSBuf->pItems + i, type, true);
×
4253
    if (TSDB_CODE_SUCCESS != code) {
×
4254
      return code;
×
4255
    }
4256
  }
4257
  return TSDB_CODE_SUCCESS;
×
4258
}
4259

4260
int32_t bottomCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4261
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4262
  STopBotRes*          pSBuf = getTopBotOutputInfo(pSourceCtx);
×
4263
  int16_t              type = pSBuf->type;
×
4264
  int32_t              code = TSDB_CODE_SUCCESS;
×
4265
  for (int32_t i = 0; i < pSResInfo->numOfRes; i++) {
×
4266
    code = addResult(pDestCtx, pSBuf->pItems + i, type, false);
×
4267
    if (TSDB_CODE_SUCCESS != code) {
×
4268
      return code;
×
4269
    }
4270
  }
4271
  return TSDB_CODE_SUCCESS;
×
4272
}
4273

4274
int32_t getSpreadInfoSize() { return (int32_t)sizeof(SSpreadInfo); }
9,518,547✔
4275

4276
bool getSpreadFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
2,014,718✔
4277
  pEnv->calcMemSize = sizeof(SSpreadInfo);
2,014,718✔
4278
  return true;
2,015,164✔
4279
}
4280

4281
int32_t spreadFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
70,865,558✔
4282
  if (pResultInfo->initialized) {
70,865,558!
4283
    return TSDB_CODE_SUCCESS;
×
4284
  }
4285
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
70,869,323!
4286
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4287
  }
4288

4289
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
70,872,938✔
4290
  SET_DOUBLE_VAL(&pInfo->min, DBL_MAX);
70,872,938✔
4291
  SET_DOUBLE_VAL(&pInfo->max, -DBL_MAX);
70,873,384✔
4292
  pInfo->hasResult = false;
70,872,927✔
4293
  return TSDB_CODE_SUCCESS;
70,873,150✔
4294
}
4295

4296
int32_t spreadFunction(SqlFunctionCtx* pCtx) {
75,847,623✔
4297
  int32_t numOfElems = 0;
75,847,623✔
4298

4299
  // Only the pre-computing information loaded and actual data does not loaded
4300
  SInputColumnInfoData* pInput = &pCtx->input;
75,847,623✔
4301
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
75,849,751✔
4302
  int32_t               type = pInput->pData[0]->info.type;
75,850,416✔
4303

4304
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
75,852,529✔
4305

4306
  if (pInput->colDataSMAIsSet) {
75,851,103!
4307
    numOfElems = pInput->numOfRows - pAgg->numOfNull;
×
4308
    if (numOfElems == 0) {
×
4309
      goto _spread_over;
×
4310
    }
4311
    double tmin = 0.0, tmax = 0.0;
×
4312
    if (IS_SIGNED_NUMERIC_TYPE(type) || IS_TIMESTAMP_TYPE(type)) {
×
4313
      tmin = (double)GET_INT64_VAL(&pAgg->min);
×
4314
      tmax = (double)GET_INT64_VAL(&pAgg->max);
×
4315
    } else if (IS_FLOAT_TYPE(type)) {
×
4316
      tmin = GET_DOUBLE_VAL(&pAgg->min);
×
4317
      tmax = GET_DOUBLE_VAL(&pAgg->max);
×
4318
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
×
4319
      tmin = (double)GET_UINT64_VAL(&pAgg->min);
×
4320
      tmax = (double)GET_UINT64_VAL(&pAgg->max);
×
4321
    }
4322

4323
    if (GET_DOUBLE_VAL(&pInfo->min) > tmin) {
×
4324
      SET_DOUBLE_VAL(&pInfo->min, tmin);
×
4325
    }
4326

4327
    if (GET_DOUBLE_VAL(&pInfo->max) < tmax) {
×
4328
      SET_DOUBLE_VAL(&pInfo->max, tmax);
×
4329
    }
4330

4331
  } else {  // computing based on the true data block
4332
    SColumnInfoData* pCol = pInput->pData[0];
75,849,048✔
4333

4334
    int32_t start = pInput->startRowIndex;
75,850,021✔
4335
    // check the valid data one by one
4336
    for (int32_t i = start; i < pInput->numOfRows + start; ++i) {
553,601,987✔
4337
      if (colDataIsNull_f(pCol, i)) {
477,755,218!
4338
        continue;
73,099,509✔
4339
      }
4340

4341
      char* data = colDataGetData(pCol, i);
404,650,887!
4342

4343
      double v = 0;
404,653,504✔
4344
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
404,653,504!
4345
      if (v < GET_DOUBLE_VAL(&pInfo->min)) {
404,649,528✔
4346
        SET_DOUBLE_VAL(&pInfo->min, v);
66,353,368✔
4347
      }
4348

4349
      if (v > GET_DOUBLE_VAL(&pInfo->max)) {
404,652,171✔
4350
        SET_DOUBLE_VAL(&pInfo->max, v);
89,899,115✔
4351
      }
4352

4353
      numOfElems += 1;
404,651,294✔
4354
    }
4355
  }
4356

4357
_spread_over:
75,849,646✔
4358
  // data in the check operation are all null, not output
4359
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
75,849,646✔
4360
  if (numOfElems > 0) {
75,848,688✔
4361
    pInfo->hasResult = true;
74,174,146✔
4362
  }
4363

4364
  return TSDB_CODE_SUCCESS;
75,849,412✔
4365
}
4366

4367
static void spreadTransferInfo(SSpreadInfo* pInput, SSpreadInfo* pOutput) {
9,368,353✔
4368
  pOutput->hasResult = pInput->hasResult;
9,368,353!
4369
  if (pInput->max > pOutput->max) {
9,368,353✔
4370
    pOutput->max = pInput->max;
6,542,526✔
4371
  }
4372

4373
  if (pInput->min < pOutput->min) {
9,368,353✔
4374
    pOutput->min = pInput->min;
6,541,866✔
4375
  }
4376
}
9,368,353✔
4377

4378
int32_t spreadFunctionMerge(SqlFunctionCtx* pCtx) {
6,585,734✔
4379
  SInputColumnInfoData* pInput = &pCtx->input;
6,585,734✔
4380
  SColumnInfoData*      pCol = pInput->pData[0];
6,585,734✔
4381

4382
  if (IS_NULL_TYPE(pCol->info.type)) {
6,585,734!
4383
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
4384
    return TSDB_CODE_SUCCESS;
×
4385
  }
4386

4387
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
6,585,734!
4388
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4389
  }
4390

4391
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
6,585,734✔
4392

4393
  int32_t start = pInput->startRowIndex;
6,585,734✔
4394
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
15,971,060✔
4395
    if (colDataIsNull_s(pCol, i)) continue;
18,770,652!
4396
    char*        data = colDataGetData(pCol, i);
9,385,326!
4397
    SSpreadInfo* pInputInfo = (SSpreadInfo*)varDataVal(data);
9,385,326✔
4398
    if (pInputInfo->hasResult) {
9,385,326!
4399
      spreadTransferInfo(pInputInfo, pInfo);
9,368,353✔
4400
    }
4401
  }
4402

4403
  if (pInfo->hasResult) {
6,585,734!
4404
    GET_RES_INFO(pCtx)->numOfRes = 1;
6,568,761✔
4405
  }
4406

4407
  return TSDB_CODE_SUCCESS;
6,585,734✔
4408
}
4409

4410
int32_t spreadFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
54,087,574✔
4411
  SSpreadInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
54,087,574✔
4412
  if (pInfo->hasResult == true) {
54,087,797!
4413
    SET_DOUBLE_VAL(&pInfo->result, pInfo->max - pInfo->min);
52,433,246✔
4414
  } else {
4415
    GET_RES_INFO(pCtx)->isNullRes = 1;
1,654,328✔
4416
  }
4417
  return functionFinalize(pCtx, pBlock);
54,087,574✔
4418
}
4419

4420
int32_t spreadPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
9,399,887✔
4421
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
9,399,887✔
4422
  SSpreadInfo*         pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
9,401,276✔
4423
  int32_t              resultBytes = getSpreadInfoSize();
9,400,552✔
4424
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
9,400,611!
4425

4426
  if (NULL == res) {
9,401,941!
4427
    return terrno;
×
4428
  }
4429
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
9,401,941!
4430
  varDataSetLen(res, resultBytes);
9,401,217✔
4431

4432
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
9,401,217✔
4433
  int32_t          code = TSDB_CODE_SUCCESS;
9,401,217✔
4434
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
9,401,217✔
4435
  if (NULL == pCol) {
9,401,217!
4436
    code = terrno;
×
4437
    goto _exit;
×
4438
  }
4439

4440
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
9,401,217✔
4441
  if (TSDB_CODE_SUCCESS != code) {
9,401,941!
4442
    goto _exit;
×
4443
  }
4444

4445
_exit:
9,401,941✔
4446
  taosMemoryFree(res);
9,401,941!
4447
  return code;
9,401,941✔
4448
}
4449

4450
int32_t spreadCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4451
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
4452
  SSpreadInfo*         pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
4453

4454
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4455
  SSpreadInfo*         pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
4456
  spreadTransferInfo(pSBuf, pDBuf);
×
4457
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
4458
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
4459
  return TSDB_CODE_SUCCESS;
×
4460
}
4461

4462
int32_t getElapsedInfoSize() { return (int32_t)sizeof(SElapsedInfo); }
×
4463

4464
bool getElapsedFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
1,681,786✔
4465
  pEnv->calcMemSize = sizeof(SElapsedInfo);
1,681,786✔
4466
  return true;
1,683,340✔
4467
}
4468

4469
int32_t elapsedFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
3,048,561✔
4470
  if (pResultInfo->initialized) {
3,048,561!
4471
    return TSDB_CODE_SUCCESS;
×
4472
  }
4473
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
3,050,101!
4474
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4475
  }
4476

4477
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
3,049,412✔
4478
  pInfo->result = 0;
3,049,007✔
4479
  pInfo->min = TSKEY_MAX;
3,049,007✔
4480
  pInfo->max = 0;
3,049,441✔
4481

4482
  if (pCtx->numOfParams > 1) {
3,049,423✔
4483
    pInfo->timeUnit = pCtx->param[1].param.i;
2,110,996✔
4484
  } else {
4485
    pInfo->timeUnit = 1;
937,565✔
4486
  }
4487

4488
  return TSDB_CODE_SUCCESS;
3,048,561✔
4489
}
4490

4491
int32_t elapsedFunction(SqlFunctionCtx* pCtx) {
3,132,552✔
4492
  int32_t numOfElems = 0;
3,132,552✔
4493

4494
  // Only the pre-computing information loaded and actual data does not loaded
4495
  SInputColumnInfoData* pInput = &pCtx->input;
3,132,552✔
4496
  SColumnDataAgg*       pAgg = pInput->pColumnDataAgg[0];
3,132,115✔
4497

4498
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
3,133,420✔
4499

4500
  numOfElems = pInput->numOfRows;  // since this is the primary timestamp, no need to exclude NULL values
3,132,598✔
4501
  if (numOfElems == 0) {
3,130,627!
4502
    // for stream
4503
    if (pCtx->end.key != INT64_MIN) {
×
4504
      pInfo->max = pCtx->end.key + 1;
×
4505
    }
4506
    goto _elapsed_over;
×
4507
  }
4508

4509
  if (pInput->colDataSMAIsSet) {
3,130,627!
4510
    if (pInfo->min == TSKEY_MAX) {
×
4511
      pInfo->min = GET_INT64_VAL(&pAgg->min);
×
4512
      pInfo->max = GET_INT64_VAL(&pAgg->max);
×
4513
    } else {
4514
      if (pCtx->order == TSDB_ORDER_ASC) {
×
4515
        pInfo->max = GET_INT64_VAL(&pAgg->max);
×
4516
      } else {
4517
        pInfo->min = GET_INT64_VAL(&pAgg->min);
×
4518
      }
4519
    }
4520
  } else {  // computing based on the true data block
4521
    if (0 == pInput->numOfRows) {
3,133,936!
4522
      if (pCtx->order == TSDB_ORDER_DESC) {
×
4523
        if (pCtx->end.key != INT64_MIN) {
×
4524
          pInfo->min = pCtx->end.key;
×
4525
        }
4526
      } else {
4527
        if (pCtx->end.key != INT64_MIN) {
×
4528
          pInfo->max = pCtx->end.key + 1;
×
4529
        }
4530
      }
4531
      goto _elapsed_over;
×
4532
    }
4533

4534
    SColumnInfoData* pCol = pInput->pData[0];
3,131,053✔
4535

4536
    int32_t start = pInput->startRowIndex;
3,133,481✔
4537
    TSKEY*  ptsList = (int64_t*)colDataGetData(pCol, 0);
3,132,598!
4538
    if (pCtx->order == TSDB_ORDER_DESC) {
3,133,713✔
4539
      if (pCtx->start.key == INT64_MIN) {
41,260!
4540
        pInfo->max = (pInfo->max < ptsList[start]) ? ptsList[start] : pInfo->max;
41,260✔
4541
      } else {
4542
        pInfo->max = pCtx->start.key + 1;
×
4543
      }
4544

4545
      if (pCtx->end.key == INT64_MIN) {
41,260!
4546
        pInfo->min =
41,260✔
4547
            (pInfo->min > ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->min;
41,260✔
4548
      } else {
4549
        pInfo->min = pCtx->end.key;
×
4550
      }
4551
    } else {
4552
      if (pCtx->start.key == INT64_MIN) {
3,091,116!
4553
        pInfo->min = (pInfo->min > ptsList[start]) ? ptsList[start] : pInfo->min;
3,092,872✔
4554
      } else {
4555
        pInfo->min = pCtx->start.key;
×
4556
      }
4557

4558
      if (pCtx->end.key == INT64_MIN) {
3,093,752✔
4559
        pInfo->max =
2,996,982✔
4560
            (pInfo->max < ptsList[start + pInput->numOfRows - 1]) ? ptsList[start + pInput->numOfRows - 1] : pInfo->max;
2,997,828✔
4561
      } else {
4562
        pInfo->max = pCtx->end.key + 1;
94,778✔
4563
      }
4564
    }
4565
  }
4566

4567
_elapsed_over:
3,133,924✔
4568
  // data in the check operation are all null, not output
4569
  SET_VAL(GET_RES_INFO(pCtx), numOfElems, 1);
3,133,924!
4570

4571
  return TSDB_CODE_SUCCESS;
3,132,572✔
4572
}
4573

4574
static void elapsedTransferInfo(SElapsedInfo* pInput, SElapsedInfo* pOutput) {
×
4575
  pOutput->timeUnit = pInput->timeUnit;
×
4576
  if (pOutput->min > pInput->min) {
×
4577
    pOutput->min = pInput->min;
×
4578
  }
4579

4580
  if (pOutput->max < pInput->max) {
×
4581
    pOutput->max = pInput->max;
×
4582
  }
4583
}
×
4584

4585
int32_t elapsedFunctionMerge(SqlFunctionCtx* pCtx) {
×
4586
  SInputColumnInfoData* pInput = &pCtx->input;
×
4587
  SColumnInfoData*      pCol = pInput->pData[0];
×
4588
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
×
4589
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4590
  }
4591

4592
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
4593

4594
  int32_t start = pInput->startRowIndex;
×
4595

4596
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
×
4597
    char*         data = colDataGetData(pCol, i);
×
4598
    SElapsedInfo* pInputInfo = (SElapsedInfo*)varDataVal(data);
×
4599
    elapsedTransferInfo(pInputInfo, pInfo);
×
4600
  }
4601

4602
  SET_VAL(GET_RES_INFO(pCtx), 1, 1);
×
4603
  return TSDB_CODE_SUCCESS;
×
4604
}
4605

4606
int32_t elapsedFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
3,050,101✔
4607
  SElapsedInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
3,050,101✔
4608
  double        result = (double)(pInfo->max - pInfo->min);
3,050,324✔
4609
  pInfo->result = fabs(result) / pInfo->timeUnit;
3,049,823!
4610
  return functionFinalize(pCtx, pBlock);
3,050,529✔
4611
}
4612

4613
int32_t elapsedPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
4614
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
×
4615
  SElapsedInfo*        pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
4616
  int32_t              resultBytes = getElapsedInfoSize();
×
4617
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
×
4618

4619
  if (NULL == res) {
×
4620
    return terrno;
×
4621
  }
4622
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
×
4623
  varDataSetLen(res, resultBytes);
×
4624

4625
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
×
4626
  int32_t          code = TSDB_CODE_SUCCESS;
×
4627
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
×
4628
  if (NULL == pCol) {
×
4629
    code = terrno;
×
4630
    goto _exit;
×
4631
  }
4632

4633
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
×
4634
  if (TSDB_CODE_SUCCESS != code) {
×
4635
    goto _exit;
×
4636
  }
4637
_exit:
×
4638
  taosMemoryFree(res);
×
4639
  return code;
×
4640
}
4641

4642
int32_t elapsedCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
4643
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
4644
  SElapsedInfo*        pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
4645

4646
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
4647
  SElapsedInfo*        pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
4648

4649
  elapsedTransferInfo(pSBuf, pDBuf);
×
4650
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
4651
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
4652
  return TSDB_CODE_SUCCESS;
×
4653
}
4654

4655
int32_t getHistogramInfoSize() {
442,370✔
4656
  return (int32_t)sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
442,370✔
4657
}
4658

4659
bool getHistogramFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
763,840✔
4660
  pEnv->calcMemSize = sizeof(SHistoFuncInfo) + HISTOGRAM_MAX_BINS_NUM * sizeof(SHistoFuncBin);
763,840✔
4661
  return true;
764,118✔
4662
}
4663

4664
static int8_t getHistogramBinType(char* binTypeStr) {
507,476✔
4665
  int8_t binType;
4666
  if (strcasecmp(binTypeStr, "user_input") == 0) {
507,476!
4667
    binType = USER_INPUT_BIN;
387,722✔
4668
  } else if (strcasecmp(binTypeStr, "linear_bin") == 0) {
119,754!
4669
    binType = LINEAR_BIN;
32,904✔
4670
  } else if (strcasecmp(binTypeStr, "log_bin") == 0) {
86,850!
4671
    binType = LOG_BIN;
86,850✔
4672
  } else {
4673
    binType = UNKNOWN_BIN;
×
4674
  }
4675

4676
  return binType;
507,476✔
4677
}
4678

4679
static int32_t getHistogramBinDesc(SHistoFuncInfo* pInfo, char* binDescStr, int8_t binType, bool normalized) {
507,710✔
4680
  cJSON*  binDesc = cJSON_Parse(binDescStr);
507,710✔
4681
  int32_t numOfBins;
4682
  double* intervals;
4683
  if (cJSON_IsObject(binDesc)) { /* linaer/log bins */
507,761✔
4684
    int32_t numOfParams = cJSON_GetArraySize(binDesc);
119,754✔
4685
    int32_t startIndex;
4686
    if (numOfParams != 4) {
119,754!
4687
      cJSON_Delete(binDesc);
×
4688
      return TSDB_CODE_FAILED;
×
4689
    }
4690

4691
    cJSON* start = cJSON_GetObjectItem(binDesc, "start");
119,754✔
4692
    cJSON* factor = cJSON_GetObjectItem(binDesc, "factor");
120,039✔
4693
    cJSON* width = cJSON_GetObjectItem(binDesc, "width");
120,039✔
4694
    cJSON* count = cJSON_GetObjectItem(binDesc, "count");
119,754✔
4695
    cJSON* infinity = cJSON_GetObjectItem(binDesc, "infinity");
120,039✔
4696

4697
    if (!cJSON_IsNumber(start) || !cJSON_IsNumber(count) || !cJSON_IsBool(infinity)) {
120,039!
4698
      cJSON_Delete(binDesc);
285✔
4699
      return TSDB_CODE_FAILED;
×
4700
    }
4701

4702
    if (count->valueint <= 0 || count->valueint > 1000) {  // limit count to 1000
119,754!
4703
      cJSON_Delete(binDesc);
×
4704
      return TSDB_CODE_FAILED;
×
4705
    }
4706

4707
    if (isinf(start->valuedouble) || (width != NULL && isinf(width->valuedouble)) ||
119,754!
4708
        (factor != NULL && isinf(factor->valuedouble)) || (count != NULL && isinf(count->valuedouble))) {
119,754!
4709
      cJSON_Delete(binDesc);
×
4710
      return TSDB_CODE_FAILED;
×
4711
    }
4712

4713
    int32_t counter = (int32_t)count->valueint;
119,754✔
4714
    if (infinity->valueint == false) {
119,754✔
4715
      startIndex = 0;
97,728✔
4716
      numOfBins = counter + 1;
97,728✔
4717
    } else {
4718
      startIndex = 1;
22,311✔
4719
      numOfBins = counter + 3;
22,311✔
4720
    }
4721

4722
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
120,039!
4723
    if (NULL == intervals) {
119,754!
4724
      cJSON_Delete(binDesc);
×
4725
      qError("histogram function out of memory");
×
4726
      return terrno;
×
4727
    }
4728
    if (cJSON_IsNumber(width) && factor == NULL && binType == LINEAR_BIN) {
119,754!
4729
      // linear bin process
4730
      if (width->valuedouble == 0) {
32,904!
4731
        taosMemoryFree(intervals);
×
4732
        cJSON_Delete(binDesc);
×
4733
        return TSDB_CODE_FAILED;
×
4734
      }
4735
      for (int i = 0; i < counter + 1; ++i) {
98,712✔
4736
        intervals[startIndex] = start->valuedouble + i * width->valuedouble;
65,808✔
4737
        if (isinf(intervals[startIndex])) {
65,808!
4738
          taosMemoryFree(intervals);
×
4739
          cJSON_Delete(binDesc);
×
4740
          return TSDB_CODE_FAILED;
×
4741
        }
4742
        startIndex++;
65,808✔
4743
      }
4744
    } else if (cJSON_IsNumber(factor) && width == NULL && binType == LOG_BIN) {
86,850!
4745
      // log bin process
4746
      if (start->valuedouble == 0) {
87,135!
4747
        taosMemoryFree(intervals);
×
4748
        cJSON_Delete(binDesc);
×
4749
        return TSDB_CODE_FAILED;
×
4750
      }
4751
      if (factor->valuedouble < 0 || factor->valuedouble == 0 || factor->valuedouble == 1) {
86,850!
4752
        taosMemoryFree(intervals);
570!
4753
        cJSON_Delete(binDesc);
×
4754
        return TSDB_CODE_FAILED;
×
4755
      }
4756
      for (int i = 0; i < counter + 1; ++i) {
478,044✔
4757
        intervals[startIndex] = start->valuedouble * pow(factor->valuedouble, i * 1.0);
390,675✔
4758
        if (isinf(intervals[startIndex])) {
390,624!
4759
          taosMemoryFree(intervals);
×
4760
          cJSON_Delete(binDesc);
×
4761
          return TSDB_CODE_FAILED;
×
4762
        }
4763
        startIndex++;
391,194✔
4764
      }
4765
    } else {
4766
      taosMemoryFree(intervals);
×
4767
      cJSON_Delete(binDesc);
×
4768
      return TSDB_CODE_FAILED;
×
4769
    }
4770

4771
    if (infinity->valueint == true) {
120,273✔
4772
      intervals[0] = -INFINITY;
22,311✔
4773
      intervals[numOfBins - 1] = INFINITY;
22,311✔
4774
      // in case of desc bin orders, -inf/inf should be swapped
4775
      if (numOfBins < 4) {
22,311!
4776
        return TSDB_CODE_FAILED;
×
4777
      }
4778
      if (intervals[1] > intervals[numOfBins - 2]) {
22,311!
4779
        TSWAP(intervals[0], intervals[numOfBins - 1]);
22,311✔
4780
      }
4781
    }
4782
  } else if (cJSON_IsArray(binDesc)) { /* user input bins */
387,722!
4783
    if (binType != USER_INPUT_BIN) {
387,722!
4784
      cJSON_Delete(binDesc);
×
4785
      return TSDB_CODE_FAILED;
×
4786
    }
4787
    numOfBins = cJSON_GetArraySize(binDesc);
387,722✔
4788
    intervals = taosMemoryCalloc(numOfBins, sizeof(double));
387,722!
4789
    if (NULL == intervals) {
387,956!
4790
      cJSON_Delete(binDesc);
×
4791
      qError("histogram function out of memory");
×
4792
      return terrno;
×
4793
    }
4794
    cJSON* bin = binDesc->child;
387,956✔
4795
    if (bin == NULL) {
387,956!
4796
      taosMemoryFree(intervals);
×
4797
      cJSON_Delete(binDesc);
×
4798
      return TSDB_CODE_FAILED;
×
4799
    }
4800
    int i = 0;
387,956✔
4801
    while (bin) {
1,807,696✔
4802
      intervals[i] = bin->valuedouble;
1,419,506✔
4803
      if (!cJSON_IsNumber(bin)) {
1,419,740!
4804
        taosMemoryFree(intervals);
×
4805
        cJSON_Delete(binDesc);
×
4806
        return TSDB_CODE_FAILED;
×
4807
      }
4808
      if (i != 0 && intervals[i] <= intervals[i - 1]) {
1,419,740!
4809
        taosMemoryFree(intervals);
×
4810
        cJSON_Delete(binDesc);
×
4811
        return TSDB_CODE_FAILED;
×
4812
      }
4813
      bin = bin->next;
1,419,740✔
4814
      i++;
1,419,740✔
4815
    }
4816
  } else {
4817
    cJSON_Delete(binDesc);
×
4818
    return TSDB_CODE_FAILED;
×
4819
  }
4820

4821
  pInfo->numOfBins = numOfBins - 1;
507,944✔
4822
  pInfo->normalized = normalized;
507,710✔
4823
  for (int32_t i = 0; i < pInfo->numOfBins; ++i) {
1,920,611✔
4824
    pInfo->bins[i].lower = intervals[i] < intervals[i + 1] ? intervals[i] : intervals[i + 1];
1,412,799✔
4825
    pInfo->bins[i].upper = intervals[i + 1] > intervals[i] ? intervals[i + 1] : intervals[i];
1,413,084✔
4826
    pInfo->bins[i].count = 0;
1,412,850✔
4827
  }
4828

4829
  taosMemoryFree(intervals);
507,761!
4830
  cJSON_Delete(binDesc);
507,710✔
4831

4832
  return TSDB_CODE_SUCCESS;
507,710✔
4833
}
4834

4835
int32_t histogramFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
507,476✔
4836
  if (pResultInfo->initialized) {
507,476!
4837
    return TSDB_CODE_SUCCESS;
×
4838
  }
4839
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
507,995!
4840
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
4841
  }
4842

4843
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
507,995✔
4844
  pInfo->numOfBins = 0;
507,710✔
4845
  pInfo->totalCount = 0;
507,995✔
4846
  pInfo->normalized = 0;
507,995✔
4847

4848
  char* binTypeStr = taosStrndup(varDataVal(pCtx->param[1].param.pz), varDataLen(pCtx->param[1].param.pz));
507,995!
4849
  if (binTypeStr == NULL) {
507,476!
4850
    return terrno;
×
4851
  }
4852
  int8_t binType = getHistogramBinType(binTypeStr);
507,476✔
4853
  taosMemoryFree(binTypeStr);
507,761!
4854

4855
  if (binType == UNKNOWN_BIN) {
507,995!
4856
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
4857
  }
4858
  char* binDesc = taosStrndup(varDataVal(pCtx->param[2].param.pz), varDataLen(pCtx->param[2].param.pz));
507,995!
4859
  if (binDesc == NULL) {
507,710!
4860
    return terrno;
×
4861
  }
4862
  int64_t normalized = pCtx->param[3].param.i;
507,710✔
4863
  if (normalized != 0 && normalized != 1) {
507,995!
4864
    taosMemoryFree(binDesc);
×
4865
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
4866
  }
4867
  int32_t code = getHistogramBinDesc(pInfo, binDesc, binType, (bool)normalized);
507,995✔
4868
  if (TSDB_CODE_SUCCESS != code) {
507,710!
4869
    taosMemoryFree(binDesc);
×
4870
    return code;
×
4871
  }
4872
  taosMemoryFree(binDesc);
507,710!
4873

4874
  return TSDB_CODE_SUCCESS;
507,772✔
4875
}
4876

4877
static int32_t histogramFunctionImpl(SqlFunctionCtx* pCtx, bool isPartial) {
585,990✔
4878
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
585,990✔
4879

4880
  SInputColumnInfoData* pInput = &pCtx->input;
585,990✔
4881
  SColumnInfoData*      pCol = pInput->pData[0];
585,990✔
4882

4883
  int32_t type = pInput->pData[0]->info.type;
586,743✔
4884

4885
  int32_t start = pInput->startRowIndex;
586,224✔
4886
  int32_t numOfRows = pInput->numOfRows;
586,743✔
4887

4888
  int32_t numOfElems = 0;
588,651✔
4889
  for (int32_t i = start; i < numOfRows + start; ++i) {
86,686,330✔
4890
    if (pCol->hasNull && colDataIsNull_f(pCol, i)) {
86,099,587!
4891
      continue;
38,963,272✔
4892
    }
4893

4894
    numOfElems++;
47,135,273✔
4895

4896
    char*  data = colDataGetData(pCol, i);
47,135,273!
4897
    double v;
4898
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pCol->info));
47,136,885!
4899

4900
    for (int32_t k = 0; k < pInfo->numOfBins; ++k) {
159,872,493✔
4901
      if (v > pInfo->bins[k].lower && v <= pInfo->bins[k].upper) {
124,816,803✔
4902
        pInfo->bins[k].count++;
12,081,924✔
4903
        pInfo->totalCount++;
12,084,030✔
4904
        break;
12,083,796✔
4905
      }
4906
    }
4907
  }
4908

4909
  if (!isPartial) {
586,743✔
4910
    GET_RES_INFO(pCtx)->numOfRes = pInfo->numOfBins;
374,220✔
4911
  } else {
4912
    GET_RES_INFO(pCtx)->numOfRes = 1;
212,523✔
4913
  }
4914
  return TSDB_CODE_SUCCESS;
586,509✔
4915
}
4916

4917
int32_t histogramFunction(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, false); }
373,752✔
4918

4919
int32_t histogramFunctionPartial(SqlFunctionCtx* pCtx) { return histogramFunctionImpl(pCtx, true); }
212,238✔
4920

4921
static void histogramTransferInfo(SHistoFuncInfo* pInput, SHistoFuncInfo* pOutput) {
134,243✔
4922
  pOutput->normalized = pInput->normalized;
134,243!
4923
  pOutput->numOfBins = pInput->numOfBins;
134,243✔
4924
  pOutput->totalCount += pInput->totalCount;
134,243✔
4925
  for (int32_t k = 0; k < pOutput->numOfBins; ++k) {
617,234✔
4926
    pOutput->bins[k].lower = pInput->bins[k].lower;
482,991✔
4927
    pOutput->bins[k].upper = pInput->bins[k].upper;
482,991✔
4928
    pOutput->bins[k].count += pInput->bins[k].count;
482,991✔
4929
  }
4930
}
134,243✔
4931

4932
int32_t histogramFunctionMerge(SqlFunctionCtx* pCtx) {
134,243✔
4933
  SInputColumnInfoData* pInput = &pCtx->input;
134,243✔
4934
  SColumnInfoData*      pCol = pInput->pData[0];
134,243✔
4935
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
134,243!
4936
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
4937
  }
4938

4939
  SHistoFuncInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
134,243✔
4940

4941
  int32_t start = pInput->startRowIndex;
134,243✔
4942

4943
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
268,486✔
4944
    char*           data = colDataGetData(pCol, i);
134,243!
4945
    SHistoFuncInfo* pInputInfo = (SHistoFuncInfo*)varDataVal(data);
134,243✔
4946
    histogramTransferInfo(pInputInfo, pInfo);
134,243✔
4947
  }
4948

4949
  SET_VAL(GET_RES_INFO(pCtx), pInfo->numOfBins, pInfo->numOfBins);
134,243!
4950
  return TSDB_CODE_SUCCESS;
134,243✔
4951
}
4952

4953
int32_t histogramFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
495,896✔
4954
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
495,896✔
4955
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
495,896✔
4956
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
496,130✔
4957
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
495,896✔
4958
  int32_t              code = TSDB_CODE_SUCCESS;
496,130✔
4959

4960
  int32_t currentRow = pBlock->info.rows;
496,130✔
4961
  if (NULL == pCol) {
495,896!
4962
    return TSDB_CODE_OUT_OF_RANGE;
×
4963
  }
4964

4965
  if (pInfo->normalized) {
495,896!
4966
    for (int32_t k = 0; k < pResInfo->numOfRes; ++k) {
1,773,614✔
4967
      if (pInfo->totalCount != 0) {
1,310,622✔
4968
        pInfo->bins[k].percentage = pInfo->bins[k].count / (double)pInfo->totalCount;
252,747!
4969
      } else {
4970
        pInfo->bins[k].percentage = 0;
1,057,641✔
4971
      }
4972
    }
4973
  }
4974

4975
  for (int32_t i = 0; i < pResInfo->numOfRes; ++i) {
1,840,124✔
4976
    int32_t len;
4977
    char    buf[512] = {0};
1,344,228✔
4978
    if (!pInfo->normalized) {
1,344,228!
4979
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
33,372✔
4980
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%" PRId64 "}", pInfo->bins[i].lower,
4981
                      pInfo->bins[i].upper, pInfo->bins[i].count);
4982
    } else {
4983
      len = tsnprintf(varDataVal(buf), sizeof(buf) - VARSTR_HEADER_SIZE,
1,310,388✔
4984
                      "{\"lower_bin\":%g, \"upper_bin\":%g, \"count\":%lf}", pInfo->bins[i].lower, pInfo->bins[i].upper,
4985
                      pInfo->bins[i].percentage);
4986
    }
4987
    varDataSetLen(buf, len);
1,344,228✔
4988
    code = colDataSetVal(pCol, currentRow, buf, false);
1,344,228✔
4989
    if (TSDB_CODE_SUCCESS != code) {
1,344,228!
4990
      return code;
×
4991
    }
4992
    currentRow++;
1,344,228✔
4993
  }
4994

4995
  return code;
496,130✔
4996
}
4997

4998
int32_t histogramPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
134,243✔
4999
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
134,243✔
5000
  SHistoFuncInfo*      pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
134,243✔
5001
  int32_t              resultBytes = getHistogramInfoSize();
134,243✔
5002
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
134,243!
5003

5004
  if (NULL == res) {
134,243!
5005
    return terrno;
×
5006
  }
5007
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
134,243!
5008
  varDataSetLen(res, resultBytes);
134,243✔
5009

5010
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
134,243✔
5011
  int32_t          code = TSDB_CODE_SUCCESS;
134,243✔
5012
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
134,243✔
5013
  if (NULL == pCol) {
134,243!
5014
    code = terrno;
×
5015
    goto _exit;
×
5016
  }
5017
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
134,243✔
5018

5019
_exit:
134,243✔
5020
  taosMemoryFree(res);
134,243!
5021
  return code;
134,243✔
5022
}
5023

5024
int32_t histogramCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
5025
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
5026
  SHistoFuncInfo*      pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
5027

5028
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
5029
  SHistoFuncInfo*      pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
5030

5031
  histogramTransferInfo(pSBuf, pDBuf);
×
5032
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
5033
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
5034
  return TSDB_CODE_SUCCESS;
×
5035
}
5036

5037
int32_t getHLLInfoSize() { return (int32_t)sizeof(SHLLInfo); }
142,298✔
5038

5039
bool getHLLFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
1,698,447✔
5040
  pEnv->calcMemSize = sizeof(SHLLInfo);
1,698,447✔
5041
  return true;
1,699,231✔
5042
}
5043

5044
static uint8_t hllCountNum(void* data, int32_t bytes, int32_t* buk) {
222,237,202✔
5045
  uint64_t hash = MurmurHash3_64(data, bytes);
222,237,202✔
5046
  int32_t  index = hash & HLL_BUCKET_MASK;
222,242,240✔
5047
  hash >>= HLL_BUCKET_BITS;
222,242,240✔
5048
  hash |= ((uint64_t)1 << HLL_DATA_BITS);
222,242,240✔
5049
  uint64_t bit = 1;
222,242,240✔
5050
  uint8_t  count = 1;
222,242,240✔
5051
  while ((hash & bit) == 0) {
378,172,368✔
5052
    count++;
155,930,128✔
5053
    bit <<= 1;
155,930,128✔
5054
  }
5055
  *buk = index;
222,242,240✔
5056
  return count;
222,243,355✔
5057
}
5058

5059
static void hllBucketHisto(uint8_t* buckets, int32_t* bucketHisto) {
3,854,569✔
5060
  uint64_t* word = (uint64_t*)buckets;
3,854,569✔
5061
  uint8_t*  bytes;
5062

5063
  for (int32_t j = 0; j < HLL_BUCKETS >> 3; j++) {
2,147,483,647✔
5064
    if (*word == 0) {
2,147,483,647✔
5065
      bucketHisto[0] += 8;
2,147,483,647✔
5066
    } else {
5067
      bytes = (uint8_t*)word;
20,406,867✔
5068
      bucketHisto[bytes[0]]++;
20,406,867✔
5069
      bucketHisto[bytes[1]]++;
25,120,977✔
5070
      bucketHisto[bytes[2]]++;
25,124,187✔
5071
      bucketHisto[bytes[3]]++;
25,126,962✔
5072
      bucketHisto[bytes[4]]++;
25,130,673✔
5073
      bucketHisto[bytes[5]]++;
25,133,057✔
5074
      bucketHisto[bytes[6]]++;
25,138,976✔
5075
      bucketHisto[bytes[7]]++;
25,141,550✔
5076
    }
5077
    word++;
2,147,483,647✔
5078
  }
5079
}
75,004✔
5080
static double hllTau(double x) {
3,855,227✔
5081
  if (x == 0. || x == 1.) return 0.;
3,855,227!
5082
  double zPrime;
5083
  double y = 1.0;
×
5084
  double z = 1 - x;
×
5085
  do {
5086
    x = sqrt(x);
×
5087
    zPrime = z;
×
5088
    y *= 0.5;
×
5089
    z -= pow(1 - x, 2) * y;
×
5090
  } while (zPrime != z);
×
5091
  return z / 3;
×
5092
}
5093

5094
static double hllSigma(double x) {
3,855,238✔
5095
  if (x == 1.0) return INFINITY;
3,855,238✔
5096
  double zPrime;
5097
  double y = 1;
2,657,878✔
5098
  double z = x;
2,657,878✔
5099
  do {
5100
    x *= x;
52,148,466✔
5101
    zPrime = z;
52,148,466✔
5102
    z += x * y;
52,148,466✔
5103
    y += y;
52,148,466✔
5104
  } while (zPrime != z);
52,148,466✔
5105
  return z;
2,657,878✔
5106
}
5107

5108
// estimate the cardinality, the algorithm refer this paper: "New cardinality estimation algorithms for HyperLogLog
5109
// sketches"
5110
static uint64_t hllCountCnt(uint8_t* buckets) {
3,854,569✔
5111
  double  m = HLL_BUCKETS;
3,854,569✔
5112
  int32_t buckethisto[64] = {0};
3,854,569✔
5113
  hllBucketHisto(buckets, buckethisto);
3,854,368✔
5114

5115
  double z = m * hllTau((m - buckethisto[HLL_DATA_BITS + 1]) / (double)m);
3,855,227!
5116
  for (int j = HLL_DATA_BITS; j >= 1; --j) {
196,569,111✔
5117
    z += buckethisto[j];
192,713,650✔
5118
    z *= 0.5;
192,713,650✔
5119
  }
5120

5121
  z += m * hllSigma(buckethisto[0] / (double)m);
3,855,461!
5122
  double E = (double)llroundl(HLL_ALPHA_INF * m * m / z);
3,855,461!
5123

5124
  return (uint64_t)E;
3,855,461!
5125
}
5126

5127
int32_t hllFunction(SqlFunctionCtx* pCtx) {
3,997,713✔
5128
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
3,997,713✔
5129

5130
  SInputColumnInfoData* pInput = &pCtx->input;
3,995,452✔
5131
  SColumnInfoData*      pCol = pInput->pData[0];
3,997,490✔
5132

5133
  int32_t type = pCol->info.type;
3,996,821✔
5134
  int32_t bytes = pCol->info.bytes;
3,997,033✔
5135

5136
  int32_t start = pInput->startRowIndex;
3,997,073✔
5137
  int32_t numOfRows = pInput->numOfRows;
3,997,775✔
5138

5139
  int32_t numOfElems = 0;
3,994,770✔
5140
  if (IS_NULL_TYPE(type)) {
3,994,770✔
5141
    goto _hll_over;
81,795✔
5142
  }
5143

5144
  for (int32_t i = start; i < numOfRows + start; ++i) {
293,000,889✔
5145
    if (pCol->hasNull && colDataIsNull_s(pCol, i)) {
357,487,089!
5146
      continue;
66,848,650✔
5147
    }
5148

5149
    numOfElems++;
222,233,010✔
5150

5151
    char* data = colDataGetData(pCol, i);
222,233,010!
5152
    if (IS_VAR_DATA_TYPE(type)) {
222,240,313!
5153
      if (IS_STR_DATA_BLOB(type)) {
32,571,027!
UNCOV
5154
        bytes = blobDataLen(data);
×
5155
        data = blobDataVal(data);
×
5156
      } else {
5157
        bytes = varDataLen(data);
32,572,241✔
5158
        data = varDataVal(data);
32,572,698✔
5159
      }
5160
    }
5161

5162
    int32_t index = 0;
222,242,430✔
5163
    uint8_t count = hllCountNum(data, bytes, &index);
222,237,794✔
5164
    uint8_t oldcount = pInfo->buckets[index];
222,237,370✔
5165
    if (count > oldcount) {
222,240,101✔
5166
      pInfo->buckets[index] = count;
42,679,806✔
5167
    }
5168
  }
5169

5170
_hll_over:
3,913,461✔
5171
  pInfo->totalCount += numOfElems;
3,995,256✔
5172

5173
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
3,997,711✔
5174
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
2,547✔
5175
  } else {
5176
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
3,996,120✔
5177
  }
5178

5179
  return TSDB_CODE_SUCCESS;
3,998,422✔
5180
}
5181

5182
static void hllTransferInfo(SHLLInfo* pInput, SHLLInfo* pOutput) {
142,583✔
5183
  for (int32_t k = 0; k < HLL_BUCKETS; ++k) {
2,147,483,647✔
5184
    if (pOutput->buckets[k] < pInput->buckets[k]) {
2,147,483,647✔
5185
      pOutput->buckets[k] = pInput->buckets[k];
712,503✔
5186
    }
5187
  }
5188
  pOutput->totalCount += pInput->totalCount;
237,592✔
5189
}
142,583✔
5190

5191
int32_t hllFunctionMerge(SqlFunctionCtx* pCtx) {
142,583✔
5192
  SInputColumnInfoData* pInput = &pCtx->input;
142,583✔
5193
  SColumnInfoData*      pCol = pInput->pData[0];
142,583✔
5194

5195
  if (IS_NULL_TYPE(pCol->info.type)) {
142,583!
5196
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
5197
    return TSDB_CODE_SUCCESS;
×
5198
  }
5199

5200
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
142,583!
5201
    return TSDB_CODE_SUCCESS;
×
5202
  }
5203

5204
  SHLLInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
142,583✔
5205

5206
  int32_t start = pInput->startRowIndex;
142,583✔
5207

5208
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
285,166✔
5209
    if (colDataIsNull_s(pCol, i)) continue;
285,166!
5210
    char*     data = colDataGetData(pCol, i);
142,583!
5211
    SHLLInfo* pInputInfo = (SHLLInfo*)varDataVal(data);
142,583✔
5212
    hllTransferInfo(pInputInfo, pInfo);
142,583✔
5213
  }
5214

5215
  if (pInfo->totalCount == 0 && !tsCountAlwaysReturnValue) {
142,583✔
5216
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
283✔
5217
  } else {
5218
    SET_VAL(GET_RES_INFO(pCtx), 1, 1);
142,300✔
5219
  }
5220

5221
  return TSDB_CODE_SUCCESS;
142,583✔
5222
}
5223

5224
int32_t hllFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
3,855,015✔
5225
  SResultRowEntryInfo* pInfo = GET_RES_INFO(pCtx);
3,855,015✔
5226

5227
  SHLLInfo* pHllInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
3,855,015✔
5228
  pHllInfo->result = hllCountCnt(pHllInfo->buckets);
3,855,015✔
5229
  if (tsCountAlwaysReturnValue && pHllInfo->result == 0) {
3,854,792✔
5230
    pInfo->numOfRes = 1;
1,196,794✔
5231
  }
5232

5233
  return functionFinalize(pCtx, pBlock);
3,854,346✔
5234
}
5235

5236
int32_t hllPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
142,298✔
5237
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
142,298✔
5238
  SHLLInfo*            pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
142,583✔
5239
  int32_t              resultBytes = getHLLInfoSize();
142,298✔
5240
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
142,583!
5241

5242
  if (NULL == res) {
142,583!
5243
    return terrno;
×
5244
  }
5245
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
142,583!
5246
  varDataSetLen(res, resultBytes);
142,583✔
5247

5248
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
142,583✔
5249
  int32_t          code = TSDB_CODE_SUCCESS;
142,583✔
5250
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
142,583✔
5251
  if (NULL == pCol) {
142,298!
5252
    code = terrno;
×
5253
    goto _exit;
×
5254
  }
5255

5256
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
142,298✔
5257

5258
_exit:
142,583✔
5259
  taosMemoryFree(res);
142,583!
5260
  return code;
142,583✔
5261
}
5262

5263
int32_t hllCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
5264
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
5265
  SHLLInfo*            pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
5266

5267
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
5268
  SHLLInfo*            pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
5269

5270
  hllTransferInfo(pSBuf, pDBuf);
×
5271
  pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
×
5272
  pDResInfo->isNullRes &= pSResInfo->isNullRes;
×
5273
  return TSDB_CODE_SUCCESS;
×
5274
}
5275

5276
bool getStateFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
1,393,299✔
5277
  pEnv->calcMemSize = sizeof(SStateInfo);
1,393,299✔
5278
  return true;
1,393,299✔
5279
}
5280

5281
static int8_t getStateOpType(char* opStr) {
1,420,873✔
5282
  int8_t opType;
5283
  if (strncasecmp(opStr, "LT", 2) == 0) {
1,420,873!
5284
    opType = STATE_OPER_LT;
156,136✔
5285
  } else if (strncasecmp(opStr, "GT", 2) == 0) {
1,264,737!
5286
    opType = STATE_OPER_GT;
281,579✔
5287
  } else if (strncasecmp(opStr, "LE", 2) == 0) {
983,158!
5288
    opType = STATE_OPER_LE;
156,136✔
5289
  } else if (strncasecmp(opStr, "GE", 2) == 0) {
827,022!
5290
    opType = STATE_OPER_GE;
173,890✔
5291
  } else if (strncasecmp(opStr, "NE", 2) == 0) {
653,132!
5292
    opType = STATE_OPER_NE;
181,216✔
5293
  } else if (strncasecmp(opStr, "EQ", 2) == 0) {
471,916!
5294
    opType = STATE_OPER_EQ;
471,916✔
5295
  } else {
5296
    opType = STATE_OPER_INVALID;
×
5297
  }
5298

5299
  return opType;
1,420,873✔
5300
}
5301

5302
static bool checkStateOp(int8_t op, SColumnInfoData* pCol, int32_t index, SVariant param) {
68,781,626✔
5303
  char* data = colDataGetData(pCol, index);
68,781,626!
5304
  switch (pCol->info.type) {
68,781,626!
5305
    case TSDB_DATA_TYPE_TINYINT: {
4,300,428✔
5306
      int8_t v = *(int8_t*)data;
4,300,428✔
5307
      STATE_COMP(op, v, param);
4,300,428!
5308
      break;
×
5309
    }
5310
    case TSDB_DATA_TYPE_UTINYINT: {
16,751,520✔
5311
      uint8_t v = *(uint8_t*)data;
16,751,520✔
5312
      STATE_COMP(op, v, param);
16,751,520!
5313
      break;
×
5314
    }
5315
    case TSDB_DATA_TYPE_SMALLINT: {
12,012,896✔
5316
      int16_t v = *(int16_t*)data;
12,012,896✔
5317
      STATE_COMP(op, v, param);
12,012,896!
5318
      break;
×
5319
    }
5320
    case TSDB_DATA_TYPE_USMALLINT: {
900,000✔
5321
      uint16_t v = *(uint16_t*)data;
900,000✔
5322
      STATE_COMP(op, v, param);
900,000!
5323
      break;
×
5324
    }
5325
    case TSDB_DATA_TYPE_INT: {
9,533,293✔
5326
      int32_t v = *(int32_t*)data;
9,533,293✔
5327
      STATE_COMP(op, v, param);
9,533,293!
5328
      break;
×
5329
    }
5330
    case TSDB_DATA_TYPE_UINT: {
900,000✔
5331
      uint32_t v = *(uint32_t*)data;
900,000✔
5332
      STATE_COMP(op, v, param);
900,000!
5333
      break;
×
5334
    }
5335
    case TSDB_DATA_TYPE_BIGINT: {
4,579,434✔
5336
      int64_t v = *(int64_t*)data;
4,579,434✔
5337
      STATE_COMP(op, v, param);
4,579,434!
5338
      break;
×
5339
    }
5340
    case TSDB_DATA_TYPE_UBIGINT: {
900,000✔
5341
      uint64_t v = *(uint64_t*)data;
900,000✔
5342
      STATE_COMP(op, v, param);
900,000!
5343
      break;
×
5344
    }
5345
    case TSDB_DATA_TYPE_FLOAT: {
2,592,596✔
5346
      float v = *(float*)data;
2,592,596✔
5347
      STATE_COMP(op, v, param);
2,592,596!
5348
      break;
×
5349
    }
5350
    case TSDB_DATA_TYPE_DOUBLE: {
16,311,459✔
5351
      double v = *(double*)data;
16,311,459✔
5352
      STATE_COMP(op, v, param);
16,311,459!
5353
      break;
×
5354
    }
5355
    default: {
×
5356
      return false;
×
5357
    }
5358
  }
5359
  return false;
×
5360
}
5361

5362
int32_t stateCountFunction(SqlFunctionCtx* pCtx) {
187,850✔
5363
  int32_t              code = TSDB_CODE_SUCCESS;
187,850✔
5364
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
187,850✔
5365
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
187,850✔
5366

5367
  SInputColumnInfoData* pInput = &pCtx->input;
187,850✔
5368
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
187,850✔
5369

5370
  SColumnInfoData* pInputCol = pInput->pData[0];
187,850✔
5371

5372
  int32_t          numOfElems = 0;
187,850✔
5373
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
187,850✔
5374

5375
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
187,850✔
5376
  if (STATE_OPER_INVALID == op) {
187,850!
5377
    return 0;
×
5378
  }
5379

5380
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
34,819,918✔
5381
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
34,632,068!
5382
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5383
    } else {
5384
      pInfo->prevTs = tsList[i];
34,632,068✔
5385
    }
5386

5387
    pInfo->isPrevTsSet = true;
34,632,068✔
5388
    numOfElems++;
34,632,068✔
5389

5390
    if (colDataIsNull_f(pInputCol, i)) {
34,632,068!
5391
      colDataSetNULL(pOutput, i);
16,730,511!
5392
      // handle selectivity
5393
      if (pCtx->subsidiaries.num > 0) {
16,731,936✔
5394
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
5,679✔
5395
        if (TSDB_CODE_SUCCESS != code) {
5,679!
5396
          return code;
×
5397
        }
5398
      }
5399
      continue;
16,731,936✔
5400
    }
5401

5402
    bool ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
17,901,842✔
5403

5404
    int64_t output = -1;
17,901,842✔
5405
    if (ret) {
17,901,842✔
5406
      output = ++pInfo->count;
11,395,538✔
5407
    } else {
5408
      pInfo->count = 0;
6,506,304✔
5409
    }
5410
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
17,901,842✔
5411
    if (TSDB_CODE_SUCCESS != code) {
17,901,842!
5412
      return code;
×
5413
    }
5414

5415
    // handle selectivity
5416
    if (pCtx->subsidiaries.num > 0) {
17,901,842✔
5417
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
68,148✔
5418
      if (TSDB_CODE_SUCCESS != code) {
68,148!
5419
        return code;
×
5420
      }
5421
    }
5422
  }
5423

5424
  pResInfo->numOfRes = numOfElems;
187,850✔
5425
  return TSDB_CODE_SUCCESS;
187,850✔
5426
}
5427

5428
int32_t stateDurationFunction(SqlFunctionCtx* pCtx) {
1,233,023✔
5429
  int32_t              code = TSDB_CODE_SUCCESS;
1,233,023✔
5430
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,233,023✔
5431
  SStateInfo*          pInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,233,023✔
5432

5433
  SInputColumnInfoData* pInput = &pCtx->input;
1,233,023✔
5434
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
1,233,023✔
5435

5436
  SColumnInfoData* pInputCol = pInput->pData[0];
1,233,023✔
5437

5438
  int32_t          numOfElems = 0;
1,233,023✔
5439
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
1,233,023✔
5440

5441
  // TODO: process timeUnit for different db precisions
5442
  int32_t timeUnit = 1;
1,233,023✔
5443
  if (pCtx->numOfParams == 5) {  // TODO: param number incorrect
1,233,023✔
5444
    timeUnit = pCtx->param[3].param.i;
927,110✔
5445
  }
5446

5447
  int8_t op = getStateOpType(varDataVal(pCtx->param[1].param.pz));
1,233,023✔
5448
  if (STATE_OPER_INVALID == op) {
1,233,023!
5449
    return TSDB_CODE_INVALID_PARA;
×
5450
  }
5451

5452
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
67,186,991✔
5453
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
65,953,968!
5454
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5455
    } else {
5456
      pInfo->prevTs = tsList[i];
65,953,968✔
5457
    }
5458

5459
    pInfo->isPrevTsSet = true;
65,953,692✔
5460
    numOfElems++;
65,953,692✔
5461

5462
    if (colDataIsNull_f(pInputCol, i)) {
65,953,692!
5463
      colDataSetNULL(pOutput, i);
15,074,184!
5464
      // handle selectivity
5465
      if (pCtx->subsidiaries.num > 0) {
15,074,460✔
5466
        code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
9,291✔
5467
        if (TSDB_CODE_SUCCESS != code) {
9,291!
5468
          return code;
×
5469
        }
5470
      }
5471
      continue;
15,074,460✔
5472
    }
5473

5474
    bool    ret = checkStateOp(op, pInputCol, i, pCtx->param[2].param);
50,879,784✔
5475
    int64_t output = -1;
50,879,784✔
5476
    if (ret) {
50,879,784✔
5477
      if (pInfo->durationStart == 0) {
12,352,936✔
5478
        output = 0;
1,721,861✔
5479
        pInfo->durationStart = tsList[i];
1,721,861✔
5480
      } else {
5481
        output = (tsList[i] - pInfo->durationStart) / timeUnit;
10,631,075!
5482
      }
5483
    } else {
5484
      pInfo->durationStart = 0;
38,526,848✔
5485
    }
5486
    code = colDataSetVal(pOutput, pCtx->offset + numOfElems - 1, (char*)&output, false);
50,879,784✔
5487
    if (TSDB_CODE_SUCCESS != code) {
50,879,784!
5488
      return code;
×
5489
    }
5490

5491
    // handle selectivity
5492
    if (pCtx->subsidiaries.num > 0) {
50,879,784✔
5493
      code = appendSelectivityValue(pCtx, i, pCtx->offset + numOfElems - 1);
111,492✔
5494
      if (TSDB_CODE_SUCCESS != code) {
111,492!
5495
        return code;
×
5496
      }
5497
    }
5498
  }
5499

5500
  pResInfo->numOfRes = numOfElems;
1,233,023✔
5501
  return TSDB_CODE_SUCCESS;
1,233,023✔
5502
}
5503

5504
bool getCsumFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
489,068✔
5505
  pEnv->calcMemSize = sizeof(SSumRes);
489,068✔
5506
  return true;
489,068✔
5507
}
5508

5509
int32_t csumFunction(SqlFunctionCtx* pCtx) {
586,609✔
5510
  int32_t              code = TSDB_CODE_SUCCESS;
586,609✔
5511
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
586,609✔
5512
  SSumRes*             pSumRes = GET_ROWCELL_INTERBUF(pResInfo);
586,609✔
5513

5514
  SInputColumnInfoData* pInput = &pCtx->input;
586,609✔
5515
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
586,609✔
5516

5517
  SColumnInfoData* pInputCol = pInput->pData[0];
586,609✔
5518
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
586,609✔
5519

5520
  int32_t numOfElems = 0;
586,609✔
5521
  int32_t type = pInputCol->info.type;
586,609✔
5522
  int32_t startOffset = pCtx->offset;
586,609✔
5523
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
79,641,993✔
5524
    if (pSumRes->isPrevTsSet == true && tsList[i] == pSumRes->prevTs) {
79,062,443!
5525
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
10,647✔
5526
    } else {
5527
      pSumRes->prevTs = tsList[i];
79,050,964✔
5528
    }
5529
    pSumRes->isPrevTsSet = true;
79,051,520✔
5530

5531
    int32_t pos = startOffset + numOfElems;
79,052,072✔
5532
    if (colDataIsNull_f(pInputCol, i)) {
79,052,072!
5533
      // colDataSetNULL(pOutput, i);
5534
      continue;
48,387,922✔
5535
    }
5536

5537
    char* data = colDataGetData(pInputCol, i);
30,667,462!
5538
    if (IS_SIGNED_NUMERIC_TYPE(type)) {
53,175,694!
5539
      int64_t v;
5540
      GET_TYPED_DATA(v, int64_t, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
22,508,232!
5541
      pSumRes->isum += v;
22,508,232✔
5542
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->isum, false);
22,508,232✔
5543
      if (TSDB_CODE_SUCCESS != code) {
22,508,232!
5544
        return code;
×
5545
      }
5546
    } else if (IS_UNSIGNED_NUMERIC_TYPE(type)) {
16,192,260!
5547
      uint64_t v;
5548
      GET_TYPED_DATA(v, uint64_t, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
8,033,030!
5549
      pSumRes->usum += v;
8,033,030✔
5550
      code = colDataSetVal(pOutput, pos, (char*)&pSumRes->usum, false);
8,033,030✔
5551
      if (TSDB_CODE_SUCCESS != code) {
8,033,030!
5552
        return code;
×
5553
      }
5554
    } else if (IS_FLOAT_TYPE(type)) {
126,200!
5555
      double v;
5556
      GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
126,200!
5557
      pSumRes->dsum += v;
126,200✔
5558
      // check for overflow
5559
      if (isinf(pSumRes->dsum) || isnan(pSumRes->dsum)) {
126,200!
5560
        colDataSetNULL(pOutput, pos);
1,262!
5561
      } else {
5562
        code = colDataSetVal(pOutput, pos, (char*)&pSumRes->dsum, false);
124,938✔
5563
        if (TSDB_CODE_SUCCESS != code) {
124,938!
5564
          return code;
×
5565
        }
5566
      }
5567
    }
5568

5569
    // handle selectivity
5570
    if (pCtx->subsidiaries.num > 0) {
30,667,462✔
5571
      code = appendSelectivityValue(pCtx, i, pos);
29,450✔
5572
      if (TSDB_CODE_SUCCESS != code) {
29,450!
5573
        return code;
×
5574
      }
5575
    }
5576

5577
    numOfElems++;
30,667,462✔
5578
  }
5579

5580
  pResInfo->numOfRes = numOfElems;
575,962✔
5581
  return TSDB_CODE_SUCCESS;
575,962✔
5582
}
5583

5584
bool getMavgFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
226,373✔
5585
  pEnv->calcMemSize = sizeof(SMavgInfo) + MAVG_MAX_POINTS_NUM * sizeof(double);
226,373✔
5586
  return true;
226,373✔
5587
}
5588

5589
int32_t mavgFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
551,374✔
5590
  if (pResultInfo->initialized) {
551,374✔
5591
    return TSDB_CODE_SUCCESS;
217,572✔
5592
  }
5593
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
333,802!
5594
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5595
  }
5596

5597
  SMavgInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
333,802✔
5598
  pInfo->pos = 0;
333,802✔
5599
  pInfo->sum = 0;
333,802✔
5600
  pInfo->prevTs = -1;
333,802✔
5601
  pInfo->isPrevTsSet = false;
333,802✔
5602
  pInfo->numOfPoints = pCtx->param[1].param.i;
333,802✔
5603
  if (pInfo->numOfPoints < 1 || pInfo->numOfPoints > MAVG_MAX_POINTS_NUM) {
333,802!
5604
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
5605
  }
5606
  pInfo->pointsMeet = false;
333,802✔
5607

5608
  return TSDB_CODE_SUCCESS;
333,802✔
5609
}
5610

5611
int32_t mavgFunction(SqlFunctionCtx* pCtx) {
325,001✔
5612
  int32_t              code = TSDB_CODE_SUCCESS;
325,001✔
5613
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
325,001✔
5614
  SMavgInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
325,001✔
5615

5616
  SInputColumnInfoData* pInput = &pCtx->input;
325,001✔
5617
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
325,001✔
5618

5619
  SColumnInfoData* pInputCol = pInput->pData[0];
325,001✔
5620
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
325,001✔
5621
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
325,001✔
5622

5623
  int32_t numOfElems = 0;
325,001✔
5624
  int32_t type = pInputCol->info.type;
325,001✔
5625
  int32_t startOffset = pCtx->offset;
325,001✔
5626
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
53,606,945✔
5627
    if (pInfo->isPrevTsSet == true && tsList[i] == pInfo->prevTs) {
53,281,944!
5628
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
5629
    } else {
5630
      pInfo->prevTs = tsList[i];
53,281,944✔
5631
    }
5632
    pInfo->isPrevTsSet = true;
53,281,944✔
5633

5634
    int32_t pos = startOffset + numOfElems;
53,281,944✔
5635
    if (colDataIsNull_f(pInputCol, i)) {
53,281,944!
5636
      // colDataSetNULL(pOutput, i);
5637
      continue;
18,887,615✔
5638
    }
5639

5640
    char*  data = colDataGetData(pInputCol, i);
34,394,329!
5641
    double v;
5642
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
34,394,329!
5643

5644
    if (!pInfo->pointsMeet && (pInfo->pos < pInfo->numOfPoints - 1)) {
34,394,329!
5645
      pInfo->points[pInfo->pos] = v;
18,581,182✔
5646
      pInfo->sum += v;
18,581,182✔
5647
    } else {
5648
      if (!pInfo->pointsMeet && (pInfo->pos == pInfo->numOfPoints - 1)) {
15,813,147!
5649
        pInfo->sum += v;
113,553✔
5650
        pInfo->pointsMeet = true;
113,553✔
5651
      } else {
5652
        pInfo->sum = pInfo->sum + v - pInfo->points[pInfo->pos];
15,699,594✔
5653
      }
5654

5655
      pInfo->points[pInfo->pos] = v;
15,813,147✔
5656
      double result = pInfo->sum / pInfo->numOfPoints;
15,813,147!
5657
      // check for overflow
5658
      if (isinf(result) || isnan(result)) {
15,813,147!
5659
        colDataSetNULL(pOutput, pos);
×
5660
      } else {
5661
        code = colDataSetVal(pOutput, pos, (char*)&result, false);
15,813,147✔
5662
        if (TSDB_CODE_SUCCESS != code) {
15,813,147!
5663
          return code;
×
5664
        }
5665
      }
5666

5667
      // handle selectivity
5668
      if (pCtx->subsidiaries.num > 0) {
15,813,147✔
5669
        code = appendSelectivityValue(pCtx, i, pos);
44,170✔
5670
        if (TSDB_CODE_SUCCESS != code) {
44,170!
5671
          return code;
×
5672
        }
5673
      }
5674

5675
      numOfElems++;
15,813,147✔
5676
    }
5677

5678
    pInfo->pos++;
34,394,329✔
5679
    if (pInfo->pos == pInfo->numOfPoints) {
34,394,329✔
5680
      pInfo->pos = 0;
324,448✔
5681
    }
5682
  }
5683

5684
  pResInfo->numOfRes = numOfElems;
325,001✔
5685
  return TSDB_CODE_SUCCESS;
325,001✔
5686
}
5687

5688
static SSampleInfo* getSampleOutputInfo(SqlFunctionCtx* pCtx) {
3,792,272✔
5689
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
3,792,272✔
5690
  SSampleInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
3,792,272✔
5691

5692
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
3,792,272✔
5693
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
3,792,272✔
5694

5695
  return pInfo;
3,791,641✔
5696
}
5697

5698
bool getSampleFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
574,797✔
5699
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
574,797✔
5700
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
574,521✔
5701
  int32_t      numOfSamples = pVal->datum.i;
572,782✔
5702
  pEnv->calcMemSize = sizeof(SSampleInfo) + numOfSamples * (pCol->node.resType.bytes + sizeof(STuplePos));
572,782✔
5703
  return true;
573,060✔
5704
}
5705

5706
int32_t sampleFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
1,826,440✔
5707
  if (pResultInfo->initialized) {
1,826,440!
5708
    return TSDB_CODE_SUCCESS;
×
5709
  }
5710
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
1,826,440!
5711
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
5712
  }
5713

5714
  taosSeedRand(taosSafeRand());
1,826,440✔
5715

5716
  SSampleInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
1,826,440✔
5717
  pInfo->samples = pCtx->param[1].param.i;
1,826,440✔
5718
  pInfo->totalPoints = 0;
1,826,440✔
5719
  pInfo->numSampled = 0;
1,826,440✔
5720
  pInfo->colType = pCtx->resDataInfo.type;
1,826,440✔
5721
  pInfo->colBytes = pCtx->resDataInfo.bytes;
1,826,440✔
5722
  pInfo->nullTuplePos.pageId = -1;
1,826,440✔
5723
  pInfo->nullTupleSaved = false;
1,826,440✔
5724
  pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
1,826,440✔
5725
  pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
1,826,440✔
5726

5727
  return TSDB_CODE_SUCCESS;
1,826,440✔
5728
}
5729

5730
static void sampleAssignResult(SSampleInfo* pInfo, char* data, int32_t index) {
32,760,454✔
5731
  assignVal(pInfo->data + index * pInfo->colBytes, data, pInfo->colBytes, pInfo->colType);
32,760,454✔
5732
}
32,759,884✔
5733

5734
static int32_t doReservoirSample(SqlFunctionCtx* pCtx, SSampleInfo* pInfo, char* data, int32_t index) {
38,707,171✔
5735
  pInfo->totalPoints++;
38,707,171✔
5736
  if (pInfo->numSampled < pInfo->samples) {
38,707,171✔
5737
    sampleAssignResult(pInfo, data, pInfo->numSampled);
28,480,855✔
5738
    if (pCtx->subsidiaries.num > 0) {
28,480,285✔
5739
      int32_t code = saveTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[pInfo->numSampled]);
1,288,368✔
5740
      if (code != TSDB_CODE_SUCCESS) {
1,288,368!
5741
        return code;
×
5742
      }
5743
    }
5744
    pInfo->numSampled++;
28,480,285✔
5745
  } else {
5746
    int32_t j = taosRand() % (pInfo->totalPoints);
10,226,316!
5747
    if (j < pInfo->samples) {
10,226,316✔
5748
      sampleAssignResult(pInfo, data, j);
4,279,884✔
5749
      if (pCtx->subsidiaries.num > 0) {
4,279,884✔
5750
        int32_t code = updateTupleData(pCtx, index, pCtx->pSrcBlock, &pInfo->tuplePos[j]);
37,759✔
5751
        if (code != TSDB_CODE_SUCCESS) {
38,044!
5752
          return code;
×
5753
        }
5754
      }
5755
    }
5756
  }
5757

5758
  return TSDB_CODE_SUCCESS;
38,706,601✔
5759
}
5760

5761
int32_t sampleFunction(SqlFunctionCtx* pCtx) {
1,965,832✔
5762
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,965,832✔
5763
  SSampleInfo*         pInfo = getSampleOutputInfo(pCtx);
1,965,832✔
5764

5765
  SInputColumnInfoData* pInput = &pCtx->input;
1,965,832✔
5766

5767
  SColumnInfoData* pInputCol = pInput->pData[0];
1,965,832✔
5768
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; i += 1) {
73,844,791✔
5769
    if (colDataIsNull_s(pInputCol, i)) {
143,753,769!
5770
      continue;
33,172,358✔
5771
    }
5772

5773
    char*   data = colDataGetData(pInputCol, i);
38,706,601!
5774
    int32_t code = doReservoirSample(pCtx, pInfo, data, i);
38,706,886✔
5775
    if (code != TSDB_CODE_SUCCESS) {
38,706,601!
5776
      return code;
×
5777
    }
5778
  }
5779

5780
  if (pInfo->numSampled == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
1,965,832!
5781
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
2,522✔
5782
    if (code != TSDB_CODE_SUCCESS) {
2,522!
5783
      return code;
×
5784
    }
5785
    pInfo->nullTupleSaved = true;
2,522✔
5786
  }
5787

5788
  SET_VAL(pResInfo, pInfo->numSampled, pInfo->numSampled);
1,965,832✔
5789
  return TSDB_CODE_SUCCESS;
1,965,832✔
5790
}
5791

5792
int32_t sampleFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,826,440✔
5793
  int32_t              code = TSDB_CODE_SUCCESS;
1,826,440✔
5794
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
1,826,440✔
5795

5796
  SSampleInfo* pInfo = getSampleOutputInfo(pCtx);
1,826,440✔
5797
  pEntryInfo->complete = true;
1,826,440✔
5798

5799
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
1,826,440✔
5800
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
1,826,440✔
5801
  if (NULL == pCol) {
1,826,440!
5802
    return TSDB_CODE_OUT_OF_RANGE;
×
5803
  }
5804

5805
  int32_t currentRow = pBlock->info.rows;
1,826,440✔
5806
  if (pInfo->numSampled == 0) {
1,826,440✔
5807
    colDataSetNULL(pCol, currentRow);
219,298!
5808
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
219,298✔
5809
    return code;
219,298✔
5810
  }
5811
  for (int32_t i = 0; i < pInfo->numSampled; ++i) {
30,087,997✔
5812
    code = colDataSetVal(pCol, currentRow + i, pInfo->data + i * pInfo->colBytes, false);
28,480,855✔
5813
    if (TSDB_CODE_SUCCESS != code) {
28,480,855!
5814
      return code;
×
5815
    }
5816
    code = setSelectivityValue(pCtx, pBlock, &pInfo->tuplePos[i], currentRow + i);
28,480,855✔
5817
    if (TSDB_CODE_SUCCESS != code) {
28,480,855!
5818
      return code;
×
5819
    }
5820
  }
5821

5822
  return code;
1,607,142✔
5823
}
5824

5825
bool getTailFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
5826
#if 0
5827
  SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
5828
  SValueNode*  pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
5829
  int32_t      numOfPoints = pVal->datum.i;
5830
  pEnv->calcMemSize = sizeof(STailInfo) + numOfPoints * (POINTER_BYTES + sizeof(STailItem) + pCol->node.resType.bytes);
5831
#endif
5832
  return true;
×
5833
}
5834

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

5841
  STailInfo* pInfo = GET_ROWCELL_INTERBUF(pResultInfo);
5842
  pInfo->numAdded = 0;
5843
  pInfo->numOfPoints = pCtx->param[1].param.i;
5844
  if (pCtx->numOfParams == 4) {
5845
    pInfo->offset = pCtx->param[2].param.i;
5846
  } else {
5847
    pInfo->offset = 0;
5848
  }
5849
  pInfo->colType = pCtx->resDataInfo.type;
5850
  pInfo->colBytes = pCtx->resDataInfo.bytes;
5851
  if ((pInfo->numOfPoints < 1 || pInfo->numOfPoints > TAIL_MAX_POINTS_NUM) ||
5852
      (pInfo->numOfPoints < 0 || pInfo->numOfPoints > TAIL_MAX_OFFSET)) {
5853
    return false;
5854
  }
5855

5856
  pInfo->pItems = (STailItem**)((char*)pInfo + sizeof(STailInfo));
5857
  char* pItem = (char*)pInfo->pItems + pInfo->numOfPoints * POINTER_BYTES;
5858

5859
  size_t unitSize = sizeof(STailItem) + pInfo->colBytes;
5860
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5861
    pInfo->pItems[i] = (STailItem*)(pItem + i * unitSize);
5862
    pInfo->pItems[i]->isNull = false;
5863
  }
5864
#endif
5865

5866
  return TSDB_CODE_SUCCESS;
×
5867
}
5868

5869
static void tailAssignResult(STailItem* pItem, char* data, int32_t colBytes, TSKEY ts, bool isNull) {
×
5870
#if 0
5871
  pItem->timestamp = ts;
5872
  if (isNull) {
5873
    pItem->isNull = true;
5874
  } else {
5875
    pItem->isNull = false;
5876
    memcpy(pItem->data, data, colBytes);
5877
  }
5878
#endif
5879
}
×
5880

5881
#if 0
5882
static int32_t tailCompFn(const void* p1, const void* p2, const void* param) {
5883
  STailItem* d1 = *(STailItem**)p1;
5884
  STailItem* d2 = *(STailItem**)p2;
5885
  return compareInt64Val(&d1->timestamp, &d2->timestamp);
5886
}
5887

5888
static void doTailAdd(STailInfo* pInfo, char* data, TSKEY ts, bool isNull) {
5889
  STailItem** pList = pInfo->pItems;
5890
  if (pInfo->numAdded < pInfo->numOfPoints) {
5891
    tailAssignResult(pList[pInfo->numAdded], data, pInfo->colBytes, ts, isNull);
5892
    taosheapsort((void*)pList, sizeof(STailItem**), pInfo->numAdded + 1, NULL, tailCompFn, 0);
5893
    pInfo->numAdded++;
5894
  } else if (pList[0]->timestamp < ts) {
5895
    tailAssignResult(pList[0], data, pInfo->colBytes, ts, isNull);
5896
    taosheapadjust((void*)pList, sizeof(STailItem**), 0, pInfo->numOfPoints - 1, NULL, tailCompFn, NULL, 0);
5897
  }
5898
}
5899
#endif
5900

5901
int32_t tailFunction(SqlFunctionCtx* pCtx) {
×
5902
#if 0
5903
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5904
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5905

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

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

5912
  int32_t startOffset = pCtx->offset;
5913
  if (pInfo->offset >= pInput->numOfRows) {
5914
    return 0;
5915
  } else {
5916
    pInfo->numOfPoints = TMIN(pInfo->numOfPoints, pInput->numOfRows - pInfo->offset);
5917
  }
5918
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex - pInfo->offset; i += 1) {
5919
    char* data = colDataGetData(pInputCol, i);
5920
    doTailAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
5921
  }
5922

5923
  taosqsort(pInfo->pItems, pInfo->numOfPoints, POINTER_BYTES, NULL, tailCompFn);
5924

5925
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
5926
    int32_t    pos = startOffset + i;
5927
    STailItem* pItem = pInfo->pItems[i];
5928
    if (pItem->isNull) {
5929
      colDataSetNULL(pOutput, pos);
5930
    } else {
5931
      colDataSetVal(pOutput, pos, pItem->data, false);
5932
    }
5933
  }
5934

5935
  return pInfo->numOfPoints;
5936
#endif
5937
  return 0;
×
5938
}
5939

5940
int32_t tailFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
5941
#if 0
5942
  SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
5943
  STailInfo*           pInfo = GET_ROWCELL_INTERBUF(pEntryInfo);
5944
  pEntryInfo->complete = true;
5945

5946
  int32_t type = pCtx->input.pData[0]->info.type;
5947
  int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
5948

5949
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
5950

5951
  // todo assign the tag value and the corresponding row data
5952
  int32_t currentRow = pBlock->info.rows;
5953
  for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
5954
    STailItem* pItem = pInfo->pItems[i];
5955
    colDataSetVal(pCol, currentRow, pItem->data, false);
5956
    currentRow += 1;
5957
  }
5958

5959
  return pEntryInfo->numOfRes;
5960
#endif
5961
  return 0;
×
5962
}
5963

5964
bool getUniqueFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
5965
#if 0
5966
  pEnv->calcMemSize = sizeof(SUniqueInfo) + UNIQUE_MAX_RESULT_SIZE;
5967
#endif
5968
  return true;
×
5969
}
5970

5971
int32_t uniqueFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
×
5972
#if 0
5973
  if (!functionSetup(pCtx, pResInfo)) {
5974
    return false;
5975
  }
5976

5977
  SUniqueInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
5978
  pInfo->numOfPoints = 0;
5979
  pInfo->colType = pCtx->resDataInfo.type;
5980
  pInfo->colBytes = pCtx->resDataInfo.bytes;
5981
  if (pInfo->pHash != NULL) {
5982
    taosHashClear(pInfo->pHash);
5983
  } else {
5984
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
5985
  }
5986
#endif
5987
  return TSDB_CODE_SUCCESS;
×
5988
}
5989

5990
#if 0
5991
static void doUniqueAdd(SUniqueInfo* pInfo, char* data, TSKEY ts, bool isNull) {
5992
  // handle null elements
5993
  if (isNull == true) {
5994
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
5995
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
5996
    if (pInfo->hasNull == false && pItem->isNull == false) {
5997
      pItem->timestamp = ts;
5998
      pItem->isNull = true;
5999
      pInfo->numOfPoints++;
6000
      pInfo->hasNull = true;
6001
    } else if (pItem->timestamp > ts && pItem->isNull == true) {
6002
      pItem->timestamp = ts;
6003
    }
6004
    return;
6005
  }
6006

6007
  int32_t      hashKeyBytes = IS_VAR_DATA_TYPE(pInfo->colType) ? varDataTLen(data) : pInfo->colBytes;
6008
  SUniqueItem* pHashItem = taosHashGet(pInfo->pHash, data, hashKeyBytes);
6009
  if (pHashItem == NULL) {
6010
    int32_t      size = sizeof(SUniqueItem) + pInfo->colBytes;
6011
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + pInfo->numOfPoints * size);
6012
    pItem->timestamp = ts;
6013
    memcpy(pItem->data, data, pInfo->colBytes);
6014

6015
    taosHashPut(pInfo->pHash, data, hashKeyBytes, (char*)pItem, sizeof(SUniqueItem*));
6016
    pInfo->numOfPoints++;
6017
  } else if (pHashItem->timestamp > ts) {
6018
    pHashItem->timestamp = ts;
6019
  }
6020
}
6021
#endif
6022

6023
int32_t uniqueFunction(SqlFunctionCtx* pCtx) {
×
6024
#if 0
6025
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
6026
  SUniqueInfo*         pInfo = GET_ROWCELL_INTERBUF(pResInfo);
6027

6028
  SInputColumnInfoData* pInput = &pCtx->input;
6029
  TSKEY*                tsList = (int64_t*)pInput->pPTS->pData;
6030

6031
  SColumnInfoData* pInputCol = pInput->pData[0];
6032
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
6033
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
6034

6035
  int32_t startOffset = pCtx->offset;
6036
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
6037
    char* data = colDataGetData(pInputCol, i);
6038
    doUniqueAdd(pInfo, data, tsList[i], colDataIsNull_s(pInputCol, i));
6039

6040
    if (sizeof(SUniqueInfo) + pInfo->numOfPoints * (sizeof(SUniqueItem) + pInfo->colBytes) >= UNIQUE_MAX_RESULT_SIZE) {
6041
      taosHashCleanup(pInfo->pHash);
6042
      return 0;
6043
    }
6044
  }
6045

6046
  for (int32_t i = 0; i < pInfo->numOfPoints; ++i) {
6047
    SUniqueItem* pItem = (SUniqueItem*)(pInfo->pItems + i * (sizeof(SUniqueItem) + pInfo->colBytes));
6048
    if (pItem->isNull == true) {
6049
      colDataSetNULL(pOutput, i);
6050
    } else {
6051
      colDataSetVal(pOutput, i, pItem->data, false);
6052
    }
6053
    if (pTsOutput != NULL) {
6054
      colDataSetInt64(pTsOutput, i, &pItem->timestamp);
6055
    }
6056
  }
6057

6058
  return pInfo->numOfPoints;
6059
#endif
6060
  return 0;
×
6061
}
6062

6063
bool getModeFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
462,247✔
6064
  pEnv->calcMemSize = sizeof(SModeInfo);
462,247✔
6065
  return true;
462,525✔
6066
}
6067

6068
int32_t modeFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
775,233✔
6069
  if (pResInfo->initialized) {
775,233!
6070
    return TSDB_CODE_SUCCESS;
×
6071
  }
6072
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
775,233!
6073
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6074
  }
6075

6076
  SModeInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
775,233✔
6077
  pInfo->colType = pCtx->resDataInfo.type;
775,233✔
6078
  pInfo->colBytes = pCtx->resDataInfo.bytes;
775,233✔
6079
  if (pInfo->pHash != NULL) {
775,233!
6080
    taosHashClear(pInfo->pHash);
×
6081
  } else {
6082
    pInfo->pHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK);
775,233✔
6083
    if (NULL == pInfo->pHash) {
775,233!
6084
      return terrno;
×
6085
    }
6086
  }
6087
  pInfo->nullTupleSaved = false;
775,233✔
6088
  pInfo->nullTuplePos.pageId = -1;
775,233✔
6089

6090
  pInfo->buf = taosMemoryMalloc(pInfo->colBytes);
775,233!
6091
  if (NULL == pInfo->buf) {
775,233!
6092
    taosHashCleanup(pInfo->pHash);
×
6093
    pInfo->pHash = NULL;
×
6094
    return terrno;
×
6095
  }
6096
  pCtx->needCleanup = true;
775,233✔
6097
  return TSDB_CODE_SUCCESS;
775,233✔
6098
}
6099

6100
static void modeFunctionCleanup(SModeInfo* pInfo) {
774,681✔
6101
  taosHashCleanup(pInfo->pHash);
774,681✔
6102
  pInfo->pHash = NULL;
775,233✔
6103
  taosMemoryFreeClear(pInfo->buf);
774,957!
6104
}
775,233✔
6105

6106
void modeFunctionCleanupExt(SqlFunctionCtx* pCtx) {
×
6107
  if (pCtx == NULL || GET_RES_INFO(pCtx) == NULL || GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)) == NULL) {
×
6108
    return;
×
6109
  }
6110
  modeFunctionCleanup(GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx)));
×
6111
}
6112

6113
static int32_t saveModeTupleData(SqlFunctionCtx* pCtx, char* data, SModeInfo* pInfo, STuplePos* pPos) {
54,247,147✔
6114
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
54,247,147!
6115
    if (pInfo->colType == TSDB_DATA_TYPE_JSON) {
649,422✔
6116
      (void)memcpy(pInfo->buf, data, getJsonValueLen(data));
633,798!
6117
    } else if (IS_STR_DATA_BLOB(pInfo->colType)) {
15,423!
6118
      (void)memcpy(pInfo->buf, data, blobDataTLen(data));
×
6119
    } else {
6120
      (void)memcpy(pInfo->buf, data, varDataTLen(data));
15,423!
6121
    }
6122
  } else {
6123
    (void)memcpy(pInfo->buf, data, pInfo->colBytes);
53,597,926!
6124
  }
6125

6126
  return doSaveTupleData(&pCtx->saveHandle, pInfo->buf, pInfo->colBytes, NULL, pPos, pCtx->pStore);
54,246,946✔
6127
}
6128

6129
static int32_t doModeAdd(SModeInfo* pInfo, int32_t rowIndex, SqlFunctionCtx* pCtx, char* data) {
85,330,408✔
6130
  int32_t code = TSDB_CODE_SUCCESS;
85,330,408✔
6131
  int32_t hashKeyBytes;
6132
  if (IS_VAR_DATA_TYPE(pInfo->colType)) {
85,330,408!
6133
    hashKeyBytes = calcStrBytesByType(pInfo->colType, data);
999,396✔
6134
  } else {
6135
    hashKeyBytes = pInfo->colBytes;
84,331,615✔
6136
  }
6137

6138
  SModeItem* pHashItem = (SModeItem*)taosHashGet(pInfo->pHash, data, hashKeyBytes);
85,330,408✔
6139
  if (pHashItem == NULL) {
85,331,212✔
6140
    int32_t   size = sizeof(SModeItem);
54,247,147✔
6141
    SModeItem item = {0};
54,247,147✔
6142

6143
    item.count += 1;
54,247,147✔
6144
    code = saveModeTupleData(pCtx, data, pInfo, &item.dataPos);
54,247,147✔
6145
    if (code != TSDB_CODE_SUCCESS) {
54,246,946!
6146
      return code;
×
6147
    }
6148

6149
    if (pCtx->subsidiaries.num > 0) {
54,246,946✔
6150
      code = saveTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &item.tuplePos);
76,444✔
6151
      if (code != TSDB_CODE_SUCCESS) {
76,444!
6152
        return code;
×
6153
      }
6154
    }
6155

6156
    code = taosHashPut(pInfo->pHash, data, hashKeyBytes, &item, sizeof(SModeItem));
54,246,946✔
6157
    if (code != TSDB_CODE_SUCCESS) {
54,246,112!
6158
      return code;
×
6159
    }
6160
  } else {
6161
    pHashItem->count += 1;
31,084,065✔
6162
    if (pCtx->subsidiaries.num > 0) {
31,084,065✔
6163
      code = updateTupleData(pCtx, rowIndex, pCtx->pSrcBlock, &pHashItem->tuplePos);
25,068✔
6164
      if (code != TSDB_CODE_SUCCESS) {
25,068!
6165
        return code;
×
6166
      }
6167
    }
6168
  }
6169

6170
  return code;
85,329,775✔
6171
}
6172

6173
int32_t modeFunction(SqlFunctionCtx* pCtx) {
1,585,827✔
6174
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,585,827✔
6175
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,585,827✔
6176

6177
  SInputColumnInfoData* pInput = &pCtx->input;
1,585,827✔
6178

6179
  SColumnInfoData* pInputCol = pInput->pData[0];
1,585,827✔
6180
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
1,585,827✔
6181

6182
  int32_t numOfElems = 0;
1,585,827✔
6183
  int32_t startOffset = pCtx->offset;
1,585,827✔
6184
  for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) {
130,912,204✔
6185
    if (colDataIsNull_s(pInputCol, i)) {
258,659,791!
6186
      continue;
44,003,557✔
6187
    }
6188
    numOfElems++;
85,329,574✔
6189

6190
    char*   data = colDataGetData(pInputCol, i);
85,329,574!
6191
    int32_t code = doModeAdd(pInfo, i, pCtx, data);
85,330,609✔
6192
    if (code != TSDB_CODE_SUCCESS) {
85,329,775✔
6193
      modeFunctionCleanup(pInfo);
6,955✔
6194
      return code;
×
6195
    }
6196
  }
6197

6198
  if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
1,585,827!
6199
    int32_t code = saveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
6,440✔
6200
    if (code != TSDB_CODE_SUCCESS) {
6,440!
6201
      modeFunctionCleanup(pInfo);
×
6202
      return code;
×
6203
    }
6204
    pInfo->nullTupleSaved = true;
6,440✔
6205
  }
6206

6207
  SET_VAL(pResInfo, numOfElems, 1);
1,585,827✔
6208

6209
  return TSDB_CODE_SUCCESS;
1,585,827✔
6210
}
6211

6212
int32_t modeFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
774,957✔
6213
  int32_t              code = TSDB_CODE_SUCCESS;
774,957✔
6214
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
774,957✔
6215
  SModeInfo*           pInfo = GET_ROWCELL_INTERBUF(pResInfo);
775,233✔
6216
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
774,957✔
6217
  SColumnInfoData*     pCol = taosArrayGet(pBlock->pDataBlock, slotId);
774,957✔
6218
  int32_t              currentRow = pBlock->info.rows;
775,233✔
6219
  if (NULL == pCol) {
774,957!
6220
    modeFunctionCleanup(pInfo);
×
6221
    return TSDB_CODE_OUT_OF_RANGE;
×
6222
  }
6223

6224
  STuplePos resDataPos, resTuplePos;
774,957✔
6225
  int32_t   maxCount = 0;
774,957✔
6226

6227
  void* pIter = taosHashIterate(pInfo->pHash, NULL);
774,957✔
6228
  while (pIter != NULL) {
55,019,290✔
6229
    SModeItem* pItem = (SModeItem*)pIter;
54,244,333✔
6230
    if (pItem->count >= maxCount) {
54,244,333✔
6231
      maxCount = pItem->count;
53,131,501✔
6232
      resDataPos = pItem->dataPos;
53,131,501✔
6233
      resTuplePos = pItem->tuplePos;
53,131,501✔
6234
    }
6235

6236
    pIter = taosHashIterate(pInfo->pHash, pIter);
54,244,333✔
6237
  }
6238

6239
  if (maxCount != 0) {
774,957✔
6240
    char* pData = NULL;
547,434✔
6241
    code = loadTupleData(pCtx, &resDataPos, &pData);
547,434✔
6242
    if (pData == NULL || TSDB_CODE_SUCCESS != code) {
547,434!
6243
      code = terrno = TSDB_CODE_NOT_FOUND;
×
6244
      qError("Load tuple data failed since %s, groupId:%" PRIu64 ", ts:%" PRId64, terrstr(),
×
6245
             resDataPos.streamTupleKey.groupId, resDataPos.streamTupleKey.ts);
6246
      modeFunctionCleanup(pInfo);
×
6247
      return code;
×
6248
    }
6249

6250
    code = colDataSetVal(pCol, currentRow, pData, false);
547,434✔
6251
    if (TSDB_CODE_SUCCESS != code) {
547,434!
6252
      modeFunctionCleanup(pInfo);
×
6253
      return code;
×
6254
    }
6255
    code = setSelectivityValue(pCtx, pBlock, &resTuplePos, currentRow);
547,434✔
6256
  } else {
6257
    colDataSetNULL(pCol, currentRow);
227,523!
6258
    code = setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
227,799✔
6259
  }
6260

6261
  modeFunctionCleanup(pInfo);
774,681✔
6262

6263
  return code;
775,233✔
6264
}
6265

6266
bool getTwaFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
302,970✔
6267
  pEnv->calcMemSize = sizeof(STwaInfo);
302,970✔
6268
  return true;
302,970✔
6269
}
6270

6271
int32_t twaFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
8,615,069✔
6272
  if (pResultInfo->initialized) {
8,615,069!
6273
    return TSDB_CODE_SUCCESS;
×
6274
  }
6275
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
8,615,069!
6276
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6277
  }
6278

6279
  STwaInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
8,615,069✔
6280
  pInfo->numOfElems = 0;
8,615,069✔
6281
  pInfo->p.key = INT64_MIN;
8,615,069✔
6282
  pInfo->win = TSWINDOW_INITIALIZER;
8,615,069✔
6283
  return TSDB_CODE_SUCCESS;
8,615,069✔
6284
}
6285

6286
static double twa_get_area(SPoint1 s, SPoint1 e) {
233,485,517✔
6287
  if (e.key == INT64_MAX || s.key == INT64_MIN) {
233,485,517!
6288
    return 0;
×
6289
  }
6290

6291
  if ((s.val >= 0 && e.val >= 0) || (s.val <= 0 && e.val <= 0)) {
233,521,510✔
6292
    return (s.val + e.val) * (e.key - s.key) / 2;
218,138,105✔
6293
  }
6294

6295
  double x = (s.key * e.val - e.key * s.val) / (e.val - s.val);
15,383,405!
6296
  double val = (s.val * (x - s.key) + e.val * (e.key - x)) / 2;
15,383,405✔
6297
  return val;
15,383,405✔
6298
}
6299

6300
int32_t twaFunction(SqlFunctionCtx* pCtx) {
8,699,074✔
6301
  int32_t               code = TSDB_CODE_SUCCESS;
8,699,074✔
6302
  SInputColumnInfoData* pInput = &pCtx->input;
8,699,074✔
6303
  SColumnInfoData*      pInputCol = pInput->pData[0];
8,699,074✔
6304

6305
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
8,699,074✔
6306
  STwaInfo*            pInfo = GET_ROWCELL_INTERBUF(pResInfo);
8,699,074✔
6307
  SPoint1*             last = &pInfo->p;
8,699,074✔
6308

6309
  if (IS_NULL_TYPE(pInputCol->info.type)) {
8,699,074!
6310
    pInfo->numOfElems = 0;
×
6311
    goto _twa_over;
×
6312
  }
6313

6314
  funcInputUpdate(pCtx);
8,699,074✔
6315
  SFuncInputRow row = {0};
8,698,443✔
6316
  bool          result = false;
8,698,443✔
6317
  if (pCtx->start.key != INT64_MIN && last->key == INT64_MIN) {
8,698,443!
6318
    while (1) {
6319
      code = funcInputGetNextRow(pCtx, &row, &result);
6,760,678✔
6320
      if (TSDB_CODE_SUCCESS != code) {
6,760,678!
6321
        return code;
×
6322
      }
6323
      if (!result) {
6,760,678!
6324
        break;
1,236✔
6325
      }
6326
      if (row.isDataNull) {
6,759,442!
6327
        continue;
1,236✔
6328
      }
6329

6330
      last->key = row.ts;
6,758,206✔
6331

6332
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData, typeGetTypeModFromColInfo(&pInputCol->info));
6,758,206!
6333

6334
      pInfo->dOutput += twa_get_area(pCtx->start, *last);
6,758,206✔
6335
      pInfo->win.skey = pCtx->start.key;
6,758,206✔
6336
      pInfo->numOfElems++;
6,758,206✔
6337
      break;
6,758,206✔
6338
    }
6339
  } else if (pInfo->p.key == INT64_MIN) {
1,939,632✔
6340
    while (1) {
6341
      code = funcInputGetNextRow(pCtx, &row, &result);
6,041,270✔
6342
      if (TSDB_CODE_SUCCESS != code) {
6,041,901!
6343
        return code;
×
6344
      }
6345
      if (!result) {
6,041,901!
6346
        break;
472,624✔
6347
      }
6348
      if (row.isDataNull) {
5,569,277!
6349
        continue;
4,174,094✔
6350
      }
6351

6352
      last->key = row.ts;
1,395,183✔
6353

6354
      GET_TYPED_DATA(last->val, double, pInputCol->info.type, row.pData, typeGetTypeModFromColInfo(&pInputCol->info));
1,394,552!
6355

6356
      pInfo->win.skey = last->key;
1,395,183✔
6357
      pInfo->numOfElems++;
1,395,183✔
6358
      break;
1,394,552✔
6359
    }
6360
  }
6361

6362
  SPoint1 st = {0};
8,699,074✔
6363

6364
  // calculate the value of
6365
  while (1) {
6366
    code = funcInputGetNextRow(pCtx, &row, &result);
228,732,522✔
6367
    if (TSDB_CODE_SUCCESS != code) {
228,803,825!
6368
      return code;
×
6369
    }
6370
    if (!result) {
228,803,825!
6371
      break;
8,699,074✔
6372
    }
6373
    if (row.isDataNull) {
220,104,751!
6374
      continue;
79,506✔
6375
    }
6376
    pInfo->numOfElems++;
220,025,245✔
6377
    switch (pInputCol->info.type) {
220,030,924!
6378
      case TSDB_DATA_TYPE_TINYINT: {
17,877,763✔
6379
        INIT_INTP_POINT(st, row.ts, *(int8_t*)row.pData);
17,877,763✔
6380
        break;
17,877,763✔
6381
      }
6382
      case TSDB_DATA_TYPE_SMALLINT: {
17,813,788✔
6383
        INIT_INTP_POINT(st, row.ts, *(int16_t*)row.pData);
17,813,788✔
6384
        break;
17,813,157✔
6385
      }
6386
      case TSDB_DATA_TYPE_INT: {
83,445,158✔
6387
        INIT_INTP_POINT(st, row.ts, *(int32_t*)row.pData);
83,445,158✔
6388
        break;
83,443,896✔
6389
      }
6390
      case TSDB_DATA_TYPE_BIGINT: {
18,796,340✔
6391
        INIT_INTP_POINT(st, row.ts, *(int64_t*)row.pData);
18,796,340✔
6392
        break;
18,795,709✔
6393
      }
6394
      case TSDB_DATA_TYPE_FLOAT: {
14,846,243✔
6395
        INIT_INTP_POINT(st, row.ts, *(float_t*)row.pData);
14,846,243✔
6396
        break;
14,846,243✔
6397
      }
6398
      case TSDB_DATA_TYPE_DOUBLE: {
17,661,726✔
6399
        INIT_INTP_POINT(st, row.ts, *(double*)row.pData);
17,661,726✔
6400
        break;
17,661,726✔
6401
      }
6402
      case TSDB_DATA_TYPE_UTINYINT: {
12,694,362✔
6403
        INIT_INTP_POINT(st, row.ts, *(uint8_t*)row.pData);
12,694,362✔
6404
        break;
12,694,362✔
6405
      }
6406
      case TSDB_DATA_TYPE_USMALLINT: {
12,687,421✔
6407
        INIT_INTP_POINT(st, row.ts, *(uint16_t*)row.pData);
12,687,421✔
6408
        break;
12,686,790✔
6409
      }
6410
      case TSDB_DATA_TYPE_UINT: {
12,758,724✔
6411
        INIT_INTP_POINT(st, row.ts, *(uint32_t*)row.pData);
12,758,724✔
6412
        break;
12,758,724✔
6413
      }
6414
      case TSDB_DATA_TYPE_UBIGINT: {
11,445,613✔
6415
        INIT_INTP_POINT(st, row.ts, *(uint64_t*)row.pData);
11,445,613✔
6416
        break;
11,444,982✔
6417
      }
6418
      default: {
×
6419
        return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
6420
      }
6421
    }
6422
    if (pInfo->p.key == st.key) {
220,023,352!
6423
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6424
    }
6425

6426
    pInfo->dOutput += twa_get_area(pInfo->p, st);
220,022,721✔
6427
    pInfo->p = st;
219,952,680✔
6428
  }
6429

6430
  // the last interpolated time window value
6431
  if (pCtx->end.key != INT64_MIN) {
8,699,074✔
6432
    pInfo->dOutput += twa_get_area(pInfo->p, pCtx->end);
6,762,642✔
6433
    pInfo->p = pCtx->end;
6,762,642✔
6434
    pInfo->numOfElems += 1;
6,762,642✔
6435
  }
6436

6437
  pInfo->win.ekey = pInfo->p.key;
8,699,074✔
6438

6439
_twa_over:
8,699,074✔
6440
  SET_VAL(pResInfo, 1, 1);
8,699,074✔
6441
  return TSDB_CODE_SUCCESS;
8,699,074✔
6442
}
6443

6444
/*
6445
 * To copy the input to interResBuf to avoid the input buffer space be over writen
6446
 * by next input data. The TWA function only applies to each table, so no merge procedure
6447
 * is required, we simply copy to the resut ot interResBuffer.
6448
 */
6449
// void twa_function_copy(SQLFunctionCtx *pCtx) {
6450
//   SResultRowEntryInfo *pResInfo = GET_RES_INFO(pCtx);
6451
//
6452
//   memcpy(GET_ROWCELL_INTERBUF(pResInfo), pCtx->pInput, (size_t)pCtx->inputBytes);
6453
//   pResInfo->hasResult = ((STwaInfo *)pCtx->pInput)->hasResult;
6454
// }
6455

6456
int32_t twaFinalize(struct SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
8,615,069✔
6457
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
8,615,069✔
6458

6459
  STwaInfo* pInfo = (STwaInfo*)GET_ROWCELL_INTERBUF(pResInfo);
8,615,069✔
6460
  if (pInfo->numOfElems == 0) {
8,615,069✔
6461
    pResInfo->numOfRes = 0;
460,444✔
6462
  } else {
6463
    if (pInfo->win.ekey == pInfo->win.skey) {
8,154,625✔
6464
      pInfo->dTwaRes = pInfo->p.val;
316,179✔
6465
    } else if (pInfo->win.ekey == INT64_MAX || pInfo->win.skey == INT64_MIN) {  // no data in timewindow
7,838,446!
6466
      pInfo->dTwaRes = 0;
1,236✔
6467
    } else {
6468
      pInfo->dTwaRes = pInfo->dOutput / (pInfo->win.ekey - pInfo->win.skey);
7,837,210!
6469
    }
6470

6471
    pResInfo->numOfRes = 1;
8,154,625✔
6472
  }
6473

6474
  return functionFinalize(pCtx, pBlock);
8,615,069✔
6475
}
6476

6477
int32_t blockDistSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
5,214✔
6478
  if (pResultInfo->initialized) {
5,214!
6479
    return TSDB_CODE_SUCCESS;
×
6480
  }
6481
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
5,214!
6482
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6483
  }
6484

6485
  STableBlockDistInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
5,214✔
6486
  pInfo->minRows = INT32_MAX;
5,214✔
6487
  return TSDB_CODE_SUCCESS;
5,214✔
6488
}
6489

6490
int32_t blockDistFunction(SqlFunctionCtx* pCtx) {
9,098✔
6491
  const int32_t BLOCK_DIST_RESULT_ROWS = 25;
9,098✔
6492

6493
  SInputColumnInfoData* pInput = &pCtx->input;
9,098✔
6494
  SColumnInfoData*      pInputCol = pInput->pData[0];
9,098✔
6495
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
9,098✔
6496
  STableBlockDistInfo*  pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
9,098✔
6497

6498
  STableBlockDistInfo p1 = {0};
9,098✔
6499
  if (tDeserializeBlockDistInfo(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
9,098!
6500
    qError("failed to deserialize block dist info");
×
6501
    return TSDB_CODE_FAILED;
×
6502
  }
6503

6504
  pDistInfo->numOfBlocks += p1.numOfBlocks;
9,098✔
6505
  pDistInfo->numOfTables += p1.numOfTables;
9,098✔
6506
  pDistInfo->numOfInmemRows += p1.numOfInmemRows;
9,098✔
6507
  pDistInfo->numOfSttRows += p1.numOfSttRows;
9,098✔
6508
  pDistInfo->totalSize += p1.totalSize;
9,098✔
6509
  pDistInfo->totalRows += p1.totalRows;
9,098✔
6510
  pDistInfo->numOfFiles += p1.numOfFiles;
9,098✔
6511

6512
  pDistInfo->defMinRows = p1.defMinRows;
9,098✔
6513
  pDistInfo->defMaxRows = p1.defMaxRows;
9,098✔
6514
  pDistInfo->rowSize = p1.rowSize;
9,098✔
6515

6516
  if (pDistInfo->minRows > p1.minRows) {
9,098✔
6517
    pDistInfo->minRows = p1.minRows;
1,213✔
6518
  }
6519
  if (pDistInfo->maxRows < p1.maxRows) {
9,098✔
6520
    pDistInfo->maxRows = p1.maxRows;
1,213✔
6521
  }
6522
  pDistInfo->numOfVgroups += (p1.numOfTables != 0 ? 1 : 0);
9,098✔
6523
  for (int32_t i = 0; i < tListLen(pDistInfo->blockRowsHisto); ++i) {
191,058✔
6524
    pDistInfo->blockRowsHisto[i] += p1.blockRowsHisto[i];
181,960✔
6525
  }
6526

6527
  pResInfo->numOfRes = BLOCK_DIST_RESULT_ROWS;  // default output rows
9,098✔
6528
  return TSDB_CODE_SUCCESS;
9,098✔
6529
}
6530

6531
int32_t tSerializeBlockDistInfo(void* buf, int32_t bufLen, const STableBlockDistInfo* pInfo) {
17,684✔
6532
  SEncoder encoder = {0};
17,684✔
6533
  int32_t  code = 0;
18,196✔
6534
  int32_t  lino;
6535
  int32_t  tlen;
6536
  tEncoderInit(&encoder, buf, bufLen);
18,196✔
6537

6538
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
18,196!
6539
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->rowSize));
36,392!
6540

6541
  TAOS_CHECK_EXIT(tEncodeU16(&encoder, pInfo->numOfFiles));
36,392!
6542
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfBlocks));
36,392!
6543
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfTables));
35,880!
6544

6545
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalSize));
35,368!
6546
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->totalRows));
35,368!
6547
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->maxRows));
35,880!
6548
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->minRows));
35,880!
6549
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMaxRows));
35,880!
6550
  TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->defMinRows));
36,392!
6551
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfInmemRows));
36,392!
6552
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfSttRows));
36,392!
6553
  TAOS_CHECK_EXIT(tEncodeU32(&encoder, pInfo->numOfVgroups));
36,392!
6554

6555
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
371,364✔
6556
    TAOS_CHECK_EXIT(tEncodeI32(&encoder, pInfo->blockRowsHisto[i]));
706,336!
6557
  }
6558

6559
  tEndEncode(&encoder);
18,196✔
6560

6561
_exit:
18,196✔
6562
  if (code) {
18,196!
6563
    tlen = code;
×
6564
  } else {
6565
    tlen = encoder.pos;
18,196✔
6566
  }
6567
  tEncoderClear(&encoder);
18,196✔
6568
  return tlen;
18,196✔
6569
}
6570

6571
int32_t tDeserializeBlockDistInfo(void* buf, int32_t bufLen, STableBlockDistInfo* pInfo) {
9,098✔
6572
  SDecoder decoder = {0};
9,098✔
6573
  int32_t  code = 0;
9,098✔
6574
  int32_t  lino;
6575
  tDecoderInit(&decoder, buf, bufLen);
9,098✔
6576

6577
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
9,098!
6578
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->rowSize));
18,196!
6579

6580
  TAOS_CHECK_EXIT(tDecodeU16(&decoder, &pInfo->numOfFiles));
18,196!
6581
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfBlocks));
18,196!
6582
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfTables));
18,196!
6583

6584
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalSize));
18,196!
6585
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->totalRows));
18,196!
6586
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->maxRows));
18,196!
6587
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->minRows));
18,196!
6588
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMaxRows));
18,196!
6589
  TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->defMinRows));
18,196!
6590
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfInmemRows));
18,196!
6591
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfSttRows));
18,196!
6592
  TAOS_CHECK_EXIT(tDecodeU32(&decoder, &pInfo->numOfVgroups));
18,196!
6593

6594
  for (int32_t i = 0; i < tListLen(pInfo->blockRowsHisto); ++i) {
191,058✔
6595
    TAOS_CHECK_EXIT(tDecodeI32(&decoder, &pInfo->blockRowsHisto[i]));
363,920!
6596
  }
6597

6598
_exit:
9,098✔
6599
  tDecoderClear(&decoder);
9,098✔
6600
  return code;
9,098✔
6601
}
6602

6603
int32_t blockDistFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
5,214✔
6604
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
5,214✔
6605
  STableBlockDistInfo* pData = GET_ROWCELL_INTERBUF(pResInfo);
5,214✔
6606

6607
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
5,214✔
6608
  if (NULL == pColInfo) {
5,214!
6609
    return TSDB_CODE_OUT_OF_RANGE;
×
6610
  }
6611

6612
  if (pData->totalRows == 0) {
5,214✔
6613
    pData->minRows = 0;
4,001✔
6614
  }
6615

6616
  int32_t row = 0;
5,214✔
6617
  char    st[256] = {0};
5,214✔
6618
  double  averageSize = 0;
5,214✔
6619
  if (pData->numOfBlocks != 0) {
5,214✔
6620
    averageSize = ((double)pData->totalSize) / pData->numOfBlocks;
1,213!
6621
  }
6622
  uint64_t totalRawSize = pData->totalRows * pData->rowSize;
5,214✔
6623
  double   compRatio = 0;
5,214✔
6624
  if (totalRawSize != 0) {
5,214✔
6625
    compRatio = pData->totalSize * 100 / (double)totalRawSize;
1,213!
6626
  }
6627

6628
  int32_t len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
5,214✔
6629
                          "Total_Blocks=[%d] Total_Size=[%.2f KiB] Average_size=[%.2f KiB] Compression_Ratio=[%.2f %c]",
6630
                          pData->numOfBlocks, pData->totalSize / 1024.0, averageSize / 1024.0, compRatio, '%');
5,214✔
6631

6632
  varDataSetLen(st, len);
5,214✔
6633
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
5,214✔
6634
  if (TSDB_CODE_SUCCESS != code) {
5,214!
6635
    return code;
×
6636
  }
6637

6638
  int64_t avgRows = 0;
5,214✔
6639
  if (pData->numOfBlocks > 0) {
5,214✔
6640
    avgRows = pData->totalRows / pData->numOfBlocks;
1,213!
6641
  }
6642

6643
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
5,214✔
6644
                  "Block_Rows=[%" PRId64 "] MinRows=[%d] MaxRows=[%d] AvgRows=[%" PRId64 "]", pData->totalRows,
6645
                  pData->minRows, pData->maxRows, avgRows);
6646
  varDataSetLen(st, len);
5,214✔
6647
  code = colDataSetVal(pColInfo, row++, st, false);
5,214✔
6648
  if (TSDB_CODE_SUCCESS != code) {
5,214!
6649
    return code;
×
6650
  }
6651

6652
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Inmem_Rows=[%u] Stt_Rows=[%u] ",
5,214✔
6653
                  pData->numOfInmemRows, pData->numOfSttRows);
6654
  varDataSetLen(st, len);
5,214✔
6655
  code = colDataSetVal(pColInfo, row++, st, false);
5,214✔
6656
  if (TSDB_CODE_SUCCESS != code) {
5,214!
6657
    return code;
×
6658
  }
6659

6660
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
10,428✔
6661
                  "Total_Tables=[%d] Total_Filesets=[%d] Total_Vgroups=[%d]", pData->numOfTables, pData->numOfFiles,
5,214✔
6662
                  pData->numOfVgroups);
6663

6664
  varDataSetLen(st, len);
5,214✔
6665
  code = colDataSetVal(pColInfo, row++, st, false);
5,214✔
6666
  if (TSDB_CODE_SUCCESS != code) {
5,214!
6667
    return code;
×
6668
  }
6669

6670
  len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE,
5,214✔
6671
                  "--------------------------------------------------------------------------------");
6672
  varDataSetLen(st, len);
5,214✔
6673
  code = colDataSetVal(pColInfo, row++, st, false);
5,214✔
6674
  if (TSDB_CODE_SUCCESS != code) {
5,214!
6675
    return code;
×
6676
  }
6677

6678
  int32_t maxVal = 0;
5,214✔
6679
  int32_t minVal = INT32_MAX;
5,214✔
6680
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
109,494✔
6681
    if (maxVal < pData->blockRowsHisto[i]) {
104,280✔
6682
      maxVal = pData->blockRowsHisto[i];
1,611✔
6683
    }
6684

6685
    if (minVal > pData->blockRowsHisto[i]) {
104,280✔
6686
      minVal = pData->blockRowsHisto[i];
6,029✔
6687
    }
6688
  }
6689

6690
  // maximum number of step is 80
6691
  double factor = pData->numOfBlocks / 80.0;
5,214✔
6692

6693
  int32_t numOfBuckets = sizeof(pData->blockRowsHisto) / sizeof(pData->blockRowsHisto[0]);
5,214✔
6694
  int32_t bucketRange = ceil(((double)(pData->defMaxRows - pData->defMinRows)) / numOfBuckets);
5,214!
6695

6696
  for (int32_t i = 0; i < tListLen(pData->blockRowsHisto); ++i) {
109,494✔
6697
    len =
104,280✔
6698
        tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "%04d |", pData->defMinRows + bucketRange * (i + 1));
104,280✔
6699

6700
    int32_t num = 0;
104,280✔
6701
    if (pData->blockRowsHisto[i] > 0) {
104,280✔
6702
      num = (pData->blockRowsHisto[i]) / factor;
2,407!
6703
    }
6704

6705
    for (int32_t j = 0; j < num; ++j) {
200,922✔
6706
      int32_t x = tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "%c", '|');
96,642✔
6707
      len += x;
96,642✔
6708
    }
6709

6710
    if (pData->blockRowsHisto[i] > 0) {
104,280✔
6711
      double v = pData->blockRowsHisto[i] * 100.0 / pData->numOfBlocks;
2,407!
6712
      len += tsnprintf(varDataVal(st) + len, sizeof(st) - VARSTR_HEADER_SIZE - len, "  %d (%.2f%c)",
2,407✔
6713
                       pData->blockRowsHisto[i], v, '%');
6714
    }
6715

6716
    varDataSetLen(st, len);
104,280✔
6717
    code = colDataSetVal(pColInfo, row++, st, false);
104,280✔
6718
    if (TSDB_CODE_SUCCESS != code) {
104,280!
6719
      return code;
×
6720
    }
6721
  }
6722

6723
  return TSDB_CODE_SUCCESS;
5,214✔
6724
}
6725
int32_t blockDBUsageSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
1,323✔
6726
  if (pResultInfo->initialized) {
1,323!
6727
    return TSDB_CODE_SUCCESS;
×
6728
  }
6729
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
1,323!
6730
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6731
  }
6732

6733
  SDBBlockUsageInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
1,323✔
6734
  return TSDB_CODE_SUCCESS;
1,323✔
6735
}
6736
int32_t blockDBUsageFunction(SqlFunctionCtx* pCtx) {
2,646✔
6737
  const int32_t BLOCK_DISK_USAGE_RESULT_ROWS = 2;
2,646✔
6738

6739
  SInputColumnInfoData* pInput = &pCtx->input;
2,646✔
6740
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,646✔
6741
  SResultRowEntryInfo*  pResInfo = GET_RES_INFO(pCtx);
2,646✔
6742
  SDBBlockUsageInfo*    pDistInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,646✔
6743

6744
  SDBBlockUsageInfo p1 = {0};
2,646✔
6745
  if (tDeserializeBlockDbUsage(varDataVal(pInputCol->pData), varDataLen(pInputCol->pData), &p1) < 0) {
2,646!
6746
    qError("failed to deserialize block dist info");
×
6747
    return TSDB_CODE_FAILED;
×
6748
  }
6749

6750
  pDistInfo->dataInDiskSize += p1.dataInDiskSize;
2,646✔
6751
  pDistInfo->walInDiskSize += p1.walInDiskSize;
2,646✔
6752
  pDistInfo->rawDataSize += p1.rawDataSize;
2,646✔
6753
  pResInfo->numOfRes = BLOCK_DISK_USAGE_RESULT_ROWS;  // default output rows
2,646✔
6754
  return TSDB_CODE_SUCCESS;
2,646✔
6755
}
6756

6757
int32_t tSerializeBlockDbUsage(void* buf, int32_t bufLen, const SDBBlockUsageInfo* pInfo) {
5,292✔
6758
  SEncoder encoder = {0};
5,292✔
6759
  int32_t  code = 0;
5,292✔
6760
  int32_t  lino;
6761
  int32_t  tlen;
6762
  tEncoderInit(&encoder, buf, bufLen);
5,292✔
6763

6764
  TAOS_CHECK_EXIT(tStartEncode(&encoder));
5,292!
6765

6766
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->dataInDiskSize));
10,584!
6767
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->walInDiskSize));
10,584!
6768
  TAOS_CHECK_EXIT(tEncodeU64(&encoder, pInfo->rawDataSize));
10,584!
6769

6770
  tEndEncode(&encoder);
5,292✔
6771

6772
_exit:
5,292✔
6773
  if (code) {
5,292!
6774
    tlen = code;
×
6775
  } else {
6776
    tlen = encoder.pos;
5,292✔
6777
  }
6778
  tEncoderClear(&encoder);
5,292✔
6779
  return tlen;
5,292✔
6780
}
6781
int32_t tDeserializeBlockDbUsage(void* buf, int32_t bufLen, SDBBlockUsageInfo* pInfo) {
2,646✔
6782
  SDecoder decoder = {0};
2,646✔
6783
  int32_t  code = 0;
2,646✔
6784
  int32_t  lino;
6785
  tDecoderInit(&decoder, buf, bufLen);
2,646✔
6786

6787
  TAOS_CHECK_EXIT(tStartDecode(&decoder));
2,646!
6788
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->dataInDiskSize));
5,292!
6789
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->walInDiskSize));
5,292!
6790
  TAOS_CHECK_EXIT(tDecodeU64(&decoder, &pInfo->rawDataSize));
5,292!
6791

6792
_exit:
2,646✔
6793
  tDecoderClear(&decoder);
2,646✔
6794
  return code;
2,646✔
6795
}
6796
int32_t blockDBUsageFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
1,323✔
6797
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,323✔
6798
  SDBBlockUsageInfo*   pData = GET_ROWCELL_INTERBUF(pResInfo);
1,323✔
6799

6800
  SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, 0);
1,323✔
6801
  if (NULL == pColInfo) {
1,323!
6802
    return TSDB_CODE_OUT_OF_RANGE;
×
6803
  }
6804
  int32_t len = 0;
1,323✔
6805
  int32_t row = 0;
1,323✔
6806
  char    st[256] = {0};
1,323✔
6807

6808
  uint64_t totalDiskSize = pData->dataInDiskSize;
1,323✔
6809
  uint64_t rawDataSize = pData->rawDataSize;
1,323✔
6810
  double   compressRatio = 0;
1,323✔
6811
  if (rawDataSize != 0) {
1,323✔
6812
    compressRatio = totalDiskSize * 100 / (double)rawDataSize;
812!
6813
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[%.2f%]", compressRatio);
812✔
6814
  } else {
6815
    len = tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Compress_ratio=[NULL]");
511✔
6816
  }
6817

6818
  varDataSetLen(st, len);
1,323✔
6819
  int32_t code = colDataSetVal(pColInfo, row++, st, false);
1,323✔
6820
  if (TSDB_CODE_SUCCESS != code) {
1,323!
6821
    return code;
×
6822
  }
6823

6824
  len =
1,323✔
6825
      tsnprintf(varDataVal(st), sizeof(st) - VARSTR_HEADER_SIZE, "Disk_occupied=[%" PRId64 "k]", pData->dataInDiskSize);
1,323✔
6826
  varDataSetLen(st, len);
1,323✔
6827
  code = colDataSetVal(pColInfo, row++, st, false);
1,323✔
6828
  if (TSDB_CODE_SUCCESS != code) {
1,323!
6829
    return code;
×
6830
  }
6831
  return code;
1,323✔
6832
}
6833

6834
bool getDerivativeFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
49,807✔
6835
  pEnv->calcMemSize = sizeof(SDerivInfo);
49,807✔
6836
  return true;
49,807✔
6837
}
6838

6839
int32_t derivativeFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
127,011✔
6840
  if (pResInfo->initialized) {
127,011✔
6841
    return TSDB_CODE_SUCCESS;
67,796✔
6842
  }
6843
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
59,215!
6844
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
6845
  }
6846

6847
  SDerivInfo* pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
59,215✔
6848

6849
  pDerivInfo->ignoreNegative = pCtx->param[2].param.i;
59,215✔
6850
  pDerivInfo->prevTs = -1;
59,215✔
6851
  pDerivInfo->tsWindow = pCtx->param[1].param.i;
59,215✔
6852
  pDerivInfo->valueSet = false;
59,215✔
6853
  return TSDB_CODE_SUCCESS;
59,215✔
6854
}
6855

6856
int32_t derivativeFunction(SqlFunctionCtx* pCtx) {
77,204✔
6857
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
77,204✔
6858
  SDerivInfo*          pDerivInfo = GET_ROWCELL_INTERBUF(pResInfo);
77,204✔
6859

6860
  SInputColumnInfoData* pInput = &pCtx->input;
77,204✔
6861
  SColumnInfoData*      pInputCol = pInput->pData[0];
77,204✔
6862

6863
  int32_t          numOfElems = 0;
77,204✔
6864
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
77,204✔
6865
  SColumnInfoData* pTsOutput = pCtx->pTsOutput;
77,204✔
6866
  int32_t          code = TSDB_CODE_SUCCESS;
77,204✔
6867

6868
  funcInputUpdate(pCtx);
77,204✔
6869

6870
  double v = 0;
77,204✔
6871
  if (pCtx->order == TSDB_ORDER_ASC) {
77,204✔
6872
    SFuncInputRow row = {0};
74,394✔
6873
    bool          result = false;
74,394✔
6874
    while (1) {
31,894,915✔
6875
      code = funcInputGetNextRow(pCtx, &row, &result);
31,969,309✔
6876
      if (TSDB_CODE_SUCCESS != code) {
31,969,309!
6877
        return code;
×
6878
      }
6879
      if (!result) {
31,969,309!
6880
        break;
74,394✔
6881
      }
6882
      if (row.isDataNull) {
31,894,915!
6883
        continue;
1,727,156✔
6884
      }
6885

6886
      char* d = row.pData;
30,167,759✔
6887
      GET_TYPED_DATA(v, double, pInputCol->info.type, d, typeGetTypeModFromColInfo(&pInputCol->info));
30,167,759!
6888

6889
      int32_t pos = pCtx->offset + numOfElems;
30,167,759✔
6890
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
30,167,759!
6891
        pDerivInfo->valueSet = true;
39,028✔
6892
      } else {
6893
        if (row.ts == pDerivInfo->prevTs) {
30,128,731!
6894
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6895
        }
6896
        double r = ((v - pDerivInfo->prevValue) * pDerivInfo->tsWindow) / (row.ts - pDerivInfo->prevTs);
30,128,731!
6897
        if (pDerivInfo->ignoreNegative && r < 0) {
30,128,731!
6898
        } else {
6899
          if (isinf(r) || isnan(r)) {
21,973,738!
6900
            colDataSetNULL(pOutput, pos);
×
6901
          } else {
6902
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
21,973,738✔
6903
            if (code != TSDB_CODE_SUCCESS) {
21,973,738!
6904
              return code;
×
6905
            }
6906
          }
6907

6908
          if (pTsOutput != NULL) {
21,973,738!
6909
            colDataSetInt64(pTsOutput, pos, &row.ts);
×
6910
          }
6911

6912
          // handle selectivity
6913
          if (pCtx->subsidiaries.num > 0) {
21,973,738✔
6914
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
27,878✔
6915
            if (code != TSDB_CODE_SUCCESS) {
27,878!
6916
              return code;
×
6917
            }
6918
          }
6919

6920
          numOfElems++;
21,973,738✔
6921
        }
6922
      }
6923

6924
      pDerivInfo->prevValue = v;
30,167,759✔
6925
      pDerivInfo->prevTs = row.ts;
30,167,759✔
6926
    }
6927
  } else {
6928
    SFuncInputRow row = {0};
2,810✔
6929
    bool          result = false;
2,810✔
6930
    while (1) {
5,620✔
6931
      code = funcInputGetNextRow(pCtx, &row, &result);
8,430✔
6932
      if (TSDB_CODE_SUCCESS != code) {
8,430!
6933
        return code;
×
6934
      }
6935
      if (!result) {
8,430!
6936
        break;
2,810✔
6937
      }
6938
      if (row.isDataNull) {
5,620!
6939
        continue;
3,372✔
6940
      }
6941

6942
      char* d = row.pData;
2,248✔
6943
      GET_TYPED_DATA(v, double, pInputCol->info.type, d, typeGetTypeModFromColInfo(&pInputCol->info));
2,248!
6944

6945
      int32_t pos = pCtx->offset + numOfElems;
2,248✔
6946
      if (!pDerivInfo->valueSet) {  // initial value is not set yet
2,248!
6947
        pDerivInfo->valueSet = true;
1,124✔
6948
      } else {
6949
        if (row.ts == pDerivInfo->prevTs) {
1,124!
6950
          return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
6951
        }
6952
        double r = ((pDerivInfo->prevValue - v) * pDerivInfo->tsWindow) / (pDerivInfo->prevTs - row.ts);
1,124!
6953
        if (pDerivInfo->ignoreNegative && r < 0) {
1,124!
6954
        } else {
6955
          if (isinf(r) || isnan(r)) {
562!
6956
            colDataSetNULL(pOutput, pos);
×
6957
          } else {
6958
            code = colDataSetVal(pOutput, pos, (const char*)&r, false);
562✔
6959
            if (code != TSDB_CODE_SUCCESS) {
562!
6960
              return code;
×
6961
            }
6962
          }
6963

6964
          if (pTsOutput != NULL) {
562!
6965
            colDataSetInt64(pTsOutput, pos, &pDerivInfo->prevTs);
×
6966
          }
6967

6968
          // handle selectivity
6969
          if (pCtx->subsidiaries.num > 0) {
562!
6970
            code = appendSelectivityCols(pCtx, row.block, row.rowIndex, pos);
×
6971
            if (code != TSDB_CODE_SUCCESS) {
×
6972
              return code;
×
6973
            }
6974
          }
6975
          numOfElems++;
562✔
6976
        }
6977
      }
6978

6979
      pDerivInfo->prevValue = v;
2,248✔
6980
      pDerivInfo->prevTs = row.ts;
2,248✔
6981
    }
6982
  }
6983

6984
  pResInfo->numOfRes = numOfElems;
77,204✔
6985

6986
  return TSDB_CODE_SUCCESS;
77,204✔
6987
}
6988

6989
int32_t getIrateInfoSize(int32_t pkBytes) { return (int32_t)sizeof(SRateInfo) + 2 * pkBytes; }
201,048✔
6990

6991
bool getIrateFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
152,938✔
6992
  int32_t pkBytes = (pFunc->hasPk) ? pFunc->pkBytes : 0;
152,938!
6993
  pEnv->calcMemSize = getIrateInfoSize(pkBytes);
152,938✔
6994
  return true;
152,938✔
6995
}
6996

6997
int32_t irateFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
954,984✔
6998
  if (pResInfo->initialized) {
954,984!
6999
    return TSDB_CODE_SUCCESS;
×
7000
  }
7001
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResInfo)) {
954,984!
7002
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7003
  }
7004

7005
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
954,984✔
7006

7007
  pInfo->firstKey = INT64_MIN;
954,984✔
7008
  pInfo->lastKey = INT64_MIN;
954,984✔
7009
  pInfo->firstValue = (double)INT64_MIN;
954,984✔
7010
  pInfo->lastValue = (double)INT64_MIN;
954,984✔
7011

7012
  pInfo->hasResult = 0;
954,984✔
7013
  return TSDB_CODE_SUCCESS;
954,984✔
7014
}
7015

7016
static void doSaveRateInfo(SRateInfo* pRateInfo, bool isFirst, int64_t ts, char* pk, double v) {
135,850,702✔
7017
  if (isFirst) {
135,850,702✔
7018
    pRateInfo->firstValue = v;
67,678,877✔
7019
    pRateInfo->firstKey = ts;
67,678,877✔
7020
    if (pRateInfo->firstPk) {
67,678,877✔
7021
      int32_t pkBytes;
7022
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
10,885!
7023
        pkBytes = calcStrBytesByType(pRateInfo->pkType, pk);
2,488✔
7024
      } else {
7025
        pkBytes = pRateInfo->pkBytes;
8,397✔
7026
      }
7027
      (void)memcpy(pRateInfo->firstPk, pk, pkBytes);
10,885!
7028
    }
7029
  } else {
7030
    pRateInfo->lastValue = v;
68,171,825✔
7031
    pRateInfo->lastKey = ts;
68,171,825✔
7032
    if (pRateInfo->lastPk) {
68,171,825✔
7033
      int32_t pkBytes;
7034
      if (IS_VAR_DATA_TYPE(pRateInfo->pkType)) {
16,172!
7035
        pkBytes = calcStrBytesByType(pRateInfo->pkType, pk);
3,732✔
7036
      } else {
7037
        pkBytes = pRateInfo->pkBytes;
12,440✔
7038
      }
7039
      (void)memcpy(pRateInfo->lastPk, pk, pkBytes);
16,172!
7040
    }
7041
  }
7042
}
135,850,702✔
7043

7044
static void initializeRateInfo(SqlFunctionCtx* pCtx, SRateInfo* pRateInfo, bool isMerge) {
1,104,061✔
7045
  if (pCtx->hasPrimaryKey) {
1,104,061!
7046
    if (!isMerge) {
5,909✔
7047
      pRateInfo->pkType = pCtx->input.pPrimaryKey->info.type;
5,287✔
7048
      pRateInfo->pkBytes = pCtx->input.pPrimaryKey->info.bytes;
5,287✔
7049
      pRateInfo->firstPk = pRateInfo->pkData;
5,287✔
7050
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
5,287✔
7051
    } else {
7052
      pRateInfo->firstPk = pRateInfo->pkData;
622✔
7053
      pRateInfo->lastPk = pRateInfo->pkData + pRateInfo->pkBytes;
622✔
7054
    }
7055
  } else {
7056
    pRateInfo->firstPk = NULL;
1,098,152✔
7057
    pRateInfo->lastPk = NULL;
1,098,152✔
7058
  }
7059
}
1,104,061✔
7060

7061
int32_t irateFunction(SqlFunctionCtx* pCtx) {
1,036,115✔
7062
  int32_t              code = TSDB_CODE_SUCCESS;
1,036,115✔
7063
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
1,036,115✔
7064
  SRateInfo*           pRateInfo = GET_ROWCELL_INTERBUF(pResInfo);
1,036,115✔
7065

7066
  SInputColumnInfoData* pInput = &pCtx->input;
1,036,115✔
7067
  SColumnInfoData*      pInputCol = pInput->pData[0];
1,036,115✔
7068

7069
  SColumnInfoData* pOutput = (SColumnInfoData*)pCtx->pOutput;
1,036,115✔
7070

7071
  funcInputUpdate(pCtx);
1,036,115✔
7072

7073
  initializeRateInfo(pCtx, pRateInfo, false);
1,036,115✔
7074

7075
  int32_t       numOfElems = 0;
1,036,115✔
7076
  int32_t       type = pInputCol->info.type;
1,036,115✔
7077
  SFuncInputRow row = {0};
1,036,115✔
7078
  bool          result = false;
1,036,115✔
7079
  while (1) {
72,937,849✔
7080
    code = funcInputGetNextRow(pCtx, &row, &result);
73,973,964✔
7081
    if (TSDB_CODE_SUCCESS != code) {
73,973,964!
7082
      return code;
×
7083
    }
7084
    if (!result) {
73,973,964!
7085
      break;
1,036,115✔
7086
    }
7087
    if (row.isDataNull) {
72,937,849!
7088
      continue;
4,571,773✔
7089
    }
7090

7091
    char*  data = row.pData;
68,366,076✔
7092
    double v = 0;
68,366,076✔
7093
    GET_TYPED_DATA(v, double, type, data, typeGetTypeModFromColInfo(&pInputCol->info));
68,366,076!
7094

7095
    if (INT64_MIN == pRateInfo->lastKey) {
68,366,076✔
7096
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
498,268✔
7097
      pRateInfo->hasResult = 1;
498,268✔
7098
      continue;
498,268✔
7099
    }
7100

7101
    if (row.ts > pRateInfo->lastKey) {
67,867,808✔
7102
      if ((INT64_MIN == pRateInfo->firstKey) || pRateInfo->lastKey > pRateInfo->firstKey) {
67,639,242!
7103
        doSaveRateInfo(pRateInfo, true, pRateInfo->lastKey, pRateInfo->lastPk, pRateInfo->lastValue);
67,639,242✔
7104
      }
7105
      doSaveRateInfo(pRateInfo, false, row.ts, row.pPk, v);
67,639,242✔
7106
      continue;
67,639,242✔
7107
    } else if (row.ts == pRateInfo->lastKey) {
228,566!
7108
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7109
    }
7110

7111
    if ((INT64_MIN == pRateInfo->firstKey) || row.ts > pRateInfo->firstKey) {
228,566!
7112
      doSaveRateInfo(pRateInfo, true, row.ts, row.pPk, v);
1,534✔
7113
    } else if (row.ts == pRateInfo->firstKey) {
227,032!
7114
      return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7115
    }
7116
  }
7117

7118
  numOfElems++;
1,036,115✔
7119

7120
  SET_VAL(pResInfo, numOfElems, 1);
1,036,115!
7121
  return TSDB_CODE_SUCCESS;
1,036,115✔
7122
}
7123

7124
static double doCalcRate(const SRateInfo* pRateInfo, double tickPerSec) {
921,011✔
7125
  if ((INT64_MIN == pRateInfo->lastKey) || (INT64_MIN == pRateInfo->firstKey) ||
921,011✔
7126
      (pRateInfo->firstKey >= pRateInfo->lastKey)) {
103,712!
7127
    return 0.0;
817,299✔
7128
  }
7129

7130
  double diff = 0;
103,712✔
7131
  // If the previous value of the last is greater than the last value, only keep the last point instead of the delta
7132
  // value between two values.
7133
  diff = pRateInfo->lastValue;
103,712✔
7134
  if (diff >= pRateInfo->firstValue) {
103,712✔
7135
    diff -= pRateInfo->firstValue;
73,510✔
7136
  }
7137

7138
  int64_t duration = pRateInfo->lastKey - pRateInfo->firstKey;
103,712✔
7139
  if (duration == 0) {
103,712!
7140
    return 0;
×
7141
  }
7142

7143
  return (duration > 0) ? ((double)diff) / (duration / tickPerSec) : 0.0;
103,712!
7144
}
7145

7146
static void irateTransferInfoImpl(TSKEY inputKey, SRateInfo* pInput, SRateInfo* pOutput, bool isFirstKey) {
29,158✔
7147
  if (inputKey > pOutput->lastKey) {
29,158✔
7148
    doSaveRateInfo(pOutput, true, pOutput->lastKey, pOutput->lastPk, pOutput->lastValue);
15,907✔
7149
    if (isFirstKey) {
15,907✔
7150
      doSaveRateInfo(pOutput, false, pInput->firstKey, pInput->firstPk, pInput->firstValue);
7,007✔
7151
    } else {
7152
      doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
8,900✔
7153
    }
7154
  } else if ((inputKey < pOutput->lastKey) && (inputKey > pOutput->firstKey)) {
13,251!
7155
    if (isFirstKey) {
3,786✔
7156
      doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
1,893✔
7157
    } else {
7158
      doSaveRateInfo(pOutput, true, pInput->lastKey, pInput->lastPk, pInput->lastValue);
1,893✔
7159
    }
7160
  } else {
7161
    // inputKey < pOutput->firstKey
7162
  }
7163
}
29,158✔
7164

7165
static void irateCopyInfo(SRateInfo* pInput, SRateInfo* pOutput) {
18,408✔
7166
  doSaveRateInfo(pOutput, true, pInput->firstKey, pInput->firstPk, pInput->firstValue);
18,408✔
7167
  doSaveRateInfo(pOutput, false, pInput->lastKey, pInput->lastPk, pInput->lastValue);
18,408✔
7168
}
18,408✔
7169

7170
static int32_t irateTransferInfo(SRateInfo* pInput, SRateInfo* pOutput) {
32,987✔
7171
  if ((pInput->firstKey != INT64_MIN &&
32,987✔
7172
       (pInput->firstKey == pOutput->firstKey || pInput->firstKey == pOutput->lastKey)) ||
29,469!
7173
      (pInput->lastKey != INT64_MIN && (pInput->lastKey == pOutput->firstKey || pInput->lastKey == pOutput->lastKey))) {
32,987!
7174
    return TSDB_CODE_FUNC_DUP_TIMESTAMP;
×
7175
  }
7176

7177
  if (pOutput->hasResult == 0) {
32,987✔
7178
    irateCopyInfo(pInput, pOutput);
18,408✔
7179
    pOutput->hasResult = pInput->hasResult;
18,408✔
7180
    return TSDB_CODE_SUCCESS;
18,408✔
7181
  }
7182

7183
  if (pInput->firstKey != INT64_MIN) {
14,579!
7184
    irateTransferInfoImpl(pInput->firstKey, pInput, pOutput, true);
14,579✔
7185
  }
7186

7187
  if (pInput->lastKey != INT64_MIN) {
14,579!
7188
    irateTransferInfoImpl(pInput->lastKey, pInput, pOutput, false);
14,579✔
7189
  }
7190

7191
  pOutput->hasResult = pInput->hasResult;
14,579✔
7192
  return TSDB_CODE_SUCCESS;
14,579✔
7193
}
7194

7195
int32_t irateFunctionMerge(SqlFunctionCtx* pCtx) {
33,973✔
7196
  SInputColumnInfoData* pInput = &pCtx->input;
33,973✔
7197
  SColumnInfoData*      pCol = pInput->pData[0];
33,973✔
7198
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
33,973!
7199
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
7200
  }
7201

7202
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
33,973✔
7203
  initializeRateInfo(pCtx, pInfo, true);
33,973✔
7204

7205
  int32_t start = pInput->startRowIndex;
33,973✔
7206
  for (int32_t i = start; i < start + pInput->numOfRows; ++i) {
67,946✔
7207
    char*      data = colDataGetData(pCol, i);
33,973!
7208
    SRateInfo* pInputInfo = (SRateInfo*)varDataVal(data);
33,973✔
7209
    initializeRateInfo(pCtx, pInfo, true);
33,973✔
7210
    if (pInputInfo->hasResult) {
33,973✔
7211
      int32_t code = irateTransferInfo(pInputInfo, pInfo);
32,987✔
7212
      if (code != TSDB_CODE_SUCCESS) {
32,987!
7213
        return code;
×
7214
      }
7215
    }
7216
  }
7217

7218
  if (pInfo->hasResult) {
33,973✔
7219
    GET_RES_INFO(pCtx)->numOfRes = 1;
32,987✔
7220
  }
7221

7222
  return TSDB_CODE_SUCCESS;
33,973✔
7223
}
7224

7225
int32_t iratePartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
33,973✔
7226
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
33,973✔
7227
  SRateInfo*           pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
33,973✔
7228
  int32_t              resultBytes = getIrateInfoSize(pInfo->pkBytes);
33,973✔
7229
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
33,973!
7230

7231
  if (NULL == res) {
33,973!
7232
    return terrno;
×
7233
  }
7234
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
33,973!
7235
  varDataSetLen(res, resultBytes);
33,973✔
7236

7237
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
33,973✔
7238
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
33,973✔
7239
  if (NULL == pCol) {
33,973!
7240
    taosMemoryFree(res);
×
7241
    return TSDB_CODE_OUT_OF_RANGE;
×
7242
  }
7243

7244
  int32_t code = colDataSetVal(pCol, pBlock->info.rows, res, false);
33,973✔
7245

7246
  taosMemoryFree(res);
33,973!
7247
  return code;
33,973✔
7248
}
7249

7250
int32_t irateFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
921,011✔
7251
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
921,011✔
7252
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
921,011✔
7253
  if (NULL == pCol) {
921,011!
7254
    return TSDB_CODE_OUT_OF_RANGE;
×
7255
  }
7256

7257
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
921,011✔
7258
  pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
921,011✔
7259

7260
  SRateInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
921,011✔
7261
  double     result = doCalcRate(pInfo, (double)TSDB_TICK_PER_SECOND(pCtx->param[1].param.i));
921,011!
7262
  int32_t    code = colDataSetVal(pCol, pBlock->info.rows, (const char*)&result, pResInfo->isNullRes);
921,011✔
7263

7264
  return code;
921,011✔
7265
}
7266

7267
int32_t groupConstValueFunction(SqlFunctionCtx* pCtx) {
2,147,483,647✔
7268
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
7269
  SGroupKeyInfo*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
7270

7271
  SInputColumnInfoData* pInput = &pCtx->input;
2,147,483,647✔
7272
  SColumnInfoData*      pInputCol = pInput->pData[0];
2,147,483,647✔
7273

7274
  int32_t startIndex = pInput->startRowIndex;
2,147,483,647✔
7275

7276
  // escape rest of data blocks to avoid first entry to be overwritten.
7277
  if (pInfo->hasResult) {
2,147,483,647!
7278
    goto _group_value_over;
1,711,613,205✔
7279
  }
7280

7281
  if (pInputCol->pData == NULL || colDataIsNull_s(pInputCol, startIndex)) {
2,147,483,647!
7282
    pInfo->isNull = true;
160,072,025✔
7283
    pInfo->hasResult = true;
160,247,138✔
7284
    goto _group_value_over;
158,932,602✔
7285
  }
7286

7287
  char* data = colDataGetData(pInputCol, startIndex);
2,147,483,647!
7288
  if (IS_VAR_DATA_TYPE(pInputCol->info.type)) {
2,147,483,647!
7289
    int32_t bytes = calcStrBytesByType(pInputCol->info.type, data);
2,147,483,647✔
7290
    (void)memcpy(pInfo->data, data, bytes);
2,147,483,647!
7291
  } else {
7292
    (void)memcpy(pInfo->data, data, pInputCol->info.bytes);
1,659,297,943!
7293
  }
7294
  pInfo->hasResult = true;
2,147,483,647✔
7295

7296
_group_value_over:
2,147,483,647✔
7297

7298
  SET_VAL(pResInfo, 1, 1);
2,147,483,647✔
7299
  return TSDB_CODE_SUCCESS;
2,147,483,647✔
7300
}
7301

7302
int32_t groupKeyFunction(SqlFunctionCtx* pCtx) { return groupConstValueFunction(pCtx); }
2,147,483,647✔
7303

7304
int32_t groupConstValueFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
2,147,483,647✔
7305
  int32_t          slotId = pCtx->pExpr->base.resSchema.slotId;
2,147,483,647✔
7306
  int32_t          code = TSDB_CODE_SUCCESS;
2,147,483,647✔
7307
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
2,147,483,647✔
7308
  if (NULL == pCol) {
2,147,483,647!
7309
    return TSDB_CODE_OUT_OF_RANGE;
×
7310
  }
7311

7312
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
2,147,483,647✔
7313

7314
  SGroupKeyInfo* pInfo = GET_ROWCELL_INTERBUF(pResInfo);
2,147,483,647✔
7315

7316
  if (pInfo->hasResult) {
2,147,483,647!
7317
    int32_t currentRow = pBlock->info.rows;
2,147,483,647✔
7318
    for (; currentRow < pBlock->info.rows + pResInfo->numOfRes; ++currentRow) {
2,147,483,647✔
7319
      code = colDataSetVal(pCol, currentRow, pInfo->data, pInfo->isNull ? true : false);
2,147,483,647!
7320
      if (TSDB_CODE_SUCCESS != code) {
2,147,483,647!
7321
        return code;
×
7322
      }
7323
    }
7324
  } else {
7325
    pResInfo->numOfRes = 0;
×
7326
  }
7327

7328
  return code;
2,147,483,647✔
7329
}
7330

7331
int32_t groupKeyFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) { return groupConstValueFinalize(pCtx, pBlock); }
2,147,483,647✔
7332

7333
int32_t groupKeyCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
×
7334
  SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
×
7335
  SGroupKeyInfo*       pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
×
7336

7337
  SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
×
7338
  SGroupKeyInfo*       pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
×
7339

7340
  // escape rest of data blocks to avoid first entry to be overwritten.
7341
  if (pDBuf->hasResult) {
×
7342
    goto _group_key_over;
×
7343
  }
7344

7345
  if (pSBuf->isNull) {
×
7346
    pDBuf->isNull = true;
×
7347
    pDBuf->hasResult = true;
×
7348
    goto _group_key_over;
×
7349
  }
7350

7351
  if (IS_VAR_DATA_TYPE(pSourceCtx->resDataInfo.type)) {
×
7352
    int32_t bytes = calcStrBytesByType(pSourceCtx->resDataInfo.type, pSBuf->data);
×
7353
    (void)memcpy(pDBuf->data, pSBuf->data, bytes);
×
7354
  } else {
7355
    (void)memcpy(pDBuf->data, pSBuf->data, pSourceCtx->resDataInfo.bytes);
×
7356
  }
7357

7358
  pDBuf->hasResult = true;
×
7359

7360
_group_key_over:
×
7361

7362
  SET_VAL(pDResInfo, 1, 1);
×
7363
  return TSDB_CODE_SUCCESS;
×
7364
}
7365

7366
int32_t cachedLastRowFunction(SqlFunctionCtx* pCtx) {
598,114✔
7367
  int32_t numOfElems = 0;
598,114✔
7368

7369
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
598,114✔
7370
  SFirstLastRes*       pInfo = GET_ROWCELL_INTERBUF(pResInfo);
597,480✔
7371

7372
  SInputColumnInfoData* pInput = &pCtx->input;
598,114✔
7373
  SColumnInfoData*      pInputCol = pInput->pData[0];
598,114✔
7374

7375
  int32_t bytes = pInputCol->info.bytes;
598,114✔
7376
  pInfo->bytes = bytes;
596,846✔
7377

7378
  SColumnInfoData* pkCol = pInput->pPrimaryKey;
597,480✔
7379
  pInfo->pkType = -1;
598,114✔
7380
  __compar_fn_t pkCompareFn = NULL;
598,114✔
7381
  if (pCtx->hasPrimaryKey) {
598,114!
7382
    pInfo->pkType = pkCol->info.type;
22,878✔
7383
    pInfo->pkBytes = pkCol->info.bytes;
22,878✔
7384
    pkCompareFn = getKeyComparFunc(pInfo->pkType, TSDB_ORDER_DESC);
22,878✔
7385
  }
7386

7387
  // data is guaranteed to be in descending order
7388
  for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) {
1,279,694✔
7389
    numOfElems++;
682,848✔
7390

7391
    bool  isNull = colDataIsNull(pInputCol, pInput->numOfRows, i, NULL);
682,848!
7392
    char* data = isNull ? NULL : colDataGetData(pInputCol, i);
682,848!
7393

7394
    TSKEY cts = getRowPTs(pInput->pPTS, i);
682,848!
7395
    if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
681,580✔
7396
      int32_t code = doSaveLastrow(pCtx, data, i, cts, pInfo);
549,524✔
7397
      if (code != TSDB_CODE_SUCCESS) {
550,158!
7398
        return code;
×
7399
      }
7400
      pResInfo->numOfRes = 1;
550,158✔
7401
    }
7402
  }
7403

7404
  SET_VAL(pResInfo, numOfElems, 1);
598,114!
7405
  return TSDB_CODE_SUCCESS;
597,480✔
7406
}
7407

7408
bool getCorrFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
×
7409
  pEnv->calcMemSize = sizeof(SCorrRes);
×
7410
  return true;
×
7411
}
7412

7413
int32_t corrFuncSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) {
×
7414
  if (pResultInfo->initialized) {
×
7415
    return TSDB_CODE_SUCCESS;
×
7416
  }
7417
  if (TSDB_CODE_SUCCESS != functionSetup(pCtx, pResultInfo)) {
×
7418
    return TSDB_CODE_FUNC_SETUP_ERROR;
×
7419
  }
7420

7421
  SCorrRes* pRes = GET_ROWCELL_INTERBUF(pResultInfo);
×
7422
  (void)memset(pRes, 0, sizeof(SCorrRes));
×
7423
  return TSDB_CODE_SUCCESS;
×
7424
}
7425

7426
int32_t corrFunction(SqlFunctionCtx* pCtx) {
×
7427
  int32_t               numOfElem = 0;
×
7428
  SInputColumnInfoData* pInput = &pCtx->input;
×
7429
  int32_t               xType = pInput->pData[0]->info.type;
×
7430
  int32_t               yType = pInput->pData[1]->info.type;
×
7431
  SCorrRes*             pCorrRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
7432

7433
  // computing based on the true data block
7434
  SColumnInfoData* pLeft = pInput->pData[0];  // left
×
7435
  SColumnInfoData* pRight = pInput->pData[1]; // right
×
7436

7437
  int32_t leftMod = typeGetTypeModFromColInfo(&pLeft->info);
×
7438
  int32_t rightMod = typeGetTypeModFromColInfo(&pRight->info);
×
7439
  int32_t start = pInput->startRowIndex;
×
7440
  int32_t numOfRows = pInput->numOfRows;
×
7441

7442
  if (IS_NULL_TYPE(xType) || IS_NULL_TYPE(yType)) {
×
7443
    numOfElem = 0;
×
7444
    goto _over;
×
7445
  }
7446
  
7447
  for(int32_t i = 0; i < numOfRows; ++i) {
×
7448
    double pInputX = 0, pInputY = 0;
×
7449

7450
    if (colDataIsNull_f(pLeft, i) || colDataIsNull_f(pRight, i)) {
×
7451
      continue;
×
7452
    }
7453

7454
    char*  pXVal = colDataGetData(pLeft, i);
×
7455
    char*  pYVal = colDataGetData(pRight, i);
×
7456

7457
    GET_TYPED_DATA(pInputX, double, xType, pXVal, leftMod);
×
7458
    GET_TYPED_DATA(pInputY, double, yType, pYVal, rightMod);
×
7459

7460
    pCorrRes->sumLeft += pInputX;
×
7461
    pCorrRes->sumRight += pInputY;
×
7462

7463
    pCorrRes->quadLeft += pInputX * pInputX;
×
7464
    pCorrRes->quadRight += pInputY * pInputY;
×
7465

7466
    pCorrRes->productVal += pInputX * pInputY;
×
7467

7468
    pCorrRes->count += 1;
×
7469
    numOfElem += 1;
×
7470
  }
7471

7472
_over:
×
7473
  // data in the check operation are all null, not output
7474
  SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
×
7475
  return TSDB_CODE_SUCCESS;
×
7476
}
7477

7478
int32_t corrFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
7479
  SInputColumnInfoData* pInput = &pCtx->input;
×
7480
  SCorrRes*             pRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
7481
  double                avg;
7482

7483
  if (pRes->count == 0) {
×
7484
    GET_RES_INFO(pCtx)->numOfRes = 0;
×
7485
    return functionFinalize(pCtx, pBlock);
×
7486
  }
7487

7488
  /**
7489
    numerator = sum_xy - (sum_x * sum_y) / n
7490
    denominator_x = math.sqrt(sum_x2 - (sum_x**2) / n)
7491
    denominator_y = math.sqrt(sum_y2 - (sum_y**2) / n)
7492
    
7493
    if denominator_x == 0 or denominator_y == 0:
7494
        return 0.0
7495
    res = numerator / (denominator_x * denominator_y)
7496
  */
7497

7498
  if (pRes->count == 1) {
×
7499
    pRes->result = 0.0;
×
7500
  } else {
7501
    double numerator = pRes->productVal - (pRes->sumLeft * pRes->sumRight) / pRes->count;
×
7502
    double dnmX = sqrt(pRes->quadLeft - pRes->sumLeft * pRes->sumLeft/pRes->count);
×
7503
    double dnmY = sqrt(pRes->quadRight - pRes->sumRight * pRes->sumRight/pRes->count);  
×
7504

7505
    if (DBL_EQUAL(dnmX, 0.0) || DBL_EQUAL(dnmY, 0.0)) {
×
7506
      pRes->result = 0.0;
×
7507
    } else {
7508
      pRes->result = numerator / (dnmX * dnmY);
×
7509

7510
      if (pRes->result > 1 || pRes->result < -1) {
×
7511
        qError("invalid corr results, %.4f, numerator:%.4f, dnmX:%.4f, dnmY:%.4f", pRes->result, numerator, dnmX, dnmY);
×
7512
        if (pRes->result > 1) {
×
7513
          pRes->result = 1;
×
7514
        } else if (pRes->result < -1) {
×
7515
          pRes->result = -1;
×
7516
        }
7517
      }
7518
    }
7519
  }
7520

7521
  return functionFinalize(pCtx, pBlock);
×
7522
}
7523

7524
int32_t getCorrInfoSize() {return sizeof(SCorrRes);}
×
7525

7526
int32_t corrPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
×
7527
  SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
×
7528
  SStdRes*             pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
7529
  int32_t              resultBytes = getCorrInfoSize();
×
7530
  char*                res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
×
7531
  int32_t              slotId = pCtx->pExpr->base.resSchema.slotId;
×
7532
  int32_t              code = 0;
×
7533

7534
  if (NULL == res) {
×
7535
    return terrno;
×
7536
  }
7537
  
7538
  (void)memcpy(varDataVal(res), pInfo, resultBytes);
×
7539
  varDataSetLen(res, resultBytes);
×
7540

7541
  SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
×
7542
  if (NULL == pCol) {
×
7543
    taosMemoryFree(res);
×
7544
    return TSDB_CODE_OUT_OF_RANGE;
×
7545
  }
7546

7547
  code = colDataSetVal(pCol, pBlock->info.rows, res, false);
×
7548

7549
  taosMemoryFree(res);
×
7550
  return code;
×
7551
}
7552

7553
int32_t corrFuncMerge(SqlFunctionCtx* pCtx) {
×
7554
  SInputColumnInfoData* pInput = &pCtx->input;
×
7555
  SColumnInfoData*      pCol = pInput->pData[0];
×
7556

7557
  if (IS_NULL_TYPE(pCol->info.type)) {
×
7558
    SET_VAL(GET_RES_INFO(pCtx), 0, 1);
×
7559
    return TSDB_CODE_SUCCESS;
×
7560
  }
7561

7562
  if (pCol->info.type != TSDB_DATA_TYPE_BINARY) {
×
7563
    return TSDB_CODE_FUNC_FUNTION_PARA_TYPE;
×
7564
  }
7565

7566
  SCorrRes* pInfo = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
×
7567

7568
  for (int32_t i = pInput->startRowIndex; i < pInput->startRowIndex + pInput->numOfRows; ++i) {
×
7569
    if (colDataIsNull_s(pCol, i)) {
×
7570
      continue;
×
7571
    }
7572

7573
    char*     data = colDataGetData(pCol, i);
×
7574
    SCorrRes* pInputInfo = (SCorrRes*)varDataVal(data);
×
7575

7576
    if (pInputInfo->count == 0) {
×
7577
      continue;
×
7578
    }
7579

7580
    // pOutput->type = pInput->type;
7581
    if (pInfo->count == 0) {
×
7582
      TAOS_MEMCPY(pInfo, pInputInfo, sizeof(SCorrRes));
×
7583
    } else if (pInfo->count > 0) {
×
7584
      pInfo->productVal += pInputInfo->productVal;
×
7585
      pInfo->quadLeft += pInputInfo->quadLeft;
×
7586
      pInfo->quadRight += pInputInfo->quadRight;
×
7587
      pInfo->sumLeft += pInputInfo->sumLeft;
×
7588
      pInfo->sumRight += pInputInfo->sumRight;
×
7589
      pInfo->count += pInputInfo->count;
×
7590
    }
7591
  }
7592

7593
  SET_VAL(GET_RES_INFO(pCtx), pInfo->count, 1);
×
7594
  return TSDB_CODE_SUCCESS;
×
7595
}
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